From ab8b62e661ee218a6a0f5f58155d37baf1f61d25 Mon Sep 17 00:00:00 2001 From: Kuingsmile Date: Tue, 2 Apr 2024 13:29:55 +0800 Subject: [PATCH] :sparkles: Feature(custom): add buildin web server ISSUES CLOSED: #180 --- public/i18n/en.yml | 3 + public/i18n/zh-CN.yml | 3 + public/i18n/zh-TW.yml | 3 + src/main/events/ipcList.ts | 7 ++ src/main/lifeCycle/index.ts | 2 + src/main/server/webServer/index.ts | 96 ++++++++++++++++++++++ src/renderer/pages/PicGoSetting.vue | 119 +++++++++++++++++++++++++++- src/universal/types/i18n.d.ts | 5 ++ src/universal/types/view.d.ts | 6 +- 9 files changed, 242 insertions(+), 2 deletions(-) diff --git a/public/i18n/en.yml b/public/i18n/en.yml index 0eaa130..543dccb 100644 --- a/public/i18n/en.yml +++ b/public/i18n/en.yml @@ -209,9 +209,12 @@ SETTINGS_ENABLE_SERVER: Enable Server SETTINGS_SET_SERVER_HOST: Set Server Host SETTINGS_SET_SERVER_PORT: Set Server Port SETTINGS_SET_SERVER_KEY: Set Auth Key +SETTINGS_SET_WEB_SERVER: Set Web Server +SETTINGS_TIPS_WEB_SERVER_NOTICE: If you don't know what is the web server's function, please read the document, or don't modify the configuration. SETTINGS_SET_ENABLE_WEB_SERVER: Enable Web Server SETTINGS_SET_WEB_SERVER_HOST: Set Web Server Host SETTINGS_SET_WEB_SERVER_PORT: Set Web Server Port +SETTINGS_SET_WEB_SERVER_PATH: Set Web Server Path SETTINGS_TIP_PLACEHOLDER_WEB_HOST: Default:127.0.0.1 SETTINGS_TIP_PLACEHOLDER_WEB_PORT: Default:37777 SETTINGS_TIP_PLACEHOLDER_HOST: Default:127.0.0.1 diff --git a/public/i18n/zh-CN.yml b/public/i18n/zh-CN.yml index f1d6306..38a3cde 100644 --- a/public/i18n/zh-CN.yml +++ b/public/i18n/zh-CN.yml @@ -211,9 +211,12 @@ SETTINGS_ENABLE_SERVER: 是否开启Server SETTINGS_SET_SERVER_HOST: 设置监听地址 SETTINGS_SET_SERVER_PORT: 设置监听端口 SETTINGS_SET_SERVER_KEY: 设置鉴权密钥 +SETTINGS_SET_WEB_SERVER: 设置Web服务 +SETTINGS_TIPS_WEB_SERVER_NOTICE: 如果你不知道Web服务的作用,请阅读文档,或者不用修改配置。 SETTINGS_SET_ENABLE_WEB_SERVER: 是否开启Web服务 SETTINGS_SET_WEB_SERVER_HOST: 设置Web服务监听地址 SETTINGS_SET_WEB_SERVER_PORT: 设置Web服务监听端口 +SETTINGS_SET_WEB_SERVER_PATH: 设置Web服务路径 SETTINGS_TIP_PLACEHOLDER_WEB_HOST: 推荐默认地址:127.0.0.1 SETTINGS_TIP_PLACEHOLDER_WEB_PORT: 推荐默认端口:37777 SETTINGS_TIP_PLACEHOLDER_HOST: 推荐默认地址:127.0.0.1 diff --git a/public/i18n/zh-TW.yml b/public/i18n/zh-TW.yml index e552e45..48d5e0d 100644 --- a/public/i18n/zh-TW.yml +++ b/public/i18n/zh-TW.yml @@ -209,9 +209,12 @@ SETTINGS_ENABLE_SERVER: 是否開啟Server SETTINGS_SET_SERVER_HOST: 設定監聽地址 SETTINGS_SET_SERVER_PORT: 設定監聽端口 SETTINGS_SET_SERVER_KEY: 設定鑒權密鑰 +SETTINGS_SET_WEB_SERVER: 設定Web服務 +SETTINGS_TIPS_WEB_SERVER_NOTICE: 如果你不知道Web服務的作用,請閱讀文檔,或者不用修改設定。 SETTINGS_SET_ENABLE_WEB_SERVER: 是否開啟Web服務 SETTINGS_SET_WEB_SERVER_HOST: 設定Web服務地 SETTINGS_SET_WEB_SERVER_PORT: 設定Web服務端口 +SETTINGS_SET_WEB_SERVER_PATH: 設定Web服務路徑 SETTINGS_TIP_PLACEHOLDER_WEB_HOST: 推薦預設地址:127.0.0.1 SETTINGS_TIP_PLACEHOLDER_WEB_PORT: 推薦預設端口:37777 SETTINGS_TIP_PLACEHOLDER_HOST: 推薦預設地址:127.0.0.1 diff --git a/src/main/events/ipcList.ts b/src/main/events/ipcList.ts index 10584ba..66f2c45 100644 --- a/src/main/events/ipcList.ts +++ b/src/main/events/ipcList.ts @@ -89,6 +89,7 @@ import SSHClient from '../utils/sshClient' import { ISftpPlistConfig } from 'piclist' import { removeFileFromS3InMain, removeFileFromDogeInMain, removeFileFromHuaweiInMain } from '~/main/utils/deleteFunc' +import webServer from '../server/webServer' const STORE_PATH = app.getPath('userData') @@ -360,6 +361,12 @@ export default { ipcMain.on('updateServer', () => { server.restart() }) + ipcMain.on('stopWebServer', () => { + webServer.stop() + }) + ipcMain.on('restartWebServer', () => { + webServer.restart() + }) ipcMain.on(OPEN_DEVTOOLS, (event: IpcMainEvent) => { event.sender.openDevTools() }) diff --git a/src/main/lifeCycle/index.ts b/src/main/lifeCycle/index.ts index b045098..48a2919 100644 --- a/src/main/lifeCycle/index.ts +++ b/src/main/lifeCycle/index.ts @@ -45,6 +45,7 @@ import path from 'path' import { CLIPBOARD_IMAGE_FOLDER } from '~/universal/utils/static' import fs from 'fs-extra' import { startFileServer } from '../fileServer' +import webServer from '../server/webServer' import axios from 'axios' const isDevelopment = process.env.NODE_ENV !== 'production' @@ -179,6 +180,7 @@ class LifeCycle { }) server.startup() startFileServer() + webServer.start() if (process.env.NODE_ENV !== 'development') { handleStartUpFiles(process.argv, process.cwd()) } diff --git a/src/main/server/webServer/index.ts b/src/main/server/webServer/index.ts index e69de29..19bd790 100644 --- a/src/main/server/webServer/index.ts +++ b/src/main/server/webServer/index.ts @@ -0,0 +1,96 @@ +import http from 'http' +import fs from 'fs-extra' +import path from 'path' +import picgo from '@core/picgo' +import logger from '../../apis/core/picgo/logger' + +const defaultPath = process.platform === 'win32' ? 'C:/Users/' : '/' + +function generateDirectoryListingHtml (files: any[], requestPath: any) { + let html = '

Directory Listing

' + return html +} + +class WebServer { + private server: http.Server + private config: IStringKeyMap + + constructor () { + this.config = this.getConfigWithDefaults() + this.server = this.getServer() + } + + getConfigWithDefaults (): IStringKeyMap { + const enableWebServer = picgo.getConfig('settings.enableWebServer') || false + const webServerHost = picgo.getConfig('settings.webServerHost') || '0.0.0.0' + const webServerPort = picgo.getConfig('settings.webServerPort') || 37777 + const webServerPath = picgo.getConfig('settings.webServerPath') || defaultPath + return { enableWebServer, webServerHost, webServerPort, webServerPath } + } + + getServer (): http.Server { + return http.createServer((req, res) => { + const requestPath = req.url?.split('?')[0] + const filePath = path.join(this.config.webServerPath, decodeURIComponent(requestPath as string)) + + fs.stat(filePath, (err, stats) => { + if (err) { + res.writeHead(404) + res.end('404 Not Found') + return + } + + if (stats.isDirectory()) { + fs.readdir(filePath, (err, files) => { + if (err) { + res.writeHead(500) + res.end('Error listing directory contents') + } else { + res.writeHead(200, { 'Content-Type': 'text/html' }) + res.end(generateDirectoryListingHtml(files, requestPath)) + } + }) + } else { + fs.readFile(filePath, (err, data) => { + if (err) { + res.writeHead(404) + res.end('404 Not Found') + } else { + res.end(data) + } + }) + } + }) + }) + } + + start () { + if (this.config.enableWebServer) { + this.server.listen(this.config.webServerPort, this.config.webServerHost, () => { + logger.info(`Web server is running, http://${this.config.webServerHost}:${this.config.webServerPort}, root path is ${this.config.webServerPath}`) + }).on('error', (err) => { + logger.error(err) + }) + } else { + logger.info('Web server is not enabled') + } + } + + stop () { + this.server.close() + logger.info('Web server is stopped') + } + + restart () { + this.stop() + this.config = this.getConfigWithDefaults() + this.server = this.getServer() + this.start() + } +} + +export default new WebServer() diff --git a/src/renderer/pages/PicGoSetting.vue b/src/renderer/pages/PicGoSetting.vue index 33ebdab..8acfa08 100644 --- a/src/renderer/pages/PicGoSetting.vue +++ b/src/renderer/pages/PicGoSetting.vue @@ -654,6 +654,18 @@ {{ $T('SETTINGS_CLICK_TO_SET') }} + + + {{ $T('SETTINGS_CLICK_TO_SET') }} + + @@ -732,6 +744,7 @@ :title="$T('SETTINGS_CUSTOM_LINK_FORMAT')" :modal-append-to-body="false" center + draggable append-to-body >
@@ -1025,6 +1041,7 @@ :modal-append-to-body="false" width="500px" center + draggable append-to-body >
@@ -1187,6 +1205,69 @@ + +
+ {{ $T('SETTINGS_TIPS_WEB_SERVER_NOTICE') }} +
+ + + + + + +
@@ -1300,6 +1382,7 @@ :title="$T('SETTINGS_UP_DOWN_DESC')" :modal-append-to-body="false" center + draggable append-to-body > ({ deleteLocalFile: false, serverKey: '', aesPassword: '', - manualPageOpen: 'browser' + manualPageOpen: 'browser', + enableWebServer: false, + webServerHost: '0.0.0.0', + webServerPort: 37777, + webServerPath: '' }) const languageList = i18nManager.languageList.map(item => ({ @@ -1888,6 +1975,7 @@ const logFileVisible = ref(false) const customLinkVisible = ref(false) const checkUpdateVisible = ref(false) const serverVisible = ref(false) +const webServerVisible = ref(false) const syncVisible = ref(false) const upDownConfigVisible = ref(false) const proxyVisible = ref(false) @@ -2039,6 +2127,10 @@ async function initData () { form.serverKey = settings.serverKey || '' form.aesPassword = settings.aesPassword || 'PicList-aesPassword' form.manualPageOpen = settings.manualPageOpen || 'window' + form.enableWebServer = settings.enableWebServer || false + form.webServerHost = settings.webServerHost || '0.0.0.0' + form.webServerPort = settings.webServerPort || 37777 + form.webServerPath = settings.webServerPath || '' currentLanguage.value = settings.language ?? 'zh-CN' currentStartMode.value = settings.startMode || 'quiet' customLink.value = settings.customLink || '![$fileName]($url)' @@ -2296,6 +2388,31 @@ function cancelCheckVersion () { checkUpdateVisible.value = false } +function handleEnableWebServerChange (val: ICheckBoxValueType) { + saveConfig('settings.enableWebServer', val) +} + +function handleWebServerHostChange (val: string) { + saveConfig('settings.webServerHost', val) +} + +function handleWebServerPortChange (val?: number, oldVal?: number) { + saveConfig('settings.webServerPort', Number(val) || 37777) +} + +function handleWebServerPathChange (val: string) { + saveConfig('settings.webServerPath', val) +} + +function confirmWebServerSetting () { + console.log('confirmWebServerSetting') + if (form.enableWebServer) { + sendToMain('restartWebServer') + } else { + sendToMain('stopWebServer') + } +} + function handleServerKeyChange (val: string) { saveConfig('settings.serverKey', val) } diff --git a/src/universal/types/i18n.d.ts b/src/universal/types/i18n.d.ts index 2a5d59b..08de9b1 100644 --- a/src/universal/types/i18n.d.ts +++ b/src/universal/types/i18n.d.ts @@ -204,9 +204,14 @@ interface ILocales { SETTINGS_SET_SERVER_HOST: string SETTINGS_SET_SERVER_PORT: string SETTINGS_SET_SERVER_KEY: string + SETTINGS_SET_WEB_SERVER: string + SETTINGS_TIPS_WEB_SERVER_NOTICE: string SETTINGS_SET_ENABLE_WEB_SERVER: string SETTINGS_SET_WEB_SERVER_HOST: string SETTINGS_SET_WEB_SERVER_PORT: string + SETTINGS_SET_WEB_SERVER_PATH: string + SETTINGS_TIP_PLACEHOLDER_WEB_HOST: string + SETTINGS_TIP_PLACEHOLDER_WEB_PORT: string SETTINGS_TIP_PLACEHOLDER_HOST: string SETTINGS_TIP_PLACEHOLDER_PORT: string SETTINGS_TIP_PLACEHOLDER_KEY: string diff --git a/src/universal/types/view.d.ts b/src/universal/types/view.d.ts index 0e0ec2d..a4d875d 100644 --- a/src/universal/types/view.d.ts +++ b/src/universal/types/view.d.ts @@ -32,7 +32,11 @@ interface ISettingForm { deleteLocalFile: boolean, serverKey: string, aesPassword: string, - manualPageOpen: string + manualPageOpen: string, + enableWebServer: boolean, + webServerHost: string, + webServerPort: number, + webServerPath: string, } interface IShortKeyMap {