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 +139 -0
- package/README.md +14 -0
- package/package.json +3 -2
- package/scripts/postinstall.js +30 -2
- package/scripts/stop-app.js +155 -0
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.
|
|
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",
|
package/scripts/postinstall.js
CHANGED
|
@@ -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
|
|
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
|
+
});
|