diff --git a/.env b/.env
new file mode 100644
index 0000000..a439f2d
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+PORT=9005
diff --git a/package-lock.json b/package-lock.json
index dc31b1e..0cabdbe 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,8 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
+ "dayjs": "^1.11.13",
+ "dotenv": "^16.4.5",
"ws": "^8.18.0"
},
"bin": {
@@ -1885,6 +1887,11 @@
"node": ">= 10"
}
},
+ "node_modules/dayjs": {
+ "version": "1.11.13",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
+ "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg=="
+ },
"node_modules/debug": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
@@ -2088,12 +2095,14 @@
}
},
"node_modules/dotenv": {
- "version": "9.0.2",
- "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz",
- "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==",
- "dev": true,
+ "version": "16.4.5",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
+ "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
"engines": {
- "node": ">=10"
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
}
},
"node_modules/dotenv-expand": {
@@ -4109,6 +4118,15 @@
"node": ">=12.0.0"
}
},
+ "node_modules/read-config-file/node_modules/dotenv": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-9.0.2.tgz",
+ "integrity": "sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/read-pkg": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
diff --git a/package.json b/package.json
index 324dbc9..74b753c 100644
--- a/package.json
+++ b/package.json
@@ -1,10 +1,10 @@
{
"name": "sdserver",
"version": "1.0.0",
- "main": "dist/main.js",
+ "main": "dist/electron/main.js",
"scripts": {
"start": "electron .",
- "build": "tsc && copyfiles -u 1 src/index.html dist/",
+ "build": "tsc && copyfiles -u 1 src/electron/index.html dist/ && copyfiles -u 1 src/electron/index.css dist/",
"pack": "electron-packager . SDServer --platform=win32 --arch=x64 --out=dist/",
"buildexe": "npx electron-builder",
"watch": "nodemon"
@@ -21,6 +21,8 @@
}
},
"dependencies": {
+ "dayjs": "^1.11.13",
+ "dotenv": "^16.4.5",
"ws": "^8.18.0"
},
"devDependencies": {
@@ -48,4 +50,4 @@
"author": "",
"license": "ISC",
"description": ""
-}
\ No newline at end of file
+}
diff --git a/src/electron/index.css b/src/electron/index.css
new file mode 100644
index 0000000..10d9a0c
--- /dev/null
+++ b/src/electron/index.css
@@ -0,0 +1,38 @@
+/* index.css */
+body {
+ font-family: Arial, sans-serif;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ height: 100vh;
+ }
+
+ #log-container {
+ width: 70%;
+ background-color: black;
+ color: green;
+ padding: 10px;
+ overflow-y: scroll; /* 允许垂直滚动 */
+ white-space: pre-wrap;
+ font-family: 'Courier New', Courier, monospace;
+ box-sizing: border-box; /* 包括 padding 在内的计算方式 */
+ }
+
+ #control-panel {
+ width: 30%;
+ padding: 20px;
+ box-sizing: border-box;
+ background-color: #f0f0f0;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ }
+
+ button {
+ margin-top: 10px;
+ }
+
+ input {
+ margin-bottom: 10px;
+ }
+
\ No newline at end of file
diff --git a/src/electron/index.html b/src/electron/index.html
new file mode 100644
index 0000000..bb569a7
--- /dev/null
+++ b/src/electron/index.html
@@ -0,0 +1,29 @@
+
+
+
+
+ SD Server Control
+
+
+
+
+
+
+
+
+
+
Control Panel
+
+
+
+
+
+
Status: Waiting for actions...
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main.ts b/src/electron/main.ts
similarity index 62%
rename from src/main.ts
rename to src/electron/main.ts
index 5a98f33..d6e55d5 100644
--- a/src/main.ts
+++ b/src/electron/main.ts
@@ -1,10 +1,14 @@
// src/main.ts
+import dotenv from 'dotenv';
import { app, BrowserWindow, ipcMain } from 'electron';
import * as path from 'path';
import { WebSocketServer } from 'ws';
+// Load environment variables from .env file
+dotenv.config();
+
let server: WebSocketServer | null = null;
-let port = 8080; // 默认端口
+let port: number = process.env.PORT ? parseInt(process.env.PORT, 10) : 8080; // 默认端口为 8080
function createWindow() {
const win = new BrowserWindow({
@@ -20,13 +24,28 @@ function createWindow() {
});
win.loadFile(path.join(__dirname, 'index.html'));
- win.webContents.openDevTools();
+ // win.webContents.openDevTools();
return win;
}
let mainWindow: BrowserWindow | null = null;
+// Create a function to send log messages to the renderer
+function sendLogToRenderer(window: BrowserWindow, message: string) {
+ window.webContents.send('log-message', message);
+}
+
+// 重寫 console.log 方法以便將訊息發送到渲染進程
+const originalConsoleLog = console.log;
+console.log = (...args: any[]) => {
+ const message = args.join(' ');
+ originalConsoleLog(message); // 保留原始行為
+ if (BrowserWindow.getAllWindows().length > 0) {
+ sendLogToRenderer(BrowserWindow.getAllWindows()[0], message); // 發送訊息到渲染進程
+ }
+};
+
app.whenReady().then(() => {
mainWindow = createWindow();
@@ -53,13 +72,15 @@ ipcMain.on('start-websocket', (event, portNumber: number) => {
server = new WebSocketServer({ port: port });
- server.on('connection', (socket) => {
- console.log(`WebSocket server started on port ${port}`);
+ server.on('connection', (socket, request) => {
+ const ip = request.socket.remoteAddress.replace("::ffff:", "") || 'Unknown IP';
+ console.log(`Client connected from IP: ${ip}`);
socket.send('Welcome to the WebSocket server');
socket.on('message', (message: string) => {
- console.log(`Received message: ${message}`);
+ console.log(`[RPC] 收到client呼叫: ${message}`);
socket.send(`Server received your message: ${message}`);
+ console.log(`[RPC] 回傳client呼叫: ${message}`);
});
socket.on('close', () => {
@@ -67,7 +88,7 @@ ipcMain.on('start-websocket', (event, portNumber: number) => {
});
});
- event.reply('websocket-status', `WebSocket server started on port ${port} 88`);
+ event.reply('websocket-status', `WebSocket server started on port ${port}`);
});
// 关闭 WebSocket 服务器
diff --git a/src/preload.ts b/src/electron/preload.ts
similarity index 67%
rename from src/preload.ts
rename to src/electron/preload.ts
index 96255c8..44a1782 100644
--- a/src/preload.ts
+++ b/src/electron/preload.ts
@@ -5,5 +5,9 @@ contextBridge.exposeInMainWorld('electron', {
startWebSocket: (port: number) => ipcRenderer.send('start-websocket', port),
stopWebSocket: () => ipcRenderer.send('stop-websocket'),
openDevTools: () => ipcRenderer.send('open-devtools'),
- onWebSocketStatus: (callback: (message: string) => void) => ipcRenderer.on('websocket-status', (event, message) => callback(message))
+ onWebSocketStatus: (callback: (message: string) => void) => ipcRenderer.on('websocket-status', (event, message) => callback(message)),
+ onLogMessage: (callback: (message: string) => void) => ipcRenderer.on('log-message', (event, message) => callback(message)),
+ env: {
+ PORT: process.env.PORT || '8080' // 提供環境變數
+ }
});
diff --git a/src/electron/renderer.ts b/src/electron/renderer.ts
new file mode 100644
index 0000000..f954661
--- /dev/null
+++ b/src/electron/renderer.ts
@@ -0,0 +1,74 @@
+const maxLogs = 200; // 设置最大日志数量
+const logs: string[] = [];
+
+
+
+// 格式化时间戳的函数
+function formatDate(date: Date): string {
+ const year = date.getFullYear();
+ const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始
+ const day = String(date.getDate()).padStart(2, '0');
+ const hours = String(date.getHours()).padStart(2, '0');
+ const minutes = String(date.getMinutes()).padStart(2, '0');
+ const seconds = String(date.getSeconds()).padStart(2, '0');
+
+ // return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
+ return `${hours}:${minutes}:${seconds}`;
+}
+
+function updateLogDisplay() {
+ const logContainer = document.getElementById('log') as HTMLElement;
+ if (logContainer) {
+ logContainer.innerText = logs.join('\n');
+ logContainer.scrollTop = 0; // 保持滚动位置在顶部
+ }
+}
+
+function addLog(message: string) {
+ const timestamp = formatDate(new Date()); // 使用当前时间生成时间戳
+ const logMessage = `[${timestamp}] ${message}`; // 在日志消息前添加时间戳
+
+ logs.unshift(logMessage); // 在数组开头插入新消息
+
+ // 如果日志超过200条,删除最旧的一条(数组末尾的元素)
+ if (logs.length > maxLogs) {
+ logs.pop();
+ }
+
+ updateLogDisplay();
+}
+
+// 设置默认端口值
+const portInputElement = document.getElementById('port') as HTMLInputElement;
+if (portInputElement) {
+ const defaultPort = window.electron.env.PORT; // 从预加载脚本中获取默认端口
+ portInputElement.value = defaultPort;
+}
+
+document.getElementById('startBtn')?.addEventListener('click', () => {
+ const portElement = document.getElementById('port') as HTMLInputElement;
+ const port = parseInt(portElement.value, 10);
+ window.electron.startWebSocket(port);
+});
+
+document.getElementById('stopBtn')?.addEventListener('click', () => {
+ window.electron.stopWebSocket();
+});
+
+document.getElementById('devToolsBtn')?.addEventListener('click', () => {
+ window.electron.openDevTools();
+});
+
+window.electron.onWebSocketStatus((message: string) => {
+ console.log(`WebSocket status: ${message}`);
+ const statusElement = document.getElementById('status');
+ if (statusElement) {
+ statusElement.innerText = `Status: ${message}`;
+ }
+ addLog(message); // 將 WebSocket 狀態消息添加到日誌顯示區
+});
+
+// 监听主进程发送的日志消息
+window.electron.onLogMessage((message: string) => {
+ addLog(message); // 將日誌消息添加到顯示區
+});
\ No newline at end of file
diff --git a/src/global.d.ts b/src/global.d.ts
index bbfaef0..ea3c59e 100644
--- a/src/global.d.ts
+++ b/src/global.d.ts
@@ -5,5 +5,7 @@ interface Window {
stopWebSocket: () => void;
openDevTools: () => void;
onWebSocketStatus: (callback: (message: string) => void) => void;
+ onLogMessage: (callback: (message: string) => void) => void; // 添加這行以處理日誌消息
+ env: { PORT: string; };
};
}
diff --git a/src/index.html b/src/index.html
deleted file mode 100644
index 77d3674..0000000
--- a/src/index.html
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
- WebSocket Control
-
-
-
-
-
-
- SD Server Control
-
-
-
-
-
-
-
- Status: Waiting for actions...
-
-
-
-
\ No newline at end of file
diff --git a/src/server.ts b/src/pkg/server.ts
similarity index 100%
rename from src/server.ts
rename to src/pkg/server.ts
diff --git a/src/renderer.ts b/src/renderer.ts
deleted file mode 100644
index 961705a..0000000
--- a/src/renderer.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-document.getElementById('startBtn')?.addEventListener('click', () => {
- // console.log('Start WebSocket button clicked');
- const portElement = document.getElementById('port') as HTMLInputElement;
- const port = parseInt(portElement.value, 10);
- window.electron.startWebSocket(port);
-});
-
-document.getElementById('stopBtn')?.addEventListener('click', () => {
- // console.log('Stop WebSocket button clicked');
- window.electron.stopWebSocket();
-});
-
-document.getElementById('devToolsBtn')?.addEventListener('click', () => {
- // console.log('Open DevTools button clicked');
- window.electron.openDevTools();
-});
-
-window.electron.onWebSocketStatus((message: string) => {
- console.log(`WebSocket status: ${message}`);
- const statusElement = document.getElementById('status');
- if (statusElement) {
- statusElement.innerText = `Status: ${message}`;
- }
-});
-
-
-// document.getElementById('startBtn')?.addEventListener('click', () => {
-// // console.log('Start WebSocket button clicked');
-// const portElement = document.getElementById('port') as HTMLInputElement;
-// const port = parseInt(portElement.value, 10);
-// ipcRenderer.send('start-websocket', port);
-// });
-
-// document.getElementById('stopBtn')?.addEventListener('click', () => {
-// // console.log('Stop WebSocket button clicked');
-// ipcRenderer.send('stop-websocket');
-// });
-
-// document.getElementById('devToolsBtn')?.addEventListener('click', () => {
-// // console.log('Open DevTools button clicked');
-// ipcRenderer.send('open-devtools');
-// });
-
-// function onWebSocketStatus(callback: (message: string) => void) {
-// ipcRenderer.on('websocket-status', (event, message) => callback(message));
-// }
-
-// // 監聽 WebSocket 狀態
-// onWebSocketStatus((message) => {
-// console.log('WebSocket status:', message);
-// });
\ No newline at end of file