Feature(server): add http server for uploading images by a http request

port 37766
This commit is contained in:
Molunerfinn
2019-12-31 23:50:19 +08:00
parent 3fd95725cf
commit c56d4efa79
13 changed files with 558 additions and 54 deletions

View File

@@ -36,6 +36,13 @@ import {
} from '~/main/migrate/shortKeyUpdateHelper'
import shortKeyHandler from '~/main/utils/shortKeyHandler'
import logger from '~/main/utils/logger'
import {
UPLOAD_WITH_FILES,
UPLOAD_WITH_FILES_RESPONSE,
UPLOAD_WITH_CLIPBOARD_FILES,
UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE
} from '~/main/utils/busApi/constants'
import server from '~/main/server/index'
const isDevelopment = process.env.NODE_ENV !== 'production'
protocol.registerSchemesAsPrivileged([{ scheme: 'picgo', privileges: { secure: true, standard: true } }])
@@ -246,8 +253,8 @@ const createWindow = () => {
return window
}
const createMiniWidow = () => {
if (miniWindow) {
const createMiniWindow = () => {
if (miniWindow || process.platform === 'darwin') {
return false
}
let obj: IBrowserWindowOptions = {
@@ -322,7 +329,7 @@ const createSettingWindow = () => {
}
})
createMenu()
createMiniWidow()
createMiniWindow()
return settingWindow
}
@@ -368,9 +375,9 @@ const showWindow = (bounds: IBounds) => {
window!.focus()
}
const uploadClipboardFiles = async () => {
const uploadClipboardFiles = async (): Promise<string> => {
let win
if (miniWindow!.isVisible()) {
if (miniWindow && miniWindow!.isVisible()) {
win = miniWindow
} else {
win = settingWindow || window || createSettingWindow()
@@ -392,19 +399,24 @@ const uploadClipboardFiles = async () => {
if (settingWindow) {
settingWindow.webContents.send('updateGallery')
}
return img[0].imgUrl as string
} else {
const notification = new Notification({
title: '上传不成功',
body: '你剪贴板最新的一条记录不是图片哦'
})
notification.show()
return ''
}
} else {
return ''
}
}
const uploadChoosedFiles = async (webContents: WebContents, files: IFileWithPath[]) => {
const uploadChoosedFiles = async (webContents: WebContents, files: IFileWithPath[]): Promise<string[]> => {
const input = files.map(item => item.path)
const imgs = await uploader.setWebContents(webContents).upload(input)
const result = []
if (imgs !== false) {
const pasteStyle = db.get('settings.pasteStyle') || 'markdown'
let pasteText = ''
@@ -419,12 +431,16 @@ const uploadChoosedFiles = async (webContents: WebContents, files: IFileWithPath
notification.show()
}, i * 100)
db.insert('uploaded', imgs[i])
result.push(imgs[i].imgUrl!)
}
clipboard.writeText(pasteText)
window!.webContents.send('uploadFiles', imgs)
if (settingWindow) {
settingWindow.webContents.send('updateGallery')
}
return result
} else {
return []
}
}
@@ -522,7 +538,7 @@ ipcMain.on('openSettingWindow', () => {
ipcMain.on('openMiniWindow', () => {
if (!miniWindow) {
createMiniWidow()
createMiniWindow()
}
miniWindow!.show()
miniWindow!.focus()
@@ -611,7 +627,7 @@ app.on('ready', async () => {
updateShortKeyFromVersion212(db, db.get('settings.shortKey'))
shortKeyHandler.init()
})
server.startup()
if (process.env.NODE_ENV !== 'development') {
let files = getUploadFiles()
if (files === null) {
@@ -654,6 +670,7 @@ app.on('activate', () => {
app.on('will-quit', () => {
globalShortcut.unregisterAll()
bus.removeAllListeners()
server.shutdown()
})
app.setLoginItemSettings({
@@ -664,7 +681,9 @@ function initEventCenter () {
const eventList: any = {
'picgo:upload': uploadClipboardFiles,
'createSettingWindow': shortKeyRequestSettingWindow,
hideMiniWindow
hideMiniWindow,
[UPLOAD_WITH_CLIPBOARD_FILES]: busCallUploadClipboardFiles,
[UPLOAD_WITH_FILES]: busCallUploadFiles
}
for (let i in eventList) {
bus.on(i, eventList[i])
@@ -682,17 +701,35 @@ function hideMiniWindow () {
}
}
async function busCallUploadClipboardFiles () {
const imgUrl = await uploadClipboardFiles()
bus.emit(UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE, imgUrl)
}
async function busCallUploadFiles (pathList: IFileWithPath[]) {
let win
if (miniWindow && miniWindow.isVisible()) {
win = miniWindow
} else {
win = settingWindow || window || createSettingWindow()
}
const urls = await uploadChoosedFiles(win.webContents, pathList)
bus.emit(UPLOAD_WITH_FILES_RESPONSE, urls)
}
// Exit cleanly on request from parent process in development mode.
if (isDevelopment) {
if (process.platform === 'win32') {
process.on('message', data => {
if (data === 'graceful-exit') {
app.quit()
server.shutdown()
}
})
} else {
process.on('SIGTERM', () => {
app.quit()
server.shutdown()
})
}
}

72
src/main/server/index.ts Normal file
View File

@@ -0,0 +1,72 @@
import http from 'http'
import routers from './routerManager'
import {
handleResponse
} from './utils'
class Server {
private httpServer: http.Server
private port: number = 36677
constructor () {
this.httpServer = http.createServer(this.handleRequest)
}
private handleRequest = (request: http.IncomingMessage, response: http.ServerResponse) => {
if (request.method === 'POST') {
if (!routers.getHandler(request.url!)) {
handleResponse({
response,
statusCode: 404,
header: {},
body: {
success: false
}
})
} else {
let body: string = ''
let postObj: IObj
request.on('data', chunk => {
body += chunk
})
request.on('end', () => {
try {
postObj = JSON.parse(body)
} catch (err) {
return handleResponse({
response,
body: {
success: false,
message: 'Not sending data in JSON format'
}
})
}
const handler = routers.getHandler(request.url!)
handler!({
...postObj,
response
})
})
}
} else {
response.statusCode = 404
response.end()
}
}
private listen = (port: number) => {
console.log(`server listen at ${port}`)
this.httpServer.listen(port).on('error', (err: ErrnoException) => {
if (err.errno === 'EADDRINUSE') {
console.log(`----- Port ${port} is busy, trying with port ${port + 1} -----`)
this.port += 1
this.listen(this.port)
}
})
}
startup () {
this.listen(this.port)
}
shutdown () {
this.httpServer.close()
}
}
export default new Server()

20
src/main/server/router.ts Normal file
View File

@@ -0,0 +1,20 @@
class Router {
private router = new Map<string, routeHandler>()
get (url: string, callback: routeHandler): void {
this.router.set(url, callback)
}
post (url: string, callback: routeHandler): void {
this.router.set(url, callback)
}
getHandler (url: string) {
if (this.router.has(url)) {
return this.router.get(url)
} else {
return null
}
}
}
export default new Router()

View File

@@ -0,0 +1,69 @@
import router from './router'
import {
uploadWithClipboardFiles,
uploadWithFiles
} from '~/main/utils/busApi/index'
import {
handleResponse
} from './utils'
import logger from '../utils/logger'
router.get('/upload', async ({
response,
list = []
} : {
response: IHttpResponse,
list?: string[]
}): Promise<void> => {
try {
if (list.length === 0) {
// upload with clipboard
const res = await uploadWithClipboardFiles()
if (res.success) {
handleResponse({
response,
body: {
success: true,
result: [res.result]
}
})
} else {
handleResponse({
response
})
}
} else {
// upload with files
const pathList = list.map(item => {
return {
path: item
}
})
const res = await uploadWithFiles(pathList)
if (res.success) {
handleResponse({
response,
body: {
success: true,
result: res.result
}
})
} else {
handleResponse({
response
})
}
}
} catch (err) {
logger.error(err)
handleResponse({
response,
body: {
success: false,
message: err
}
})
}
})
export default router

19
src/main/server/utils.ts Normal file
View File

@@ -0,0 +1,19 @@
export const handleResponse = ({
response,
statusCode = 200,
header = {
'Content-Type': 'application/json'
},
body = {
success: false
}
} : {
response: IHttpResponse,
statusCode?: number,
header?: IObj,
body?: any
}) => {
response.writeHead(statusCode, header)
response.write(JSON.stringify(body))
response.end()
}

View File

@@ -0,0 +1,6 @@
export const GET_SETTING_WINDOW = 'GET_SETTING_WINDOW'
export const GET_MINI_WINDOW = 'GET_SETTING_WINDOW'
export const UPLOAD_WITH_FILES = 'UPLOAD_WITH_FILES'
export const UPLOAD_WITH_FILES_RESPONSE = 'UPLOAD_WITH_FILES_RESPONSE'
export const UPLOAD_WITH_CLIPBOARD_FILES = 'UPLOAD_WITH_CLIPBOARD_FILES'
export const UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE = 'UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE'

View File

@@ -0,0 +1,49 @@
import bus from '../eventBus'
import {
UPLOAD_WITH_FILES,
UPLOAD_WITH_FILES_RESPONSE,
UPLOAD_WITH_CLIPBOARD_FILES,
UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE
} from './constants'
export const uploadWithClipboardFiles = (): Promise<{
success: boolean,
result?: string[]
}> => {
return new Promise((resolve, reject) => {
bus.emit(UPLOAD_WITH_CLIPBOARD_FILES)
bus.once(UPLOAD_WITH_CLIPBOARD_FILES_RESPONSE, (result: string) => {
if (result) {
return resolve({
success: true,
result: [result]
})
} else {
return resolve({
success: false
})
}
})
})
}
export const uploadWithFiles = (pathList: IFileWithPath[]): Promise<{
success: boolean,
result?: string[]
}> => {
return new Promise((resolve, reject) => {
bus.emit(UPLOAD_WITH_FILES, pathList)
bus.once(UPLOAD_WITH_FILES_RESPONSE, (result: string[]) => {
if (result.length) {
return resolve({
success: true,
result
})
} else {
return resolve({
success: false
})
}
})
})
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@@ -29,7 +29,7 @@ import path from 'path'
mixins: [mixin]
})
export default class extends Vue {
logo = path.join(process.env.BASE_URL as string, 'squareLogo.png')
logo = require('../assets/squareLogo.png')
dragover = false
progress = 0
showProgress = false

View File

@@ -7,6 +7,23 @@ interface IObjT<T> {
[propName: string]: T
}
interface ErrnoException extends Error {
errno?: number | string;
code?: string;
path?: string;
syscall?: string;
stack?: string;
}
type routeHandler = (ctx: IServerCTX) => Promise<void>
type IHttpResponse = import('http').ServerResponse
interface IServerCTX {
response: IHttpResponse
[propName: string]: any
}
// Image && PicBed
interface ImgInfo {
buffer?: Buffer