[add] first
This commit is contained in:
		
							
								
								
									
										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 目录下的所有文件
 | 
			
		||||
}
 | 
			
		||||
  
 | 
			
		||||
		Reference in New Issue
	
	Block a user