collabdocchat 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.gitignore ADDED
@@ -0,0 +1,139 @@
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ lerna-debug.log*
8
+ .pnpm-debug.log*
9
+
10
+ # Diagnostic reports (https://nodejs.org/api/report.html)
11
+ report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
12
+
13
+ # Runtime data
14
+ pids
15
+ *.pid
16
+ *.seed
17
+ *.pid.lock
18
+
19
+ # Directory for instrumented libs generated by jscoverage/JSCover
20
+ lib-cov
21
+
22
+ # Coverage directory used by tools like istanbul
23
+ coverage
24
+ *.lcov
25
+
26
+ # nyc test coverage
27
+ .nyc_output
28
+
29
+ # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
30
+ .grunt
31
+
32
+ # Bower dependency directory (https://bower.io/)
33
+ bower_components
34
+
35
+ # node-waf configuration
36
+ .lock-wscript
37
+
38
+ # Compiled binary addons (https://nodejs.org/api/addons.html)
39
+ build/Release
40
+
41
+ # Dependency directories
42
+ node_modules/
43
+ jspm_packages/
44
+
45
+ # Snowpack dependency directory (https://snowpack.dev/)
46
+ web_modules/
47
+
48
+ # TypeScript cache
49
+ *.tsbuildinfo
50
+
51
+ # Optional npm cache directory
52
+ .npm
53
+
54
+ # Optional eslint cache
55
+ .eslintcache
56
+
57
+ # Optional stylelint cache
58
+ .stylelintcache
59
+
60
+ # Microbundle cache
61
+ .rpt2_cache/
62
+ .rts2_cache_cjs/
63
+ .rts2_cache_es/
64
+ .rts2_cache_umd/
65
+
66
+ # Optional REPL history
67
+ .node_repl_history
68
+
69
+ # Output of 'npm pack'
70
+ *.tgz
71
+
72
+ # Yarn Integrity file
73
+ .yarn-integrity
74
+
75
+ # dotenv environment variable files
76
+ .env
77
+ .env.development.local
78
+ .env.test.local
79
+ .env.production.local
80
+ .env.local
81
+
82
+ # parcel-bundler cache (https://parceljs.org/)
83
+ .cache
84
+ .parcel-cache
85
+
86
+ # Next.js build output
87
+ .next
88
+ out
89
+
90
+ # Nuxt.js build / generate output
91
+ .nuxt
92
+ dist
93
+
94
+ # Gatsby files
95
+ .cache/
96
+ # Comment in the public line in if your project uses Gatsby and not Next.js
97
+ # https://nextjs.org/blog/next-9-1#public-directory-support
98
+ # public
99
+
100
+ # vuepress build output
101
+ .vuepress/dist
102
+
103
+ # vuepress v2.x temp and cache directory
104
+ .temp
105
+ .cache
106
+
107
+ # vitepress build output
108
+ **/.vitepress/dist
109
+
110
+ # vitepress cache directory
111
+ **/.vitepress/cache
112
+
113
+ # Docusaurus cache and generated files
114
+ .docusaurus
115
+
116
+ # Serverless directories
117
+ .serverless/
118
+
119
+ # FuseBox cache
120
+ .fusebox/
121
+
122
+ # DynamoDB Local files
123
+ .dynamodb/
124
+
125
+ # TernJS port file
126
+ .tern-port
127
+
128
+ # Stores VSCode versions used for testing VSCode extensions
129
+ .vscode-test
130
+
131
+ # yarn v2
132
+ .yarn/cache
133
+ .yarn/unplugged
134
+ .yarn/build-state.yml
135
+ .yarn/install-state.gz
136
+ .pnp.*
137
+
138
+ # CollabDocChat 进程 PID 文件
139
+ .collabdocchat.pid
package/README.md CHANGED
@@ -186,6 +186,20 @@ npm run client # 前端开发服务器
186
186
 
187
187
  或手动访问:`http://localhost:5173`
188
188
 
189
+ 7. **停止服务**
190
+
191
+ ```bash
192
+ # 停止所有 CollabDocChat 服务
193
+ npm run stop
194
+
195
+ # 或手动停止(Windows)
196
+ taskkill /F /IM node.exe
197
+
198
+ # 或手动停止(Linux/Mac)
199
+ pkill -f "node.*server/index.js"
200
+ pkill -f vite
201
+ ```
202
+
189
203
  ---
190
204
 
191
205
  ## 📁 项目结构
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "collabdocchat",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "开源的实时协作文档聊天平台 - 集成任务管理、多人文档编辑、智能点名功能",
5
5
  "main": "./server/index.js",
6
6
  "type": "module",
@@ -12,7 +12,8 @@
12
12
  "LICENSE",
13
13
  "package.json",
14
14
  "vite.config.js",
15
- "index.html"
15
+ "index.html",
16
+ ".gitignore"
16
17
  ],
17
18
  "keywords": [
18
19
  "collaboration",
@@ -2,7 +2,7 @@ import { spawn } from 'child_process';
2
2
  import { platform } from 'os';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { dirname, join } from 'path';
5
- import http from 'http';
5
+ import { writeFileSync, existsSync } from 'fs';
6
6
 
7
7
  const __filename = fileURLToPath(import.meta.url);
8
8
  const __dirname = dirname(__filename);
@@ -11,6 +11,25 @@ const rootDir = join(__dirname, '..');
11
11
  const PORT = process.env.PORT || 3000;
12
12
  const CLIENT_PORT = 5173;
13
13
  const CLIENT_URL = `http://localhost:${CLIENT_PORT}`;
14
+ const pidFile = join(rootDir, '.collabdocchat.pid');
15
+ const isWindows = platform() === 'win32';
16
+
17
+ // 保存 PID 到文件
18
+ function savePid(pid) {
19
+ try {
20
+ let pids = [];
21
+ if (existsSync(pidFile)) {
22
+ const content = readFileSync(pidFile, 'utf-8');
23
+ pids = content.trim().split('\n').filter(Boolean);
24
+ }
25
+ if (!pids.includes(pid.toString())) {
26
+ pids.push(pid.toString());
27
+ writeFileSync(pidFile, pids.join('\n') + '\n');
28
+ }
29
+ } catch (error) {
30
+ // 忽略错误
31
+ }
32
+ }
14
33
 
15
34
  // 打开浏览器的函数
16
35
  function openBrowser(url) {
@@ -94,6 +113,11 @@ function startServer() {
94
113
  windowsHide: true
95
114
  });
96
115
 
116
+ // 保存服务器进程 PID
117
+ if (server.pid) {
118
+ savePid(server.pid);
119
+ }
120
+
97
121
  server.unref();
98
122
  return server;
99
123
  }
@@ -101,7 +125,6 @@ function startServer() {
101
125
  // 启动客户端
102
126
  function startClient() {
103
127
  console.log('🎨 正在启动客户端...');
104
- const isWindows = platform() === 'win32';
105
128
  const client = spawn(isWindows ? 'npm.cmd' : 'npm', ['run', 'client'], {
106
129
  cwd: rootDir,
107
130
  stdio: 'inherit',
@@ -109,6 +132,11 @@ function startClient() {
109
132
  windowsHide: true
110
133
  });
111
134
 
135
+ // 保存客户端进程 PID(注意:npm 会启动子进程,这里保存的是 npm 进程的 PID)
136
+ if (client.pid) {
137
+ savePid(client.pid);
138
+ }
139
+
112
140
  client.unref();
113
141
  return client;
114
142
  }
@@ -0,0 +1,155 @@
1
+ import { exec } from 'child_process';
2
+ import { platform } from 'os';
3
+ import { fileURLToPath } from 'url';
4
+ import { dirname, join } from 'path';
5
+ import { existsSync, unlinkSync, readFileSync } from 'fs';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = dirname(__filename);
9
+ const rootDir = join(__dirname, '..');
10
+ const pidFile = join(rootDir, '.collabdocchat.pid');
11
+
12
+ const isWindows = platform() === 'win32';
13
+
14
+ console.log('🛑 正在停止 CollabDocChat 服务...\n');
15
+
16
+ // 读取 PID 文件
17
+ function readPidFile() {
18
+ if (existsSync(pidFile)) {
19
+ try {
20
+ const content = readFileSync(pidFile, 'utf-8');
21
+ return content.trim().split('\n').filter(Boolean);
22
+ } catch (error) {
23
+ return [];
24
+ }
25
+ }
26
+ return [];
27
+ }
28
+
29
+ // 停止进程(Windows)
30
+ function stopProcessWindows(pid) {
31
+ return new Promise((resolve) => {
32
+ exec(`taskkill /F /PID ${pid}`, (error) => {
33
+ if (error) {
34
+ // 进程可能已经不存在
35
+ resolve(false);
36
+ } else {
37
+ console.log(`✅ 已停止进程 ${pid}`);
38
+ resolve(true);
39
+ }
40
+ });
41
+ });
42
+ }
43
+
44
+ // 停止进程(Linux/Mac)
45
+ function stopProcessUnix(pid) {
46
+ return new Promise((resolve) => {
47
+ exec(`kill -9 ${pid}`, (error) => {
48
+ if (error) {
49
+ resolve(false);
50
+ } else {
51
+ console.log(`✅ 已停止进程 ${pid}`);
52
+ resolve(true);
53
+ }
54
+ });
55
+ });
56
+ }
57
+
58
+ // 通过端口停止进程
59
+ function stopByPort(port) {
60
+ return new Promise((resolve) => {
61
+ if (isWindows) {
62
+ exec(`netstat -ano | findstr :${port}`, (error, stdout) => {
63
+ if (stdout) {
64
+ const lines = stdout.split('\n');
65
+ const pids = new Set();
66
+ lines.forEach(line => {
67
+ const match = line.match(/\s+(\d+)\s*$/);
68
+ if (match) {
69
+ pids.add(match[1]);
70
+ }
71
+ });
72
+
73
+ if (pids.size > 0) {
74
+ Promise.all(Array.from(pids).map(pid => stopProcessWindows(pid)))
75
+ .then(() => resolve(true));
76
+ } else {
77
+ resolve(false);
78
+ }
79
+ } else {
80
+ resolve(false);
81
+ }
82
+ });
83
+ } else {
84
+ exec(`lsof -ti:${port}`, (error, stdout) => {
85
+ if (stdout) {
86
+ const pids = stdout.trim().split('\n').filter(Boolean);
87
+ if (pids.length > 0) {
88
+ Promise.all(pids.map(pid => stopProcessUnix(pid)))
89
+ .then(() => resolve(true));
90
+ } else {
91
+ resolve(false);
92
+ }
93
+ } else {
94
+ resolve(false);
95
+ }
96
+ });
97
+ }
98
+ });
99
+ }
100
+
101
+ // 主函数
102
+ async function main() {
103
+ let stopped = false;
104
+
105
+ // 方法1: 通过 PID 文件停止
106
+ const pids = readPidFile();
107
+ if (pids.length > 0) {
108
+ console.log(`📋 找到 ${pids.length} 个进程记录`);
109
+ for (const pid of pids) {
110
+ if (isWindows) {
111
+ await stopProcessWindows(pid);
112
+ } else {
113
+ await stopProcessUnix(pid);
114
+ }
115
+ stopped = true;
116
+ }
117
+ }
118
+
119
+ // 方法2: 通过端口停止(备用方法)
120
+ console.log('\n🔍 检查端口占用...');
121
+ const port3000 = await stopByPort(3000);
122
+ const port5173 = await stopByPort(5173);
123
+
124
+ if (port3000 || port5173) {
125
+ stopped = true;
126
+ }
127
+
128
+ // 删除 PID 文件
129
+ if (existsSync(pidFile)) {
130
+ try {
131
+ unlinkSync(pidFile);
132
+ console.log('✅ 已清理进程记录文件');
133
+ } catch (error) {
134
+ // 忽略错误
135
+ }
136
+ }
137
+
138
+ if (stopped || port3000 || port5173) {
139
+ console.log('\n✅ CollabDocChat 服务已停止');
140
+ } else {
141
+ console.log('\n⚠️ 未找到运行中的 CollabDocChat 服务');
142
+ console.log('💡 提示:如果服务仍在运行,可以手动停止:');
143
+ if (isWindows) {
144
+ console.log(' taskkill /F /IM node.exe');
145
+ } else {
146
+ console.log(' pkill -f "node.*server/index.js"');
147
+ console.log(' pkill -f vite');
148
+ }
149
+ }
150
+ }
151
+
152
+ main().catch(error => {
153
+ console.error('❌ 停止服务时出错:', error.message);
154
+ process.exit(1);
155
+ });