xray-manager 1.0.0

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.
Files changed (91) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +798 -0
  3. package/dist/cli.d.ts +11 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +113 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/config.d.ts +49 -0
  8. package/dist/commands/config.d.ts.map +1 -0
  9. package/dist/commands/config.js +295 -0
  10. package/dist/commands/config.js.map +1 -0
  11. package/dist/commands/interactive.d.ts +83 -0
  12. package/dist/commands/interactive.d.ts.map +1 -0
  13. package/dist/commands/interactive.js +362 -0
  14. package/dist/commands/interactive.js.map +1 -0
  15. package/dist/commands/logs.d.ts +43 -0
  16. package/dist/commands/logs.d.ts.map +1 -0
  17. package/dist/commands/logs.js +257 -0
  18. package/dist/commands/logs.js.map +1 -0
  19. package/dist/commands/service.d.ts +43 -0
  20. package/dist/commands/service.d.ts.map +1 -0
  21. package/dist/commands/service.js +177 -0
  22. package/dist/commands/service.js.map +1 -0
  23. package/dist/commands/user.d.ts +43 -0
  24. package/dist/commands/user.d.ts.map +1 -0
  25. package/dist/commands/user.js +212 -0
  26. package/dist/commands/user.js.map +1 -0
  27. package/dist/constants/exit-codes.d.ts +49 -0
  28. package/dist/constants/exit-codes.d.ts.map +1 -0
  29. package/dist/constants/exit-codes.js +100 -0
  30. package/dist/constants/exit-codes.js.map +1 -0
  31. package/dist/constants/paths.d.ts +57 -0
  32. package/dist/constants/paths.d.ts.map +1 -0
  33. package/dist/constants/paths.js +72 -0
  34. package/dist/constants/paths.js.map +1 -0
  35. package/dist/constants/timeouts.d.ts +84 -0
  36. package/dist/constants/timeouts.d.ts.map +1 -0
  37. package/dist/constants/timeouts.js +111 -0
  38. package/dist/constants/timeouts.js.map +1 -0
  39. package/dist/services/config-manager.d.ts +66 -0
  40. package/dist/services/config-manager.d.ts.map +1 -0
  41. package/dist/services/config-manager.js +206 -0
  42. package/dist/services/config-manager.js.map +1 -0
  43. package/dist/services/log-manager.d.ts +113 -0
  44. package/dist/services/log-manager.d.ts.map +1 -0
  45. package/dist/services/log-manager.js +288 -0
  46. package/dist/services/log-manager.js.map +1 -0
  47. package/dist/services/systemd-manager.d.ts +197 -0
  48. package/dist/services/systemd-manager.d.ts.map +1 -0
  49. package/dist/services/systemd-manager.js +458 -0
  50. package/dist/services/systemd-manager.js.map +1 -0
  51. package/dist/services/user-manager.d.ts +63 -0
  52. package/dist/services/user-manager.d.ts.map +1 -0
  53. package/dist/services/user-manager.js +219 -0
  54. package/dist/services/user-manager.js.map +1 -0
  55. package/dist/types/config.d.ts +256 -0
  56. package/dist/types/config.d.ts.map +1 -0
  57. package/dist/types/config.js +7 -0
  58. package/dist/types/config.js.map +1 -0
  59. package/dist/types/service.d.ts +96 -0
  60. package/dist/types/service.d.ts.map +1 -0
  61. package/dist/types/service.js +7 -0
  62. package/dist/types/service.js.map +1 -0
  63. package/dist/types/user.d.ts +114 -0
  64. package/dist/types/user.d.ts.map +1 -0
  65. package/dist/types/user.js +7 -0
  66. package/dist/types/user.js.map +1 -0
  67. package/dist/utils/clipboard.d.ts +21 -0
  68. package/dist/utils/clipboard.d.ts.map +1 -0
  69. package/dist/utils/clipboard.js +45 -0
  70. package/dist/utils/clipboard.js.map +1 -0
  71. package/dist/utils/format.d.ts +93 -0
  72. package/dist/utils/format.d.ts.map +1 -0
  73. package/dist/utils/format.js +242 -0
  74. package/dist/utils/format.js.map +1 -0
  75. package/dist/utils/logger.d.ts +113 -0
  76. package/dist/utils/logger.d.ts.map +1 -0
  77. package/dist/utils/logger.js +260 -0
  78. package/dist/utils/logger.js.map +1 -0
  79. package/dist/utils/preflight.d.ts +57 -0
  80. package/dist/utils/preflight.d.ts.map +1 -0
  81. package/dist/utils/preflight.js +215 -0
  82. package/dist/utils/preflight.js.map +1 -0
  83. package/dist/utils/validator.d.ts +102 -0
  84. package/dist/utils/validator.d.ts.map +1 -0
  85. package/dist/utils/validator.js +238 -0
  86. package/dist/utils/validator.js.map +1 -0
  87. package/dist/utils/which.d.ts +13 -0
  88. package/dist/utils/which.d.ts.map +1 -0
  89. package/dist/utils/which.js +28 -0
  90. package/dist/utils/which.js.map +1 -0
  91. package/package.json +69 -0
@@ -0,0 +1,206 @@
1
+ "use strict";
2
+ /**
3
+ * ConfigManager - Xray Configuration File Management
4
+ *
5
+ * Provides safe interface to read, write, validate, and backup Xray config
6
+ *
7
+ * @module services/config-manager
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.ConfigManager = void 0;
11
+ const promises_1 = require("fs/promises");
12
+ const fs_1 = require("fs");
13
+ const path_1 = require("path");
14
+ const paths_1 = require("../constants/paths");
15
+ /**
16
+ * ConfigManager - Safe configuration file operations
17
+ */
18
+ class ConfigManager {
19
+ /**
20
+ * Create a new ConfigManager
21
+ *
22
+ * @param configPath - Path to config file (default: /usr/local/etc/xray/config.json)
23
+ */
24
+ constructor(configPath) {
25
+ this.configPath = configPath || paths_1.DEFAULT_PATHS.CONFIG_FILE;
26
+ this.backupDir = paths_1.DEFAULT_PATHS.BACKUP_DIR || '/var/backups/xray';
27
+ }
28
+ /**
29
+ * Read and parse config file
30
+ *
31
+ * @returns Parsed configuration object
32
+ */
33
+ async readConfig() {
34
+ try {
35
+ const content = await (0, promises_1.readFile)(this.configPath, 'utf-8');
36
+ const config = JSON.parse(content);
37
+ return config;
38
+ }
39
+ catch (error) {
40
+ if (error.code === 'ENOENT') {
41
+ throw new Error(`配置文件不存在: ${this.configPath}`);
42
+ }
43
+ else if (error.code === 'EACCES') {
44
+ throw new Error(`配置文件无读取权限: ${this.configPath}。请使用 sudo 或以 root 用户运行。`);
45
+ }
46
+ else if (error instanceof SyntaxError) {
47
+ throw new Error(`配置文件 JSON 格式错误: ${error.message}`);
48
+ }
49
+ throw error;
50
+ }
51
+ }
52
+ /**
53
+ * Write config to file with secure permissions
54
+ *
55
+ * @param config - Configuration object to write
56
+ */
57
+ async writeConfig(config) {
58
+ try {
59
+ // Validate config before writing
60
+ this.validateConfig(config);
61
+ // Ensure directory exists
62
+ const dir = (0, path_1.dirname)(this.configPath);
63
+ if (!(0, fs_1.existsSync)(dir)) {
64
+ await (0, promises_1.mkdir)(dir, { recursive: true });
65
+ }
66
+ // Write with pretty formatting
67
+ const content = JSON.stringify(config, null, 2);
68
+ await (0, promises_1.writeFile)(this.configPath, content, 'utf-8');
69
+ // Set secure permissions (600 = rw-------)
70
+ await (0, promises_1.chmod)(this.configPath, 0o600);
71
+ }
72
+ catch (error) {
73
+ if (error.code === 'EACCES') {
74
+ throw new Error(`配置文件无写入权限: ${this.configPath}。请使用 sudo 或以 root 用户运行。`);
75
+ }
76
+ throw error;
77
+ }
78
+ }
79
+ /**
80
+ * Validate configuration structure
81
+ *
82
+ * @param config - Configuration to validate
83
+ * @throws Error if validation fails
84
+ */
85
+ validateConfig(config) {
86
+ if (!config || typeof config !== 'object') {
87
+ throw new Error('配置必须是一个对象');
88
+ }
89
+ // Check for required top-level fields
90
+ if (!config.inbounds || !Array.isArray(config.inbounds)) {
91
+ throw new Error('配置必须包含 inbounds 数组');
92
+ }
93
+ if (!config.outbounds || !Array.isArray(config.outbounds)) {
94
+ throw new Error('配置必须包含 outbounds 数组');
95
+ }
96
+ // Validate inbounds
97
+ for (const inbound of config.inbounds) {
98
+ if (!inbound.protocol) {
99
+ throw new Error('每个 inbound 必须指定 protocol');
100
+ }
101
+ if (typeof inbound.port !== 'number') {
102
+ throw new Error('每个 inbound 必须指定有效的 port');
103
+ }
104
+ }
105
+ // Validate outbounds
106
+ for (const outbound of config.outbounds) {
107
+ if (!outbound.protocol) {
108
+ throw new Error('每个 outbound 必须指定 protocol');
109
+ }
110
+ }
111
+ }
112
+ /**
113
+ * Backup configuration file
114
+ *
115
+ * @returns Path to backup file
116
+ */
117
+ async backupConfig() {
118
+ try {
119
+ // Ensure backup directory exists
120
+ if (!(0, fs_1.existsSync)(this.backupDir)) {
121
+ await (0, promises_1.mkdir)(this.backupDir, { recursive: true, mode: 0o700 });
122
+ }
123
+ // Generate timestamp-based backup filename
124
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
125
+ const backupPath = (0, path_1.join)(this.backupDir, `config.${timestamp}.json`);
126
+ // Read current config
127
+ const config = await this.readConfig();
128
+ // Write backup
129
+ const content = JSON.stringify(config, null, 2);
130
+ await (0, promises_1.writeFile)(backupPath, content, 'utf-8');
131
+ await (0, promises_1.chmod)(backupPath, 0o600);
132
+ return backupPath;
133
+ }
134
+ catch (error) {
135
+ throw new Error(`备份配置失败: ${error.message}`);
136
+ }
137
+ }
138
+ /**
139
+ * List available backups
140
+ *
141
+ * @returns Array of backup file paths
142
+ */
143
+ async listBackups() {
144
+ try {
145
+ if (!(0, fs_1.existsSync)(this.backupDir)) {
146
+ return [];
147
+ }
148
+ const files = await (0, promises_1.readdir)(this.backupDir);
149
+ const backups = files
150
+ .filter((file) => file.startsWith('config.') && file.endsWith('.json'))
151
+ .map((file) => (0, path_1.join)(this.backupDir, file))
152
+ .sort()
153
+ .reverse(); // Most recent first
154
+ return backups;
155
+ }
156
+ catch (error) {
157
+ throw new Error(`列出备份失败: ${error.message}`);
158
+ }
159
+ }
160
+ /**
161
+ * Restore configuration from backup
162
+ *
163
+ * @param backupPath - Path to backup file
164
+ */
165
+ async restoreConfig(backupPath) {
166
+ try {
167
+ // Verify backup file exists
168
+ await (0, promises_1.access)(backupPath);
169
+ // Backup current config first (pre-restore backup)
170
+ await this.backupConfig();
171
+ // Read backup content
172
+ const content = await (0, promises_1.readFile)(backupPath, 'utf-8');
173
+ const config = JSON.parse(content);
174
+ // Validate and write
175
+ await this.writeConfig(config);
176
+ }
177
+ catch (error) {
178
+ throw new Error(`恢复配置失败: ${error.message}`);
179
+ }
180
+ }
181
+ /**
182
+ * Modify a configuration item
183
+ *
184
+ * @param path - Dot-separated path to config item (e.g., "log.loglevel")
185
+ * @param value - New value
186
+ */
187
+ async modifyConfigItem(path, value) {
188
+ const config = await this.readConfig();
189
+ // Split path and navigate to parent object
190
+ const parts = path.split('.');
191
+ let current = config;
192
+ for (let i = 0; i < parts.length - 1; i++) {
193
+ if (!current[parts[i]]) {
194
+ current[parts[i]] = {};
195
+ }
196
+ current = current[parts[i]];
197
+ }
198
+ // Set value
199
+ const lastPart = parts[parts.length - 1];
200
+ current[lastPart] = value;
201
+ // Validate and write
202
+ await this.writeConfig(config);
203
+ }
204
+ }
205
+ exports.ConfigManager = ConfigManager;
206
+ //# sourceMappingURL=config-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../src/services/config-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * LogManager - System Log Management via journalctl
3
+ *
4
+ * Provides safe interface to query and follow systemd journal logs
5
+ *
6
+ * @module services/log-manager
7
+ */
8
+ import { ChildProcess } from 'child_process';
9
+ /**
10
+ * Log entry structure
11
+ */
12
+ export interface LogEntry {
13
+ /** Log timestamp */
14
+ timestamp: Date;
15
+ /** Log message */
16
+ message: string;
17
+ /** Log level */
18
+ level: string;
19
+ /** Process ID */
20
+ pid?: string;
21
+ /** Hostname */
22
+ hostname?: string;
23
+ /** Systemd unit */
24
+ unit?: string;
25
+ /** Raw log data */
26
+ raw?: string;
27
+ }
28
+ /**
29
+ * Log query options
30
+ */
31
+ export interface LogQueryOptions {
32
+ /** Filter by log level (error, warning, info, debug) */
33
+ level?: string;
34
+ /** Time range start (e.g., "1 hour ago", "today", "2024-01-01") */
35
+ since?: string;
36
+ /** Time range end */
37
+ until?: string;
38
+ /** Number of lines to retrieve */
39
+ lines?: number;
40
+ /** Follow mode (real-time) */
41
+ follow?: boolean;
42
+ }
43
+ /**
44
+ * Log follow process
45
+ */
46
+ export interface LogFollowProcess {
47
+ /** Kill the follow process */
48
+ kill: () => void;
49
+ /** Child process */
50
+ process: ChildProcess;
51
+ }
52
+ /**
53
+ * LogManager - Query and follow systemd journal logs
54
+ */
55
+ export declare class LogManager {
56
+ private serviceName;
57
+ /**
58
+ * Create a new LogManager
59
+ *
60
+ * @param serviceName - Service name to query logs for
61
+ */
62
+ constructor(serviceName: string);
63
+ /**
64
+ * Validate service name to prevent command injection
65
+ *
66
+ * @param name - Service name to validate
67
+ * @throws Error if invalid
68
+ */
69
+ private validateServiceName;
70
+ /**
71
+ * Check if journalctl is available
72
+ *
73
+ * @returns True if journalctl is available
74
+ */
75
+ isJournalctlAvailable(): boolean;
76
+ /**
77
+ * Map log level to journalctl priority
78
+ *
79
+ * @param level - Log level (error, warning, info, debug)
80
+ * @returns journalctl priority string
81
+ */
82
+ private mapLevelToPriority;
83
+ /**
84
+ * Map journalctl priority to readable level
85
+ *
86
+ * @param priority - Journalctl priority (0-7)
87
+ * @returns Readable log level
88
+ */
89
+ private mapPriorityToLevel;
90
+ /**
91
+ * Parse a JSON log entry from journalctl
92
+ *
93
+ * @param jsonLine - JSON string from journalctl -o json
94
+ * @returns Parsed log entry
95
+ */
96
+ parseLogEntry(jsonLine: string): LogEntry;
97
+ /**
98
+ * Query logs with filters
99
+ *
100
+ * @param options - Query options
101
+ * @returns Array of log entries
102
+ */
103
+ queryLogs(options?: LogQueryOptions): Promise<LogEntry[]>;
104
+ /**
105
+ * Follow logs in real-time
106
+ *
107
+ * @param options - Query options
108
+ * @param onLog - Callback for each log entry
109
+ * @returns Follow process controller
110
+ */
111
+ followLogs(options?: LogQueryOptions, onLog?: (entry: LogEntry) => void): Promise<LogFollowProcess>;
112
+ }
113
+ //# sourceMappingURL=log-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-manager.d.ts","sourceRoot":"","sources":["../../src/services/log-manager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAS,YAAY,EAAE,MAAM,eAAe,CAAC;AAIpD;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,oBAAoB;IACpB,SAAS,EAAE,IAAI,CAAC;IAEhB,kBAAkB;IAClB,OAAO,EAAE,MAAM,CAAC;IAEhB,gBAAgB;IAChB,KAAK,EAAE,MAAM,CAAC;IAEd,iBAAiB;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,eAAe;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,mBAAmB;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,mBAAmB;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,kCAAkC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,8BAA8B;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8BAA8B;IAC9B,IAAI,EAAE,MAAM,IAAI,CAAC;IAEjB,oBAAoB;IACpB,OAAO,EAAE,YAAY,CAAC;CACvB;AAED;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,WAAW,CAAS;IAE5B;;;;OAIG;gBACS,WAAW,EAAE,MAAM;IAK/B;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAuB3B;;;;OAIG;IACH,qBAAqB,IAAI,OAAO;IAShC;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAe1B;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAe1B;;;;;OAKG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ;IAkCzC;;;;;OAKG;IACG,SAAS,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IA4FnE;;;;;;OAMG;IACG,UAAU,CACd,OAAO,GAAE,eAAoB,EAC7B,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAChC,OAAO,CAAC,gBAAgB,CAAC;CAuE7B"}
@@ -0,0 +1,288 @@
1
+ "use strict";
2
+ /**
3
+ * LogManager - System Log Management via journalctl
4
+ *
5
+ * Provides safe interface to query and follow systemd journal logs
6
+ *
7
+ * @module services/log-manager
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.LogManager = void 0;
11
+ const child_process_1 = require("child_process");
12
+ const fs_1 = require("fs");
13
+ const which_1 = require("../utils/which");
14
+ /**
15
+ * LogManager - Query and follow systemd journal logs
16
+ */
17
+ class LogManager {
18
+ /**
19
+ * Create a new LogManager
20
+ *
21
+ * @param serviceName - Service name to query logs for
22
+ */
23
+ constructor(serviceName) {
24
+ this.validateServiceName(serviceName);
25
+ this.serviceName = serviceName;
26
+ }
27
+ /**
28
+ * Validate service name to prevent command injection
29
+ *
30
+ * @param name - Service name to validate
31
+ * @throws Error if invalid
32
+ */
33
+ validateServiceName(name) {
34
+ if (!name || name.trim().length === 0) {
35
+ throw new Error('Service name cannot be empty');
36
+ }
37
+ // Prevent path traversal
38
+ if (name.includes('/') || name.includes('\\') || name.includes('..')) {
39
+ throw new Error(`Invalid service name: ${name} (path traversal detected)`);
40
+ }
41
+ // Prevent command injection
42
+ const dangerousChars = /[;&|`$()]/;
43
+ if (dangerousChars.test(name)) {
44
+ throw new Error(`Invalid service name: ${name} (potentially dangerous characters detected)`);
45
+ }
46
+ // Only allow alphanumeric, dash, underscore, and dot
47
+ const validPattern = /^[a-zA-Z0-9_.-]+$/;
48
+ if (!validPattern.test(name)) {
49
+ throw new Error(`Invalid service name: ${name}`);
50
+ }
51
+ }
52
+ /**
53
+ * Check if journalctl is available
54
+ *
55
+ * @returns True if journalctl is available
56
+ */
57
+ isJournalctlAvailable() {
58
+ try {
59
+ const journalctlPath = (0, which_1.which)('journalctl');
60
+ return journalctlPath !== null && (0, fs_1.existsSync)(journalctlPath);
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ }
66
+ /**
67
+ * Map log level to journalctl priority
68
+ *
69
+ * @param level - Log level (error, warning, info, debug)
70
+ * @returns journalctl priority string
71
+ */
72
+ mapLevelToPriority(level) {
73
+ const mapping = {
74
+ emergency: 'emerg',
75
+ alert: 'alert',
76
+ critical: 'crit',
77
+ error: 'err',
78
+ warning: 'warning',
79
+ notice: 'notice',
80
+ info: 'info',
81
+ debug: 'debug',
82
+ };
83
+ return mapping[level.toLowerCase()] || level;
84
+ }
85
+ /**
86
+ * Map journalctl priority to readable level
87
+ *
88
+ * @param priority - Journalctl priority (0-7)
89
+ * @returns Readable log level
90
+ */
91
+ mapPriorityToLevel(priority) {
92
+ const mapping = {
93
+ '0': 'emergency',
94
+ '1': 'alert',
95
+ '2': 'critical',
96
+ '3': 'error',
97
+ '4': 'warning',
98
+ '5': 'notice',
99
+ '6': 'info',
100
+ '7': 'debug',
101
+ };
102
+ return mapping[priority] || 'unknown';
103
+ }
104
+ /**
105
+ * Parse a JSON log entry from journalctl
106
+ *
107
+ * @param jsonLine - JSON string from journalctl -o json
108
+ * @returns Parsed log entry
109
+ */
110
+ parseLogEntry(jsonLine) {
111
+ try {
112
+ const data = JSON.parse(jsonLine);
113
+ // Extract timestamp (microseconds since epoch)
114
+ const timestampMicros = parseInt(data.__REALTIME_TIMESTAMP || '0', 10);
115
+ const timestamp = new Date(timestampMicros / 1000);
116
+ // Extract message
117
+ const message = data.MESSAGE || '';
118
+ // Extract and map priority
119
+ const priority = data.PRIORITY || '6';
120
+ const level = this.mapPriorityToLevel(priority);
121
+ // Extract metadata
122
+ const pid = data._PID;
123
+ const hostname = data._HOSTNAME;
124
+ const unit = data._SYSTEMD_UNIT;
125
+ return {
126
+ timestamp,
127
+ message,
128
+ level,
129
+ pid,
130
+ hostname,
131
+ unit,
132
+ raw: jsonLine,
133
+ };
134
+ }
135
+ catch (error) {
136
+ throw new Error(`Failed to parse log entry: ${error.message}`);
137
+ }
138
+ }
139
+ /**
140
+ * Query logs with filters
141
+ *
142
+ * @param options - Query options
143
+ * @returns Array of log entries
144
+ */
145
+ async queryLogs(options = {}) {
146
+ if (!this.isJournalctlAvailable()) {
147
+ throw new Error('journalctl is not available on this system. Please ensure systemd is installed.');
148
+ }
149
+ // Build journalctl arguments
150
+ const args = [
151
+ '-u',
152
+ this.serviceName, // Unit filter
153
+ '-o',
154
+ 'json', // JSON output
155
+ '--no-pager', // Disable pager
156
+ ];
157
+ // Add level filter
158
+ if (options.level) {
159
+ const priority = this.mapLevelToPriority(options.level);
160
+ args.push('-p', priority);
161
+ }
162
+ // Add time range filters
163
+ if (options.since) {
164
+ args.push('--since', options.since);
165
+ }
166
+ if (options.until) {
167
+ args.push('--until', options.until);
168
+ }
169
+ // Add line limit
170
+ if (options.lines) {
171
+ args.push('-n', String(options.lines));
172
+ }
173
+ return new Promise((resolve, reject) => {
174
+ const child = (0, child_process_1.spawn)('journalctl', args, {
175
+ stdio: ['ignore', 'pipe', 'pipe'],
176
+ });
177
+ let stdout = '';
178
+ let stderr = '';
179
+ child.stdout.on('data', (data) => {
180
+ stdout += data.toString();
181
+ });
182
+ child.stderr.on('data', (data) => {
183
+ stderr += data.toString();
184
+ });
185
+ child.on('close', (code) => {
186
+ if (code !== 0) {
187
+ const errorMsg = stderr.trim() || `journalctl exited with code ${code}`;
188
+ // Provide helpful error messages
189
+ if (errorMsg.includes('permission') || errorMsg.includes('access')) {
190
+ reject(new Error(`无权访问日志。请使用 sudo 或以 root 用户运行。\n详细错误: ${errorMsg}`));
191
+ }
192
+ else {
193
+ reject(new Error(`查询日志失败: ${errorMsg}`));
194
+ }
195
+ return;
196
+ }
197
+ // Parse log entries
198
+ const logs = [];
199
+ const lines = stdout.trim().split('\n');
200
+ for (const line of lines) {
201
+ if (!line.trim())
202
+ continue;
203
+ try {
204
+ const entry = this.parseLogEntry(line);
205
+ logs.push(entry);
206
+ }
207
+ catch (error) {
208
+ // Skip malformed entries
209
+ console.warn(`Skipped malformed log entry: ${error.message}`);
210
+ }
211
+ }
212
+ resolve(logs);
213
+ });
214
+ child.on('error', (error) => {
215
+ reject(new Error(`Failed to execute journalctl: ${error.message}`));
216
+ });
217
+ });
218
+ }
219
+ /**
220
+ * Follow logs in real-time
221
+ *
222
+ * @param options - Query options
223
+ * @param onLog - Callback for each log entry
224
+ * @returns Follow process controller
225
+ */
226
+ async followLogs(options = {}, onLog) {
227
+ if (!this.isJournalctlAvailable()) {
228
+ throw new Error('journalctl is not available on this system. Please ensure systemd is installed.');
229
+ }
230
+ // Build journalctl arguments
231
+ const args = [
232
+ '-u',
233
+ this.serviceName,
234
+ '-o',
235
+ 'json',
236
+ '--no-pager',
237
+ '-f', // Follow mode
238
+ ];
239
+ // Add level filter
240
+ if (options.level) {
241
+ const priority = this.mapLevelToPriority(options.level);
242
+ args.push('-p', priority);
243
+ }
244
+ // Add line limit for initial output
245
+ if (options.lines) {
246
+ args.push('-n', String(options.lines));
247
+ }
248
+ const child = (0, child_process_1.spawn)('journalctl', args, {
249
+ stdio: ['ignore', 'pipe', 'pipe'],
250
+ });
251
+ // Handle stdout
252
+ if (onLog) {
253
+ let buffer = '';
254
+ child.stdout.on('data', (data) => {
255
+ buffer += data.toString();
256
+ const lines = buffer.split('\n');
257
+ // Process complete lines
258
+ for (let i = 0; i < lines.length - 1; i++) {
259
+ const line = lines[i].trim();
260
+ if (!line)
261
+ continue;
262
+ try {
263
+ const entry = this.parseLogEntry(line);
264
+ onLog(entry);
265
+ }
266
+ catch (error) {
267
+ console.warn(`Skipped malformed log entry: ${error.message}`);
268
+ }
269
+ }
270
+ // Keep incomplete line in buffer
271
+ buffer = lines[lines.length - 1];
272
+ });
273
+ }
274
+ // Handle stderr
275
+ child.stderr.on('data', (data) => {
276
+ const errorMsg = data.toString();
277
+ console.error(`journalctl error: ${errorMsg}`);
278
+ });
279
+ return {
280
+ process: child,
281
+ kill: () => {
282
+ child.kill('SIGINT');
283
+ },
284
+ };
285
+ }
286
+ }
287
+ exports.LogManager = LogManager;
288
+ //# sourceMappingURL=log-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-manager.js","sourceRoot":"","sources":["../../src/services/log-manager.ts"],"names":[],"mappings":"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"}