2019-12-31 10:50:19 -05:00
|
|
|
import http from 'http'
|
|
|
|
import routers from './routerManager'
|
|
|
|
import {
|
2020-03-19 07:25:05 -04:00
|
|
|
handleResponse,
|
|
|
|
ensureHTTPLink
|
2019-12-31 10:50:19 -05:00
|
|
|
} from './utils'
|
2020-04-10 11:28:46 -04:00
|
|
|
import picgo from '@core/picgo'
|
|
|
|
import logger from '@core/picgo/logger'
|
2020-03-19 07:25:05 -04:00
|
|
|
import axios from 'axios'
|
2023-10-09 06:37:29 -04:00
|
|
|
import multer from 'multer'
|
|
|
|
import { app } from 'electron'
|
|
|
|
import path from 'path'
|
|
|
|
import fs from 'fs-extra'
|
|
|
|
|
|
|
|
const appPath = app.getPath('userData')
|
|
|
|
const serverTempDir = path.join(appPath, 'serverTemp')
|
|
|
|
|
|
|
|
fs.ensureDirSync(serverTempDir)
|
|
|
|
|
|
|
|
const multerStorage = multer.diskStorage({
|
|
|
|
destination: function (_req: any, _file: any, cb: (arg0: null, arg1: any) => void) {
|
|
|
|
fs.ensureDirSync(serverTempDir)
|
|
|
|
cb(null, serverTempDir)
|
|
|
|
},
|
|
|
|
filename: function (_req: any, file: { originalname: any }, cb: (arg0: null, arg1: any) => void) {
|
2023-12-27 21:46:38 -05:00
|
|
|
// eslint-disable-next-line no-control-regex
|
|
|
|
if (!/[^\u0000-\u00ff]/.test(file.originalname)) {
|
|
|
|
file.originalname = Buffer.from(file.originalname, 'latin1').toString(
|
|
|
|
'utf8'
|
|
|
|
)
|
|
|
|
}
|
2023-10-09 06:37:29 -04:00
|
|
|
cb(null, file.originalname)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
const uploadMulter = multer({
|
|
|
|
storage: multerStorage
|
|
|
|
})
|
2019-12-31 10:50:19 -05:00
|
|
|
|
|
|
|
class Server {
|
|
|
|
private httpServer: http.Server
|
2019-12-31 22:58:09 -05:00
|
|
|
private config: IServerConfig
|
2023-08-10 08:30:46 -04:00
|
|
|
|
2019-12-31 10:50:19 -05:00
|
|
|
constructor () {
|
2020-06-28 03:28:44 -04:00
|
|
|
let config = picgo.getConfig<IServerConfig>('settings.server')
|
2020-01-07 21:57:19 -05:00
|
|
|
const result = this.checkIfConfigIsValid(config)
|
|
|
|
if (result) {
|
|
|
|
this.config = config
|
2023-10-09 11:18:09 -04:00
|
|
|
if (this.config.host === '127.0.0.1') {
|
|
|
|
this.config.host = '0.0.0.0'
|
|
|
|
}
|
2020-01-07 21:57:19 -05:00
|
|
|
} else {
|
|
|
|
config = {
|
|
|
|
port: 36677,
|
2023-10-09 11:18:09 -04:00
|
|
|
host: '0.0.0.0',
|
2020-01-07 21:57:19 -05:00
|
|
|
enable: true
|
|
|
|
}
|
|
|
|
this.config = config
|
|
|
|
picgo.saveConfig({
|
|
|
|
'settings.server': config
|
|
|
|
})
|
2019-12-31 22:58:09 -05:00
|
|
|
}
|
2019-12-31 10:50:19 -05:00
|
|
|
this.httpServer = http.createServer(this.handleRequest)
|
|
|
|
}
|
2022-01-04 10:40:28 -05:00
|
|
|
|
2020-01-07 21:57:19 -05:00
|
|
|
private checkIfConfigIsValid (config: IObj | undefined) {
|
2023-08-10 08:30:46 -04:00
|
|
|
return config && config.port && config.host && (config.enable !== undefined)
|
2020-01-07 21:57:19 -05:00
|
|
|
}
|
2022-01-04 10:40:28 -05:00
|
|
|
|
2019-12-31 10:50:19 -05:00
|
|
|
private handleRequest = (request: http.IncomingMessage, response: http.ServerResponse) => {
|
2022-07-15 22:36:00 -04:00
|
|
|
if (request.method === 'OPTIONS') {
|
|
|
|
handleResponse({
|
|
|
|
response
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
2022-10-31 05:13:51 -04:00
|
|
|
|
2019-12-31 10:50:19 -05:00
|
|
|
if (request.method === 'POST') {
|
2023-09-06 11:40:50 -04:00
|
|
|
const [url, query] = request.url!.split('?')
|
|
|
|
if (!routers.getHandler(url!)) {
|
|
|
|
logger.warn(`[PicList Server] don't support [${url}] url`)
|
2019-12-31 10:50:19 -05:00
|
|
|
handleResponse({
|
|
|
|
response,
|
|
|
|
statusCode: 404,
|
|
|
|
body: {
|
|
|
|
success: false
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} else {
|
2023-10-09 06:37:29 -04:00
|
|
|
if (request.headers['content-type'] && request.headers['content-type'].startsWith('multipart/form-data')) {
|
|
|
|
// @ts-ignore
|
|
|
|
uploadMulter.any()(request, response, (err: any) => {
|
|
|
|
if (err) {
|
|
|
|
logger.info('[PicList Server]', err)
|
|
|
|
return handleResponse({
|
|
|
|
response,
|
|
|
|
body: {
|
|
|
|
success: false,
|
|
|
|
message: 'Error processing formData'
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
// @ts-ignore
|
|
|
|
const list = request.files.map(file => file.path)
|
2023-12-07 09:55:31 -05:00
|
|
|
logger.info('[PicList Server] get a formData request')
|
2023-10-09 06:37:29 -04:00
|
|
|
const handler = routers.getHandler(url)?.handler
|
|
|
|
if (handler) {
|
|
|
|
handler({
|
|
|
|
list,
|
|
|
|
response,
|
|
|
|
urlparams: query ? new URLSearchParams(query) : undefined
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
let body: string = ''
|
|
|
|
let postObj: IObj
|
|
|
|
request.on('data', chunk => {
|
|
|
|
body += chunk
|
|
|
|
})
|
|
|
|
request.on('end', () => {
|
|
|
|
try {
|
|
|
|
postObj = (body === '') ? {} : JSON.parse(body)
|
|
|
|
} catch (err: any) {
|
|
|
|
logger.error('[PicList Server]', err)
|
|
|
|
return handleResponse({
|
|
|
|
response,
|
|
|
|
body: {
|
|
|
|
success: false,
|
|
|
|
message: 'Not sending data in JSON format'
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
logger.info('[PicList Server] get the request', body)
|
|
|
|
const handler = routers.getHandler(url!)?.handler
|
|
|
|
handler!({
|
|
|
|
...postObj,
|
2019-12-31 10:50:19 -05:00
|
|
|
response,
|
2023-10-09 06:37:29 -04:00
|
|
|
urlparams: query ? new URLSearchParams(query) : undefined
|
2019-12-31 10:50:19 -05:00
|
|
|
})
|
|
|
|
})
|
2023-10-09 06:37:29 -04:00
|
|
|
}
|
2019-12-31 10:50:19 -05:00
|
|
|
}
|
|
|
|
} else {
|
2023-02-15 10:36:47 -05:00
|
|
|
logger.warn(`[PicList Server] don't support [${request.method}] method`)
|
2019-12-31 10:50:19 -05:00
|
|
|
response.statusCode = 404
|
|
|
|
response.end()
|
|
|
|
}
|
|
|
|
}
|
2022-01-04 10:40:28 -05:00
|
|
|
|
2020-03-19 07:25:05 -04:00
|
|
|
// port as string is a bug
|
|
|
|
private listen = (port: number | string) => {
|
2023-10-09 11:18:09 -04:00
|
|
|
logger.info(`[PicList Server] is listening at ${port} of ${this.config.host}`)
|
2020-03-19 07:25:05 -04:00
|
|
|
if (typeof port === 'string') {
|
|
|
|
port = parseInt(port, 10)
|
|
|
|
}
|
|
|
|
this.httpServer.listen(port, this.config.host).on('error', async (err: ErrnoException) => {
|
2019-12-31 10:50:19 -05:00
|
|
|
if (err.errno === 'EADDRINUSE') {
|
2020-03-19 07:25:05 -04:00
|
|
|
try {
|
|
|
|
// make sure the system has a PicGo Server instance
|
|
|
|
await axios.post(ensureHTTPLink(`${this.config.host}:${port}/heartbeat`))
|
|
|
|
this.shutdown(true)
|
|
|
|
} catch (e) {
|
2023-02-15 10:36:47 -05:00
|
|
|
logger.warn(`[PicList Server] ${port} is busy, trying with port ${(port as number) + 1}`)
|
2020-03-19 07:25:05 -04:00
|
|
|
// fix a bug: not write an increase number to config file
|
|
|
|
// to solve the auto number problem
|
|
|
|
this.listen((port as number) + 1)
|
|
|
|
}
|
2019-12-31 10:50:19 -05:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2022-01-04 10:40:28 -05:00
|
|
|
|
2019-12-31 10:50:19 -05:00
|
|
|
startup () {
|
2021-08-01 02:50:25 -04:00
|
|
|
console.log('startup', this.config.enable)
|
2019-12-31 22:58:09 -05:00
|
|
|
if (this.config.enable) {
|
|
|
|
this.listen(this.config.port)
|
|
|
|
}
|
2019-12-31 10:50:19 -05:00
|
|
|
}
|
2022-01-04 10:40:28 -05:00
|
|
|
|
2020-03-19 07:25:05 -04:00
|
|
|
shutdown (hasStarted?: boolean) {
|
2019-12-31 10:50:19 -05:00
|
|
|
this.httpServer.close()
|
2020-03-19 07:25:05 -04:00
|
|
|
if (!hasStarted) {
|
2023-02-15 10:36:47 -05:00
|
|
|
logger.info('[PicList Server] shutdown')
|
2020-03-19 07:25:05 -04:00
|
|
|
}
|
2019-12-31 22:58:09 -05:00
|
|
|
}
|
2022-01-04 10:40:28 -05:00
|
|
|
|
2019-12-31 22:58:09 -05:00
|
|
|
restart () {
|
|
|
|
this.config = picgo.getConfig('settings.server')
|
2023-10-09 11:18:09 -04:00
|
|
|
if (this.config.host === '127.0.0.1') {
|
|
|
|
this.config.host = '0.0.0.0'
|
|
|
|
}
|
2019-12-31 22:58:09 -05:00
|
|
|
this.shutdown()
|
|
|
|
this.startup()
|
2019-12-31 10:50:19 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default new Server()
|