(serverTimeMs: number)
| 179 | error?: any; |
| 180 | hint?: string; |
| 181 | }> { |
| 182 | const platform = process.platform; |
| 183 | const target = new Date(serverTimeMs); |
| 184 | try { |
| 185 | if (platform === "linux") { |
| 186 | const epochSec = Math.floor(serverTimeMs / 1000).toString(); |
| 187 | const args = ["-u", "-s", `@${epochSec}`]; |
| 188 | const { stdout, stderr } = await execFileAsync("date", args, { timeout: 5000 }); |
| 189 | return { ok: true, command: `date ${args.join(" ")}`, stdout, stderr }; |
| 190 | } else if (platform === "darwin") { |
| 191 | // BSD date: [[[[mm]dd]HH]MM][[cc]yy][.ss] |
| 192 | const yyyy = target.getUTCFullYear(); |
| 193 | const cc = Math.floor(yyyy / 100); |
| 194 | const yy = yyyy % 100; |
| 195 | const mm = target.getUTCMonth() + 1; |
| 196 | const dd = target.getUTCDate(); |
| 197 | const HH = target.getUTCHours(); |
| 198 | const MM = target.getUTCMinutes(); |
| 199 | const ss = target.getUTCSeconds(); |
| 200 | const pad = (n: number, w = 2) => n.toString().padStart(w, "0"); |
| 201 | const ts = `${pad(mm)}${pad(dd)}${pad(HH)}${pad(MM)}${cc}${pad(yy)}.${pad(ss)}`; |
| 202 | const args = ["-u", ts]; |
| 203 | const { stdout, stderr } = await execFileAsync("date", args, { timeout: 5000 }); |
| 204 | return { ok: true, command: `date ${args.join(" ")}`, stdout, stderr }; |
| 205 | } else if (platform === "win32") { |
| 206 | // Not supported here due to permission and locale complexities. |
| 207 | return { |
| 208 | ok: false, |
| 209 | hint: |
| 210 | "Windows 上暂不支持自动设置,请以管理员权限手动同步时间或启用 Windows 时间服务。", |
| 211 | }; |
| 212 | } |
| 213 | return { ok: false, hint: `暂不支持的平台:${platform}` }; |
| 214 | } catch (error: any) { |
| 215 | const msg = String(error?.message || error); |
| 216 | const needRoot = /not permitted|Operation not permitted|must be root|permission/i.test( |
| 217 | msg |
| 218 | ); |
| 219 | return { |
| 220 | ok: false, |
| 221 | error, |
| 222 | hint: needRoot |
| 223 | ? "需要管理员权限(sudo/root)。请以提升权限运行或手动执行上述命令。" |
| 224 | : "设置失败。请检查系统权限与命令可用性。", |
| 225 | }; |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | class NtpPlugin extends Plugin { |
| 230 | description: string = `\nNTP 对时\n\n${help_text}`; |
| 231 | cmdHandlers: Record< |
| 232 | string, |
| 233 | (msg: Api.Message, trigger?: Api.Message) => Promise<void> |
| 234 | > = { |
| 235 | ntp: async (msg: Api.Message) => { |
| 236 | const text = msg.message || ""; |
| 237 | const args = text.trim().split(/\s+/g).slice(1); // remove command |
no test coverage detected