[add] first
This commit is contained in:
commit
0271674764
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/dist
|
||||||
|
/node_modules
|
||||||
|
/release
|
20
.vscode/launch.json
vendored
Normal file
20
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Debug Main Process",
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
|
||||||
|
"windows": {
|
||||||
|
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
|
||||||
|
},
|
||||||
|
"args": ["."],
|
||||||
|
"outputCapture": "std",
|
||||||
|
"sourceMaps": true,
|
||||||
|
"restart": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
20
.vscode/tasks.json
vendored
Normal file
20
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "npm: build",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "npm",
|
||||||
|
"args": ["run", "build"],
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "npm: start",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "npm",
|
||||||
|
"args": ["start"],
|
||||||
|
"problemMatcher": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
10
nodemon.json
Normal file
10
nodemon.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"watch": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"ext": "ts",
|
||||||
|
"exec": "npm run build",
|
||||||
|
"ignore": [
|
||||||
|
"dist"
|
||||||
|
]
|
||||||
|
}
|
5233
package-lock.json
generated
Normal file
5233
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
51
package.json
Normal file
51
package.json
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"name": "sdserver",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "dist/main.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "electron .",
|
||||||
|
"build": "tsc && copyfiles -u 1 src/index.html dist/",
|
||||||
|
"pack": "electron-packager . SDServer --platform=win32 --arch=x64 --out=dist/",
|
||||||
|
"buildexe": "npx electron-builder",
|
||||||
|
"watch": "nodemon"
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"appId": "SDServer",
|
||||||
|
"files": [
|
||||||
|
"dist/**/*",
|
||||||
|
"node_modules/**/*",
|
||||||
|
"package.json"
|
||||||
|
],
|
||||||
|
"directories": {
|
||||||
|
"output": "release"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ws": "^8.18.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/electron": "^1.6.10",
|
||||||
|
"@types/node": "^22.5.0",
|
||||||
|
"@types/ws": "^8.5.12",
|
||||||
|
"copyfiles": "^2.4.1",
|
||||||
|
"electron": "^32.0.1",
|
||||||
|
"electron-builder": "^24.7.0",
|
||||||
|
"electron-packager": "^17.1.2",
|
||||||
|
"nodemon": "^3.1.4",
|
||||||
|
"ts-node": "^10.9.2",
|
||||||
|
"typescript": "^5.5.4"
|
||||||
|
},
|
||||||
|
"bin": "dist/server.js",
|
||||||
|
"pkg": {
|
||||||
|
"assets": [
|
||||||
|
"public/**/*"
|
||||||
|
],
|
||||||
|
"outputPath": "executables",
|
||||||
|
"targets": [
|
||||||
|
"node18-win-x64"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"description": ""
|
||||||
|
}
|
9
src/global.d.ts
vendored
Normal file
9
src/global.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// src/global.d.ts
|
||||||
|
interface Window {
|
||||||
|
electron: {
|
||||||
|
startWebSocket: (port: number) => void;
|
||||||
|
stopWebSocket: () => void;
|
||||||
|
openDevTools: () => void;
|
||||||
|
onWebSocketStatus: (callback: (message: string) => void) => void;
|
||||||
|
};
|
||||||
|
}
|
33
src/index.html
Normal file
33
src/index.html
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-TW">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>WebSocket Control</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>SD Server Control</h1>
|
||||||
|
|
||||||
|
<label for="port">Port:</label>
|
||||||
|
<input type="number" id="port" value="8080">
|
||||||
|
<button id="startBtn">Start WebSocket Server</button>
|
||||||
|
<button id="stopBtn">Stop WebSocket Server</button>
|
||||||
|
<button id="devToolsBtn">Open DevTools</button>
|
||||||
|
|
||||||
|
<p id="status">Status: Waiting for actions...</p>
|
||||||
|
<script src="renderer.js"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
96
src/main.ts
Normal file
96
src/main.ts
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
// src/main.ts
|
||||||
|
import { app, BrowserWindow, ipcMain } from 'electron';
|
||||||
|
import * as path from 'path';
|
||||||
|
import { WebSocketServer } from 'ws';
|
||||||
|
|
||||||
|
let server: WebSocketServer | null = null;
|
||||||
|
let port = 8080; // 默认端口
|
||||||
|
|
||||||
|
function createWindow() {
|
||||||
|
const win = new BrowserWindow({
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
webPreferences: {
|
||||||
|
preload: path.join(__dirname, 'preload.js'),
|
||||||
|
contextIsolation: true,
|
||||||
|
nodeIntegration: false,
|
||||||
|
// contextIsolation: false, // 使渲染進程能夠使用 Node.js
|
||||||
|
// nodeIntegration: true, // 使渲染進程可以使用 Node.js 模組
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
win.loadFile(path.join(__dirname, 'index.html'));
|
||||||
|
win.webContents.openDevTools();
|
||||||
|
|
||||||
|
return win;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mainWindow: BrowserWindow | null = null;
|
||||||
|
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
mainWindow = createWindow();
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
createWindow();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 启动 WebSocket 服务器
|
||||||
|
ipcMain.on('start-websocket', (event, portNumber: number) => {
|
||||||
|
if (server) {
|
||||||
|
server.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
port = portNumber || 8080;
|
||||||
|
|
||||||
|
server = new WebSocketServer({ port: port });
|
||||||
|
|
||||||
|
server.on('connection', (socket) => {
|
||||||
|
console.log(`WebSocket server started on port ${port}`);
|
||||||
|
socket.send('Welcome to the WebSocket server');
|
||||||
|
|
||||||
|
socket.on('message', (message: string) => {
|
||||||
|
console.log(`Received message: ${message}`);
|
||||||
|
socket.send(`Server received your message: ${message}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('close', () => {
|
||||||
|
console.log('Client disconnected');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
event.reply('websocket-status', `WebSocket server started on port ${port} 88`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 关闭 WebSocket 服务器
|
||||||
|
ipcMain.on('stop-websocket', (event) => {
|
||||||
|
if (server) {
|
||||||
|
server.clients.forEach(client => {
|
||||||
|
if (client.readyState === 1) {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
server.close((err) => {
|
||||||
|
if (err) {
|
||||||
|
event.reply('websocket-status', 'Failed to stop WebSocket server');
|
||||||
|
} else {
|
||||||
|
event.reply('websocket-status', 'WebSocket server stopped');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
event.reply('websocket-status', 'No WebSocket server is running');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 打开开发者工具
|
||||||
|
ipcMain.on('open-devtools', () => {
|
||||||
|
mainWindow.webContents.openDevTools();
|
||||||
|
});
|
9
src/preload.ts
Normal file
9
src/preload.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// src/preload.ts
|
||||||
|
import { contextBridge, ipcRenderer } from 'electron';
|
||||||
|
|
||||||
|
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))
|
||||||
|
});
|
51
src/renderer.ts
Normal file
51
src/renderer.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
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);
|
||||||
|
// });
|
25
src/server.ts
Normal file
25
src/server.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import WebSocket, { WebSocketServer } from 'ws';
|
||||||
|
|
||||||
|
const server = new WebSocketServer({ port: 8080 });
|
||||||
|
|
||||||
|
server.on('connection', (socket: WebSocket) => {
|
||||||
|
console.log('客户端已连接');
|
||||||
|
|
||||||
|
// 发送消息到客户端
|
||||||
|
socket.send('欢迎连接到WebSocket服务器');
|
||||||
|
|
||||||
|
// 接收来自客户端的消息
|
||||||
|
socket.on('message', (message: string) => {
|
||||||
|
console.log(`收到客户端消息: ${message}`);
|
||||||
|
|
||||||
|
// 回应消息
|
||||||
|
socket.send(`服务器收到你的消息: ${message}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 处理客户端断开连接
|
||||||
|
socket.on('close', () => {
|
||||||
|
console.log('客户端已断开连接');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('WebSocket服务器运行在 ws://localhost:8080');
|
20
tsconfig.json
Normal file
20
tsconfig.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2020", // 设置 ECMAScript 版本
|
||||||
|
"module": "CommonJS", // 使用 CommonJS 模块系统
|
||||||
|
"sourceMap": true,
|
||||||
|
"strict": false, // 启用严格模式
|
||||||
|
"esModuleInterop": true, // 启用 ES 模块的兼容性
|
||||||
|
"skipLibCheck": true, // 跳过库的类型检查
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"./src/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src",
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"] // 包含 src 目录下的所有文件
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user