fdb2 1.0.10 → 1.0.12

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/bin/fdb2.js CHANGED
@@ -4,10 +4,43 @@ const { exec, spawn, execSync, spawnSync } = require('child_process');
4
4
  const path = require('path');
5
5
  const fs = require('fs');
6
6
  const net = require('net');
7
+ const os = require('os');
7
8
 
8
9
  // 项目根目录
9
10
  const projectRoot = path.resolve(__dirname, '..');
10
11
 
12
+ // 获取 PID 文件路径
13
+ function getPidFilePath() {
14
+ const dataDir = process.env.DB_TOOL_DATA_DIR || path.join(os.homedir(), '.fdb2');
15
+ if (!fs.existsSync(dataDir)) {
16
+ fs.mkdirSync(dataDir, { recursive: true });
17
+ }
18
+ return path.join(dataDir, 'fdb2.server.pid');
19
+ }
20
+
21
+ // 读取 PID
22
+ function readPid() {
23
+ const pidFilePath = getPidFilePath();
24
+ if (fs.existsSync(pidFilePath)) {
25
+ return parseInt(fs.readFileSync(pidFilePath, 'utf8'));
26
+ }
27
+ return null;
28
+ }
29
+
30
+ // 写入 PID
31
+ function writePid(pid) {
32
+ const pidFilePath = getPidFilePath();
33
+ fs.writeFileSync(pidFilePath, pid.toString());
34
+ }
35
+
36
+ // 删除 PID
37
+ function deletePid() {
38
+ const pidFilePath = getPidFilePath();
39
+ if (fs.existsSync(pidFilePath)) {
40
+ fs.unlinkSync(pidFilePath);
41
+ }
42
+ }
43
+
11
44
  // 解析命令行参数
12
45
  const args = process.argv.slice(2);
13
46
  const command = args[0] || 'help';
@@ -74,17 +107,16 @@ async function startProject() {
74
107
  console.log('Starting FDB2 project...');
75
108
 
76
109
  // 检查 PID 文件是否存在,如果存在则说明服务器已经在运行
77
- const pidFilePath = path.join(projectRoot, 'fdb2.server.pid');
78
- if (fs.existsSync(pidFilePath)) {
110
+ const pid = readPid();
111
+ if (pid) {
79
112
  try {
80
- const pid = parseInt(fs.readFileSync(pidFilePath, 'utf8'));
81
113
  process.kill(pid, 0);
82
114
  console.log('Server is already running with PID:', pid);
83
115
  return;
84
116
  } catch (error) {
85
117
  if (error.code === 'ESRCH') {
86
118
  console.log('Cleaning up stale PID file...');
87
- fs.unlinkSync(pidFilePath);
119
+ deletePid();
88
120
  }
89
121
  }
90
122
  }
@@ -120,24 +152,40 @@ async function startProject() {
120
152
  // 日志文件路径
121
153
  const logFilePath = path.join(projectRoot, 'server.log');
122
154
 
123
- // 创建日志文件的写入流
124
- const out = fs.openSync(logFilePath, 'a');
125
- const err = fs.openSync(logFilePath, 'a');
155
+ // 安全地创建日志文件写入流,忽略错误
156
+ function createLogFileStream(logFilePath) {
157
+ try {
158
+ const fd = fs.openSync(logFilePath, 'a');
159
+ console.log(`Log file created: ${logFilePath}`);
160
+ return fd;
161
+ } catch (error) {
162
+ console.warn(`Failed to create log file ${logFilePath}: ${error.message}`);
163
+ console.warn('Logs will only be written to console.');
164
+ return null;
165
+ }
166
+ }
167
+
168
+ // 创建日志文件流
169
+ const logFileFd = createLogFileStream(logFilePath);
126
170
 
127
171
  // 使用 node 命令启动服务器(异步,后台运行)
128
172
  const child = spawn(cmd, args, {
129
173
  cwd: projectRoot,
130
174
  detached: true,
131
- stdio: ['ignore', out, err]
175
+ stdio: ['ignore', logFileFd || 'inherit', logFileFd || 'inherit']
132
176
  });
133
177
 
134
178
  // 解除父子进程关联,让子进程在后台独立运行
135
179
  child.unref();
136
180
 
137
181
  // 保存 PID 到文件
138
- fs.writeFileSync(pidFilePath, child.pid.toString());
182
+ writePid(child.pid);
139
183
 
140
- console.log('Logs are written to:', logFilePath);
184
+ if (logFileFd) {
185
+ console.log('Logs are written to:', logFilePath);
186
+ } else {
187
+ console.log('Logs are written to console only');
188
+ }
141
189
  console.log('Server started successfully with PID:', child.pid);
142
190
  console.log('Server is running in the background');
143
191
  console.log(`Server is running at http://localhost:${port}`);
@@ -147,32 +195,84 @@ async function startProject() {
147
195
  function stopProject() {
148
196
  console.log('Stopping FDB2 project...');
149
197
 
150
- // 读取 PID 文件
151
- const pidFilePath = path.join(projectRoot, 'fdb2.server.pid');
198
+ // 读取 PID
199
+ const pid = readPid();
152
200
 
153
- if (!fs.existsSync(pidFilePath)) {
201
+ if (!pid) {
154
202
  console.log('No server process found (PID file not exists)');
155
203
  return;
156
204
  }
157
205
 
158
206
  try {
159
- // 读取 PID
160
- const pid = parseInt(fs.readFileSync(pidFilePath, 'utf8'));
161
207
  console.log(`Stopping server process with PID: ${pid}`);
162
208
 
163
- // 发送终止信号
164
- process.kill(pid);
209
+ // 发送终止信号 - 尝试不同的信号
210
+ try {
211
+ // 首先尝试 SIGTERM (15) - 正常终止
212
+ process.kill(pid, 'SIGTERM');
213
+ console.log('SIGTERM signal sent');
214
+
215
+ // 等待一段时间(2秒)
216
+ const startTime = Date.now();
217
+ const maxWaitTime = 2000; // 2秒
218
+ let processExists = true;
219
+
220
+ while (Date.now() - startTime < maxWaitTime) {
221
+ try {
222
+ // 检查进程是否还存在
223
+ process.kill(pid, 0);
224
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 100); // 等待100ms
225
+ } catch (err) {
226
+ if (err.code === 'ESRCH') {
227
+ processExists = false;
228
+ break;
229
+ }
230
+ }
231
+ }
232
+
233
+ // 如果进程仍然存在,尝试 SIGKILL (9) - 强制终止
234
+ if (processExists) {
235
+ console.log('Process still exists, sending SIGKILL...');
236
+ try {
237
+ process.kill(pid, 'SIGKILL');
238
+ console.log('SIGKILL signal sent');
239
+
240
+ // 再等待500ms
241
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 500);
242
+ } catch (killErr) {
243
+ // SIGKILL 失败可能表示我们没有权限
244
+ if (killErr.code === 'EPERM') {
245
+ console.error('Insufficient permissions to kill process');
246
+ console.error('Try running with sudo or manually kill the process:');
247
+ console.error(` sudo kill -9 ${pid}`);
248
+ }
249
+ throw killErr;
250
+ }
251
+ }
252
+ } catch (killError) {
253
+ // 如果 kill 操作失败,检查错误类型
254
+ if (killError.code === 'EPERM') {
255
+ // 权限不足
256
+ console.error('Insufficient permissions to kill process');
257
+ console.error('Try running with sudo or manually kill the process:');
258
+ console.error(` sudo kill -9 ${pid}`);
259
+ throw killError;
260
+ } else if (killError.code === 'ESRCH') {
261
+ // 进程不存在
262
+ console.log('Process not found');
263
+ } else {
264
+ throw killError;
265
+ }
266
+ }
165
267
 
166
268
  // 删除 PID 文件
167
- fs.unlinkSync(pidFilePath);
269
+ deletePid();
168
270
  console.log('Server stopped successfully');
169
271
  } catch (error) {
170
272
  // 如果进程不存在(ESRCH 错误),也删除 PID 文件
171
273
  if (error.code === 'ESRCH') {
172
274
  console.log('Server process not found, cleaning up PID file');
173
- if (fs.existsSync(pidFilePath)) {
174
- fs.unlinkSync(pidFilePath);
175
- }
275
+ deletePid();
176
276
  } else {
177
277
  console.error('Failed to stop server:', error.message);
178
278
  }
@@ -196,8 +296,7 @@ function restartProject() {
196
296
  console.log('Waiting for server process to stop...');
197
297
  for (let i = 0; i < 10; i++) {
198
298
  // 检查 PID 文件是否存在
199
- const pidFilePath = path.join(projectRoot, 'fdb2.server.pid');
200
- if (!fs.existsSync(pidFilePath)) {
299
+ if (!readPid()) {
201
300
  break;
202
301
  }
203
302
  // 等待 100 毫秒