collabdocchat 1.2.7 → 1.2.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "collabdocchat",
3
- "version": "1.2.7",
3
+ "version": "1.2.8",
4
4
  "description": "开源的实时协作文档聊天平台 - 集成任务管理、多人文档编辑、智能点名功能",
5
5
  "main": "./server/index.js",
6
6
  "type": "module",
@@ -1,186 +1,57 @@
1
- import { spawn } from 'child_process';
2
- import { platform } from 'os';
3
1
  import { fileURLToPath } from 'url';
4
2
  import { dirname, join } from 'path';
5
- import { writeFileSync, existsSync, readFileSync } from 'fs';
3
+ import { writeFileSync, existsSync } from 'fs';
6
4
 
7
5
  const __filename = fileURLToPath(import.meta.url);
8
6
  const __dirname = dirname(__filename);
9
7
  const rootDir = join(__dirname, '..');
10
8
 
11
- const PORT = process.env.PORT || 3000;
12
- const CLIENT_PORT = 5173;
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
- }
33
-
34
- // 打开浏览器的函数
35
- function openBrowser(url) {
36
- const platformName = platform();
37
- let command;
38
- let args;
39
-
40
- switch (platformName) {
41
- case 'win32':
42
- command = 'cmd';
43
- args = ['/c', 'start', url];
44
- break;
45
- case 'darwin':
46
- command = 'open';
47
- args = [url];
48
- break;
49
- default:
50
- command = 'xdg-open';
51
- args = [url];
52
- }
53
-
54
- const browser = spawn(command, args, { stdio: 'ignore', detached: true });
55
- browser.unref();
56
- }
57
-
58
- // 检查服务器是否就绪
59
- function waitForServer(url, maxAttempts = 30, delay = 1000) {
60
- return new Promise((resolve, reject) => {
61
- let attempts = 0;
62
- const urlObj = new URL(url);
63
-
64
- const check = () => {
65
- attempts++;
66
-
67
- const req = http.get({
68
- hostname: urlObj.hostname,
69
- port: urlObj.port,
70
- path: urlObj.pathname,
71
- timeout: 1000
72
- }, (res) => {
73
- if (res.statusCode === 200) {
74
- resolve();
75
- return;
76
- }
77
- if (attempts < maxAttempts) {
78
- setTimeout(check, delay);
79
- } else {
80
- reject(new Error('服务器启动超时'));
81
- }
82
- });
83
-
84
- req.on('error', () => {
85
- if (attempts < maxAttempts) {
86
- setTimeout(check, delay);
87
- } else {
88
- reject(new Error('服务器启动超时'));
89
- }
90
- });
91
-
92
- req.on('timeout', () => {
93
- req.destroy();
94
- if (attempts < maxAttempts) {
95
- setTimeout(check, delay);
96
- } else {
97
- reject(new Error('服务器启动超时'));
98
- }
99
- });
100
- };
101
-
102
- check();
103
- });
104
- }
105
-
106
- // 启动服务器
107
- function startServer() {
108
- console.log('\n🚀 正在启动 CollabDocChat 服务器...');
109
- const server = spawn('node', ['server/index.js'], {
110
- cwd: rootDir,
111
- stdio: 'inherit',
112
- detached: true,
113
- windowsHide: true
114
- });
115
-
116
- // 保存服务器进程 PID
117
- if (server.pid) {
118
- savePid(server.pid);
119
- }
120
-
121
- server.unref();
122
- return server;
123
- }
124
-
125
- // 启动客户端
126
- function startClient() {
127
- console.log('🎨 正在启动客户端...');
128
- const client = spawn(isWindows ? 'npm.cmd' : 'npm', ['run', 'client'], {
129
- cwd: rootDir,
130
- stdio: 'inherit',
131
- detached: true,
132
- windowsHide: true
133
- });
134
-
135
- // 保存客户端进程 PID(注意:npm 会启动子进程,这里保存的是 npm 进程的 PID)
136
- if (client.pid) {
137
- savePid(client.pid);
138
- }
139
-
140
- client.unref();
141
- return client;
142
- }
143
-
144
- // 主函数 - 完全异步,不阻塞
145
- function main() {
146
- console.log('\n📦 CollabDocChat 安装完成!');
147
- console.log('🚀 正在后台启动应用...\n');
148
-
149
- // 立即启动服务器(不等待)
150
- try {
151
- const server = startServer();
152
- } catch (error) {
153
- // 静默处理
154
- }
9
+ // 创建默认 .env 文件
10
+ function createEnvFile() {
11
+ const envPath = join(rootDir, '.env');
155
12
 
156
- // 立即启动客户端(不等待)
157
- try {
158
- const client = startClient();
159
- } catch (error) {
160
- // 静默处理
161
- }
162
-
163
- // 延迟打开浏览器,给服务器启动时间
164
- setTimeout(() => {
13
+ if (!existsSync(envPath)) {
14
+ const envContent = `# 服务器配置
15
+ PORT=3000
16
+ NODE_ENV=development
17
+
18
+ # MongoDB 配置
19
+ MONGODB_URI=mongodb://localhost:27017/collabdocchat
20
+
21
+ # JWT 配置
22
+ JWT_SECRET=your-secret-key-change-this-in-production-${Date.now()}
23
+ JWT_EXPIRES_IN=7d
24
+
25
+ # 管理员账号(首次启动时创建)
26
+ ADMIN_USERNAME=admin
27
+ ADMIN_PASSWORD=admin123
28
+ ADMIN_EMAIL=admin@example.com
29
+ `;
30
+
165
31
  try {
166
- console.log(`\n🌐 正在打开浏览器: ${CLIENT_URL}`);
167
- openBrowser(CLIENT_URL);
168
- console.log('\n✅ 应用正在启动中,浏览器已打开。');
169
- console.log(' 如果页面未加载,请稍等片刻后刷新页面。');
170
- console.log('\n💡 提示:服务器和客户端正在后台运行');
171
- console.log(' 要停止服务,运行: cd node_modules/collabdocchat && npm run stop');
32
+ writeFileSync(envPath, envContent);
33
+ console.log('✅ 已创建默认配置文件 .env');
172
34
  } catch (error) {
173
- // 静默处理
35
+ console.log('⚠️ 无法创建 .env 文件,请手动创建');
174
36
  }
175
- }, 8000);
37
+ }
176
38
  }
177
39
 
178
- // 立即执行
179
- main();
180
-
181
- // 延迟退出,给输出时间显示
182
- // 但不会阻塞太久
183
- setTimeout(() => {
184
- process.exit(0);
185
- }, 2000);
186
-
40
+ console.log('\n🎉 CollabDocChat 安装成功!\n');
41
+ console.log('📦 开源的实时协作文档聊天平台\n');
42
+
43
+ // 创建配置文件
44
+ createEnvFile();
45
+
46
+ console.log('\n📖 快速开始:\n');
47
+ console.log(' 1. 确保 MongoDB 已安装并运行');
48
+ console.log(' 2. 安装开发依赖: npm install');
49
+ console.log(' 3. 启动应用: npm start');
50
+ console.log('\n💡 更多信息:');
51
+ console.log(' • 查看 README.md 了解详细说明');
52
+ console.log(' • 查看 INSTALLATION.md 了解安装指南');
53
+ console.log(' • 默认管理员账号: admin / admin123');
54
+ console.log('\n🔗 文档链接:');
55
+ console.log(' • GitHub: https://github.com/shijinghao/collabdocchat');
56
+ console.log(' • npm: https://www.npmjs.com/package/collabdocchat');
57
+ console.log('\n');
@@ -1,8 +1,9 @@
1
- import { spawn } from 'child_process';
1
+ import { spawn, exec } from 'child_process';
2
2
  import { platform } from 'os';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { dirname, join } from 'path';
5
5
  import http from 'http';
6
+ import { existsSync } from 'fs';
6
7
 
7
8
  const __filename = fileURLToPath(import.meta.url);
8
9
  const __dirname = dirname(__filename);
@@ -11,29 +12,92 @@ const rootDir = join(__dirname, '..');
11
12
  const PORT = process.env.PORT || 3000;
12
13
  const CLIENT_PORT = 5173;
13
14
  const CLIENT_URL = `http://localhost:${CLIENT_PORT}`;
15
+ const isWindows = platform() === 'win32';
16
+
17
+ // 检查 devDependencies 是否已安装
18
+ function checkDevDependencies() {
19
+ const vitePath = join(rootDir, 'node_modules', 'vite');
20
+ return existsSync(vitePath);
21
+ }
22
+
23
+ // 安装 devDependencies
24
+ function installDevDependencies() {
25
+ return new Promise((resolve, reject) => {
26
+ console.log('📦 正在安装开发依赖...\n');
27
+
28
+ const npmCmd = isWindows ? 'npm.cmd' : 'npm';
29
+ const install = spawn(npmCmd, ['install'], {
30
+ cwd: rootDir,
31
+ stdio: 'inherit',
32
+ shell: true
33
+ });
34
+
35
+ install.on('close', (code) => {
36
+ if (code === 0) {
37
+ console.log('\n✅ 依赖安装完成\n');
38
+ resolve();
39
+ } else {
40
+ reject(new Error(`依赖安装失败,退出码: ${code}`));
41
+ }
42
+ });
43
+
44
+ install.on('error', (error) => {
45
+ reject(error);
46
+ });
47
+ });
48
+ }
49
+
50
+ // 检查端口是否被占用
51
+ function checkPort(port) {
52
+ return new Promise((resolve) => {
53
+ const server = http.createServer();
54
+
55
+ server.once('error', (err) => {
56
+ if (err.code === 'EADDRINUSE') {
57
+ resolve(false); // 端口被占用
58
+ } else {
59
+ resolve(true);
60
+ }
61
+ });
62
+
63
+ server.once('listening', () => {
64
+ server.close();
65
+ resolve(true); // 端口可用
66
+ });
67
+
68
+ server.listen(port);
69
+ });
70
+ }
14
71
 
15
72
  // 打开浏览器的函数
16
73
  function openBrowser(url) {
17
- const platformName = platform();
18
- let command;
19
- let args;
20
-
21
- switch (platformName) {
22
- case 'win32':
23
- command = 'cmd';
24
- args = ['/c', 'start', url];
25
- break;
26
- case 'darwin':
27
- command = 'open';
28
- args = [url];
29
- break;
30
- default:
31
- command = 'xdg-open';
32
- args = [url];
33
- }
74
+ try {
75
+ const platformName = platform();
76
+ let command, args;
77
+
78
+ switch (platformName) {
79
+ case 'win32':
80
+ command = 'cmd';
81
+ args = ['/c', 'start', '""', url];
82
+ break;
83
+ case 'darwin':
84
+ command = 'open';
85
+ args = [url];
86
+ break;
87
+ default:
88
+ command = 'xdg-open';
89
+ args = [url];
90
+ }
34
91
 
35
- const browser = spawn(command, args, { stdio: 'ignore', detached: true });
36
- browser.unref();
92
+ const browser = spawn(command, args, {
93
+ stdio: 'ignore',
94
+ detached: true,
95
+ shell: true
96
+ });
97
+ browser.unref();
98
+ } catch (error) {
99
+ console.log(`⚠️ 无法自动打开浏览器,请手动访问: ${url}`);
100
+ }
37
101
  }
38
102
 
39
103
  // 检查服务器是否就绪
@@ -48,23 +112,13 @@ function waitForServer(url, maxAttempts = 30, delay = 1000) {
48
112
  const req = http.get({
49
113
  hostname: urlObj.hostname,
50
114
  port: urlObj.port,
51
- path: urlObj.pathname,
115
+ path: '/',
52
116
  timeout: 1000
53
117
  }, (res) => {
54
- if (res.statusCode === 200) {
55
- resolve();
56
- return;
57
- }
58
- // 继续等待
59
- if (attempts < maxAttempts) {
60
- setTimeout(check, delay);
61
- } else {
62
- reject(new Error('服务器启动超时'));
63
- }
118
+ resolve();
64
119
  });
65
120
 
66
121
  req.on('error', () => {
67
- // 服务器未就绪,继续等待
68
122
  if (attempts < maxAttempts) {
69
123
  setTimeout(check, delay);
70
124
  } else {
@@ -98,10 +152,11 @@ function startServer() {
98
152
  return server;
99
153
  }
100
154
 
101
- // 启动客户端(如果使用 Vite)
155
+ // 启动客户端
102
156
  function startClient() {
103
- console.log('🎨 正在启动客户端...');
104
- const client = spawn('npm', ['run', 'client'], {
157
+ console.log('🎨 正在启动客户端...\n');
158
+ const npmCmd = isWindows ? 'npm.cmd' : 'npm';
159
+ const client = spawn(npmCmd, ['run', 'client'], {
105
160
  cwd: rootDir,
106
161
  stdio: 'inherit',
107
162
  shell: true
@@ -114,12 +169,36 @@ function startClient() {
114
169
  async function main() {
115
170
  console.log('📦 CollabDocChat 正在启动...\n');
116
171
 
172
+ // 检查端口
173
+ const portAvailable = await checkPort(PORT);
174
+ if (!portAvailable) {
175
+ console.error(`❌ 错误:端口 ${PORT} 已被占用`);
176
+ console.error('\n💡 解决方案:');
177
+ console.error(' 1. 停止占用端口的进程: npm run stop');
178
+ console.error(' 2. 或修改 .env 文件中的 PORT 配置');
179
+ console.error(' 3. Windows: netstat -ano | findstr :3000');
180
+ console.error(' 然后: taskkill /PID <进程ID> /F\n');
181
+ process.exit(1);
182
+ }
183
+
184
+ // 检查并安装 devDependencies
185
+ if (!checkDevDependencies()) {
186
+ console.log('⚠️ 检测到缺少开发依赖\n');
187
+ try {
188
+ await installDevDependencies();
189
+ } catch (error) {
190
+ console.error('❌ 依赖安装失败:', error.message);
191
+ console.error('\n💡 请手动运行: npm install\n');
192
+ process.exit(1);
193
+ }
194
+ }
195
+
117
196
  // 启动服务器
118
197
  const server = startServer();
119
198
 
120
199
  // 等待服务器就绪
121
200
  try {
122
- await waitForServer(`http://localhost:${PORT}/health`, 30, 1000);
201
+ await waitForServer(`http://localhost:${PORT}`, 30, 1000);
123
202
  console.log(`✅ 服务器已就绪: http://localhost:${PORT}\n`);
124
203
  } catch (error) {
125
204
  console.error('❌ 服务器启动失败:', error.message);
@@ -135,12 +214,17 @@ async function main() {
135
214
  await waitForServer(CLIENT_URL, 20, 500);
136
215
  console.log(`\n🌐 正在打开浏览器: ${CLIENT_URL}`);
137
216
  openBrowser(CLIENT_URL);
217
+ console.log('\n✅ 应用启动成功!');
218
+ console.log('\n💡 提示:');
219
+ console.log(' • 服务器: http://localhost:3000');
220
+ console.log(' • 客户端: http://localhost:5173');
221
+ console.log(' • 默认账号: admin / admin123');
222
+ console.log('\n⚠️ 按 Ctrl+C 停止服务\n');
138
223
  } catch (error) {
139
224
  console.log(`\n⚠️ 客户端可能还在启动中,请手动访问: ${CLIENT_URL}`);
140
- // 即使检查失败也尝试打开浏览器
141
225
  openBrowser(CLIENT_URL);
142
226
  }
143
- }, 2000);
227
+ }, 3000);
144
228
 
145
229
  // 处理退出信号
146
230
  process.on('SIGINT', () => {
@@ -161,4 +245,3 @@ main().catch(error => {
161
245
  console.error('❌ 启动失败:', error);
162
246
  process.exit(1);
163
247
  });
164
-