@pilaf/backends 1.0.1 → 1.2.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.
- package/README.md +1170 -10
- package/lib/collectors/DockerLogCollector.js +334 -0
- package/lib/collectors/index.js +9 -0
- package/lib/core/CommandRouter.js +154 -0
- package/lib/core/CorrelationStrategy.js +172 -0
- package/lib/core/LogCollector.js +194 -0
- package/lib/core/LogParser.js +125 -0
- package/lib/core/index.js +26 -0
- package/lib/errors/index.js +363 -0
- package/lib/helpers/EventObserver.js +267 -0
- package/lib/helpers/QueryHelper.js +279 -0
- package/lib/helpers/index.js +13 -0
- package/lib/index.js +72 -1
- package/lib/mineflayer-backend.js +266 -1
- package/lib/monitoring/CircularBuffer.js +202 -0
- package/lib/monitoring/LogMonitor.js +303 -0
- package/lib/monitoring/correlations/TagCorrelationStrategy.js +214 -0
- package/lib/monitoring/correlations/UsernameCorrelationStrategy.js +233 -0
- package/lib/monitoring/correlations/index.js +13 -0
- package/lib/monitoring/index.js +16 -0
- package/lib/parsers/MinecraftLogParser.js +512 -0
- package/lib/parsers/PatternRegistry.js +366 -0
- package/lib/parsers/fixtures/minecraft-logs.js +188 -0
- package/lib/parsers/index.js +13 -0
- package/lib/rcon-backend.js +42 -26
- package/package.json +2 -1
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LogCollector - Abstract base class for log collection
|
|
3
|
+
*
|
|
4
|
+
* Defines the interface for collecting raw log data from various sources
|
|
5
|
+
* (Docker containers, log files, syslog, etc.). Concrete implementations
|
|
6
|
+
* must extend this class and implement the abstract methods.
|
|
7
|
+
*
|
|
8
|
+
* @abstract
|
|
9
|
+
* @class
|
|
10
|
+
* @extends EventEmitter
|
|
11
|
+
*
|
|
12
|
+
* Responsibilities (MECE):
|
|
13
|
+
* - ONLY: Connect to log source and receive raw log lines
|
|
14
|
+
* - NOT: Parse log content (LogParser's responsibility)
|
|
15
|
+
* - NOT: Correlate responses (CorrelationStrategy's responsibility)
|
|
16
|
+
*
|
|
17
|
+
* Usage Example:
|
|
18
|
+
* // Extend LogCollector and implement abstract methods
|
|
19
|
+
* function DockerLogCollector() {
|
|
20
|
+
* LogCollector.call(this);
|
|
21
|
+
* }
|
|
22
|
+
* DockerLogCollector.prototype = Object.create(LogCollector.prototype);
|
|
23
|
+
* DockerLogCollector.prototype.connect = async function(config) { ... };
|
|
24
|
+
* DockerLogCollector.prototype.disconnect = async function() { ... };
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const EventEmitter = require('events');
|
|
28
|
+
|
|
29
|
+
class LogCollector extends EventEmitter {
|
|
30
|
+
/**
|
|
31
|
+
* Create a LogCollector
|
|
32
|
+
* @throws {Error} Direct instantiation of abstract class
|
|
33
|
+
*/
|
|
34
|
+
constructor() {
|
|
35
|
+
super();
|
|
36
|
+
|
|
37
|
+
// Prevent direct instantiation of abstract class
|
|
38
|
+
if (this.constructor === LogCollector) {
|
|
39
|
+
throw new Error('LogCollector is abstract and cannot be instantiated directly');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Connection state
|
|
44
|
+
* @protected
|
|
45
|
+
* @type {boolean}
|
|
46
|
+
*/
|
|
47
|
+
this._connected = false;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Pause state
|
|
51
|
+
* @protected
|
|
52
|
+
* @type {boolean}
|
|
53
|
+
*/
|
|
54
|
+
this._paused = false;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Connection configuration
|
|
58
|
+
* @protected
|
|
59
|
+
* @type {Object|null}
|
|
60
|
+
*/
|
|
61
|
+
this._config = null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get connection state
|
|
66
|
+
* @returns {boolean}
|
|
67
|
+
*/
|
|
68
|
+
get connected() {
|
|
69
|
+
return this._connected;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get pause state
|
|
74
|
+
* @returns {boolean}
|
|
75
|
+
*/
|
|
76
|
+
get paused() {
|
|
77
|
+
return this._paused;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get connection configuration
|
|
82
|
+
* @returns {Object|null}
|
|
83
|
+
*/
|
|
84
|
+
get config() {
|
|
85
|
+
return this._config;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Connect to the log source
|
|
90
|
+
*
|
|
91
|
+
* Abstract method that must be implemented by concrete classes.
|
|
92
|
+
* Should establish connection to the log source and start emitting
|
|
93
|
+
* 'data' events with raw log lines.
|
|
94
|
+
*
|
|
95
|
+
* @abstract
|
|
96
|
+
* @param {Object} config - Connection configuration
|
|
97
|
+
* @param {string} [config.host] - Host address (for remote sources)
|
|
98
|
+
* @param {number} [config.port] - Port number (for remote sources)
|
|
99
|
+
* @param {string} [config.path] - File path (for file sources)
|
|
100
|
+
* @param {string} [config.containerName] - Container name (for Docker)
|
|
101
|
+
* @returns {Promise<void>}
|
|
102
|
+
* @throws {Error} If connection fails
|
|
103
|
+
*/
|
|
104
|
+
async connect(config) {
|
|
105
|
+
throw new Error('Method "connect()" must be implemented by subclass');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Disconnect from the log source
|
|
110
|
+
*
|
|
111
|
+
* Abstract method that must be implemented by concrete classes.
|
|
112
|
+
* Should clean up resources and stop emitting events.
|
|
113
|
+
*
|
|
114
|
+
* @abstract
|
|
115
|
+
* @returns {Promise<void>}
|
|
116
|
+
*/
|
|
117
|
+
async disconnect() {
|
|
118
|
+
throw new Error('Method "disconnect()" must be implemented by subclass');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Pause log collection
|
|
123
|
+
*
|
|
124
|
+
* Stops emitting 'data' events without disconnecting.
|
|
125
|
+
* Collection can be resumed with resume().
|
|
126
|
+
*
|
|
127
|
+
* @returns {void}
|
|
128
|
+
*/
|
|
129
|
+
pause() {
|
|
130
|
+
this._paused = true;
|
|
131
|
+
this.emit('paused');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Resume log collection
|
|
136
|
+
*
|
|
137
|
+
* Resumes emitting 'data' events after pause().
|
|
138
|
+
*
|
|
139
|
+
* @returns {void}
|
|
140
|
+
*/
|
|
141
|
+
resume() {
|
|
142
|
+
this._paused = false;
|
|
143
|
+
this.emit('resumed');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Emit a log line (protected method for subclasses)
|
|
148
|
+
*
|
|
149
|
+
* Emits 'data' event with raw log line if connected and not paused.
|
|
150
|
+
* Subclasses should call this method when they receive log data.
|
|
151
|
+
*
|
|
152
|
+
* @protected
|
|
153
|
+
* @param {string} line - Raw log line
|
|
154
|
+
* @returns {boolean} - True if event was emitted, false if paused/disconnected
|
|
155
|
+
*/
|
|
156
|
+
_emitData(line) {
|
|
157
|
+
if (!this._connected || this._paused) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
this.emit('data', line);
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Emit an error (protected method for subclasses)
|
|
167
|
+
*
|
|
168
|
+
* Emits 'error' event. Subclasses should call this method when
|
|
169
|
+
* errors occur during collection.
|
|
170
|
+
*
|
|
171
|
+
* @protected
|
|
172
|
+
* @param {Error} error - The error to emit
|
|
173
|
+
* @returns {void}
|
|
174
|
+
*/
|
|
175
|
+
_emitError(error) {
|
|
176
|
+
this.emit('error', error);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Emit end event (protected method for subclasses)
|
|
181
|
+
*
|
|
182
|
+
* Emits 'end' event when the log stream terminates.
|
|
183
|
+
* Subclasses should call this when the stream ends naturally.
|
|
184
|
+
*
|
|
185
|
+
* @protected
|
|
186
|
+
* @returns {void}
|
|
187
|
+
*/
|
|
188
|
+
_emitEnd() {
|
|
189
|
+
this._connected = false;
|
|
190
|
+
this.emit('end');
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
module.exports = { LogCollector };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LogParser - Abstract base class for log parsing
|
|
3
|
+
*
|
|
4
|
+
* Defines the interface for parsing raw log lines into structured events.
|
|
5
|
+
* Concrete implementations must extend this class and implement the
|
|
6
|
+
* abstract parse() method.
|
|
7
|
+
*
|
|
8
|
+
* @abstract
|
|
9
|
+
* @class
|
|
10
|
+
*
|
|
11
|
+
* Responsibilities (MECE):
|
|
12
|
+
* - ONLY: Parse raw log lines into structured events
|
|
13
|
+
* - NOT: Collect logs (LogCollector's responsibility)
|
|
14
|
+
* - NOT: Emit events to consumers (LogMonitor's responsibility)
|
|
15
|
+
* - NOT: Correlate responses (CorrelationStrategy's responsibility)
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* class MinecraftLogParser extends LogParser {
|
|
19
|
+
* parse(line) {
|
|
20
|
+
* // Parse and return { type, data, raw } or null
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
class LogParser {
|
|
26
|
+
/**
|
|
27
|
+
* Create a LogParser
|
|
28
|
+
* @throws {Error} Direct instantiation of abstract class
|
|
29
|
+
*/
|
|
30
|
+
constructor() {
|
|
31
|
+
// Prevent direct instantiation of abstract class
|
|
32
|
+
if (this.constructor === LogParser) {
|
|
33
|
+
throw new Error('LogParser is abstract and cannot be instantiated directly');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Parse a log line into a structured event
|
|
39
|
+
*
|
|
40
|
+
* Abstract method that must be implemented by concrete classes.
|
|
41
|
+
* Should analyze the log line and extract structured data.
|
|
42
|
+
*
|
|
43
|
+
* @abstract
|
|
44
|
+
* @param {string} line - Raw log line to parse
|
|
45
|
+
* @returns {Object|null} - Parsed event or null if line doesn't match any pattern
|
|
46
|
+
* @property {string} type - Event type (e.g., 'teleport', 'death', 'command')
|
|
47
|
+
* @property {Object} data - Parsed event data (structure varies by type)
|
|
48
|
+
* @property {string} raw - Original raw log line
|
|
49
|
+
* @example
|
|
50
|
+
* // Returns:
|
|
51
|
+
* // {
|
|
52
|
+
* // type: 'teleport',
|
|
53
|
+
* // data: { player: 'TestPlayer', position: { x: 100, y: 64, z: 100 } },
|
|
54
|
+
* // raw: '[12:34:56] Teleported TestPlayer to 100.0, 64.0, 100.0'
|
|
55
|
+
* // }
|
|
56
|
+
*/
|
|
57
|
+
parse(line) {
|
|
58
|
+
throw new Error('Method "parse()" must be implemented by subclass');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Add a parsing pattern (optional method for pattern-based parsers)
|
|
63
|
+
*
|
|
64
|
+
* Default implementation throws. Pattern-based parsers should override.
|
|
65
|
+
*
|
|
66
|
+
* @param {string} name - Pattern name/identifier
|
|
67
|
+
* @param {RegExp|string} pattern - Regex pattern or string pattern
|
|
68
|
+
* @param {Function} handler - Handler function: (match) => data
|
|
69
|
+
* @returns {void}
|
|
70
|
+
* @throws {Error} If not supported by parser implementation
|
|
71
|
+
*/
|
|
72
|
+
addPattern(name, pattern, handler) {
|
|
73
|
+
throw new Error('Method "addPattern()" is not supported by this parser');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Remove a parsing pattern (optional method for pattern-based parsers)
|
|
78
|
+
*
|
|
79
|
+
* Default implementation throws. Pattern-based parsers should override.
|
|
80
|
+
*
|
|
81
|
+
* @param {string} name - Pattern name to remove
|
|
82
|
+
* @returns {boolean} - True if pattern was removed, false if not found
|
|
83
|
+
* @throws {Error} If not supported by parser implementation
|
|
84
|
+
*/
|
|
85
|
+
removePattern(name) {
|
|
86
|
+
throw new Error('Method "removePattern()" is not supported by this parser');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get all registered patterns (optional method for pattern-based parsers)
|
|
91
|
+
*
|
|
92
|
+
* Default implementation throws. Pattern-based parsers should override.
|
|
93
|
+
*
|
|
94
|
+
* @returns {Array<string>} - Array of pattern names
|
|
95
|
+
* @throws {Error} If not supported by parser implementation
|
|
96
|
+
*/
|
|
97
|
+
getPatterns() {
|
|
98
|
+
throw new Error('Method "getPatterns()" is not supported by this parser');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Validate parse result format
|
|
103
|
+
*
|
|
104
|
+
* Protected method to ensure parse() returns correct format.
|
|
105
|
+
* Used by concrete implementations to validate their output.
|
|
106
|
+
*
|
|
107
|
+
* @protected
|
|
108
|
+
* @param {Object|null} result - Result from parse()
|
|
109
|
+
* @returns {boolean} - True if format is valid
|
|
110
|
+
*/
|
|
111
|
+
_validateResult(result) {
|
|
112
|
+
if (result === null) {
|
|
113
|
+
return true; // null is valid (no match)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
typeof result === 'object' &&
|
|
118
|
+
typeof result.type === 'string' &&
|
|
119
|
+
typeof result.data === 'object' &&
|
|
120
|
+
typeof result.raw === 'string'
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = { LogParser };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core Abstractions Index
|
|
3
|
+
*
|
|
4
|
+
* This module exports all core abstraction classes for the Pilaf backend system.
|
|
5
|
+
* These abstractions define the interfaces that concrete implementations must follow.
|
|
6
|
+
*
|
|
7
|
+
* @module core/index
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { LogCollector } = require('./LogCollector.js');
|
|
11
|
+
const { LogParser } = require('./LogParser.js');
|
|
12
|
+
const { CommandRouter } = require('./CommandRouter.js');
|
|
13
|
+
const { CorrelationStrategy } = require('./CorrelationStrategy.js');
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
// Abstract base classes
|
|
17
|
+
LogCollector,
|
|
18
|
+
LogParser,
|
|
19
|
+
CommandRouter,
|
|
20
|
+
CorrelationStrategy,
|
|
21
|
+
|
|
22
|
+
// Factory functions (implemented by concrete modules)
|
|
23
|
+
collectors: null, // Will be set by collectors/index.js
|
|
24
|
+
parsers: null, // Will be set by parsers/index.js
|
|
25
|
+
strategies: null // Will be set by strategies/index.js
|
|
26
|
+
};
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pilaf Error Hierarchy
|
|
3
|
+
*
|
|
4
|
+
* Defines all error types used throughout the Pilaf backend system.
|
|
5
|
+
* Follows a hierarchical structure with machine-readable codes and
|
|
6
|
+
* human-readable messages.
|
|
7
|
+
*
|
|
8
|
+
* Error Hierarchy:
|
|
9
|
+
* PilafError (base)
|
|
10
|
+
* ├── ConnectionError
|
|
11
|
+
* │ ├── RconConnectionError
|
|
12
|
+
* │ ├── DockerConnectionError
|
|
13
|
+
* │ └── FileAccessError
|
|
14
|
+
* ├── CommandExecutionError
|
|
15
|
+
* │ ├── CommandTimeoutError
|
|
16
|
+
* │ └── CommandRejectedError
|
|
17
|
+
* ├── ParseError
|
|
18
|
+
* │ ├── MalformedLogError
|
|
19
|
+
* │ └── UnknownPatternError
|
|
20
|
+
* ├── CorrelationError
|
|
21
|
+
* │ ├── ResponseTimeoutError
|
|
22
|
+
* │ └── AmbiguousMatchError
|
|
23
|
+
* └── ResourceError
|
|
24
|
+
* ├── BufferOverflowError
|
|
25
|
+
* └── HandleExhaustedError
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Base Pilaf Error
|
|
30
|
+
*
|
|
31
|
+
* All Pilaf errors extend from this class.
|
|
32
|
+
*
|
|
33
|
+
* @class
|
|
34
|
+
* @extends Error
|
|
35
|
+
* @property {string} code - Machine-readable error code
|
|
36
|
+
* @property {string} message - Human-readable error message
|
|
37
|
+
* @property {Object} details - Additional debugging context
|
|
38
|
+
* @property {Error} [cause] - Original error that caused this error
|
|
39
|
+
*/
|
|
40
|
+
class PilafError extends Error {
|
|
41
|
+
/**
|
|
42
|
+
* Create a PilafError
|
|
43
|
+
* @param {string} code - Machine-readable error code (e.g., 'CONNECTION_FAILED')
|
|
44
|
+
* @param {string} message - Human-readable error message
|
|
45
|
+
* @param {Object} [details={}] - Additional debugging context
|
|
46
|
+
* @param {Error} [cause] - Original error that caused this error
|
|
47
|
+
*/
|
|
48
|
+
constructor(code, message, details = {}, cause = null) {
|
|
49
|
+
super(message);
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Error name (class name)
|
|
53
|
+
* @type {string}
|
|
54
|
+
*/
|
|
55
|
+
this.name = this.constructor.name;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Machine-readable error code
|
|
59
|
+
* @type {string}
|
|
60
|
+
*/
|
|
61
|
+
this.code = code;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Human-readable message
|
|
65
|
+
* @type {string}
|
|
66
|
+
*/
|
|
67
|
+
this.message = message;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Additional debugging context
|
|
71
|
+
* @type {Object}
|
|
72
|
+
*/
|
|
73
|
+
this.details = details;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Original cause (if any)
|
|
77
|
+
* @type {Error|null}
|
|
78
|
+
*/
|
|
79
|
+
this.cause = cause;
|
|
80
|
+
|
|
81
|
+
// Maintain proper stack trace
|
|
82
|
+
if (Error.captureStackTrace) {
|
|
83
|
+
Error.captureStackTrace(this, this.constructor);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Convert error to JSON for logging/serialization
|
|
89
|
+
* @returns {Object} - JSON representation of error
|
|
90
|
+
*/
|
|
91
|
+
toJSON() {
|
|
92
|
+
return {
|
|
93
|
+
name: this.name,
|
|
94
|
+
code: this.code,
|
|
95
|
+
message: this.message,
|
|
96
|
+
details: this.details,
|
|
97
|
+
cause: this.cause ? {
|
|
98
|
+
name: this.cause.name,
|
|
99
|
+
message: this.cause.message,
|
|
100
|
+
stack: this.cause.stack
|
|
101
|
+
} : null,
|
|
102
|
+
stack: this.stack
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Pretty-print error for debugging
|
|
108
|
+
* @returns {string} - Formatted error string
|
|
109
|
+
*/
|
|
110
|
+
toString() {
|
|
111
|
+
let output = `[${this.code}] ${this.message}`;
|
|
112
|
+
|
|
113
|
+
if (Object.keys(this.details).length > 0) {
|
|
114
|
+
output += `\nDetails: ${JSON.stringify(this.details, null, 2)}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (this.cause) {
|
|
118
|
+
output += `\nCaused by: ${this.cause.message}`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return output;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ============================================================================
|
|
126
|
+
// CONNECTION ERRORS
|
|
127
|
+
// ============================================================================
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Base class for connection-related errors
|
|
131
|
+
*/
|
|
132
|
+
class ConnectionError extends PilafError {
|
|
133
|
+
constructor(message, details = {}, cause = null) {
|
|
134
|
+
super('CONNECTION_ERROR', message, details, cause);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* RCON connection failure
|
|
140
|
+
*/
|
|
141
|
+
class RconConnectionError extends ConnectionError {
|
|
142
|
+
constructor(message, details = {}, cause = null) {
|
|
143
|
+
super(message, { ...details, component: 'RCON' }, cause);
|
|
144
|
+
this.code = 'RCON_CONNECTION_ERROR';
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Docker API connection failure
|
|
150
|
+
*/
|
|
151
|
+
class DockerConnectionError extends ConnectionError {
|
|
152
|
+
constructor(message, details = {}, cause = null) {
|
|
153
|
+
super(message, { ...details, component: 'Docker' }, cause);
|
|
154
|
+
this.code = 'DOCKER_CONNECTION_ERROR';
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* File access failure
|
|
160
|
+
*/
|
|
161
|
+
class FileAccessError extends ConnectionError {
|
|
162
|
+
constructor(message, details = {}, cause = null) {
|
|
163
|
+
super(message, { ...details, component: 'FileSystem' }, cause);
|
|
164
|
+
this.code = 'FILE_ACCESS_ERROR';
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ============================================================================
|
|
169
|
+
// COMMAND EXECUTION ERRORS
|
|
170
|
+
// ============================================================================
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Base class for command execution errors
|
|
174
|
+
*/
|
|
175
|
+
class CommandExecutionError extends PilafError {
|
|
176
|
+
constructor(message, details = {}, cause = null) {
|
|
177
|
+
super('COMMAND_ERROR', message, details, cause);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Command execution timeout
|
|
183
|
+
*/
|
|
184
|
+
class CommandTimeoutError extends CommandExecutionError {
|
|
185
|
+
constructor(command, timeout, details = {}) {
|
|
186
|
+
super(
|
|
187
|
+
`Command timed out after ${timeout}ms`,
|
|
188
|
+
{ ...details, command, timeout },
|
|
189
|
+
null
|
|
190
|
+
);
|
|
191
|
+
this.code = 'COMMAND_TIMEOUT';
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Command rejected by server
|
|
197
|
+
*/
|
|
198
|
+
class CommandRejectedError extends CommandExecutionError {
|
|
199
|
+
constructor(command, reason, details = {}) {
|
|
200
|
+
super(
|
|
201
|
+
`Command rejected by server: ${reason}`,
|
|
202
|
+
{ ...details, command, reason },
|
|
203
|
+
null
|
|
204
|
+
);
|
|
205
|
+
this.code = 'COMMAND_REJECTED';
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ============================================================================
|
|
210
|
+
// PARSING ERRORS
|
|
211
|
+
// ============================================================================
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Base class for parsing errors
|
|
215
|
+
*/
|
|
216
|
+
class ParseError extends PilafError {
|
|
217
|
+
constructor(message, details = {}, cause = null) {
|
|
218
|
+
super('PARSE_ERROR', message, details, cause);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Malformed log line
|
|
224
|
+
*/
|
|
225
|
+
class MalformedLogError extends ParseError {
|
|
226
|
+
constructor(line, reason, details = {}) {
|
|
227
|
+
super(
|
|
228
|
+
`Malformed log line: ${reason}`,
|
|
229
|
+
{ ...details, line },
|
|
230
|
+
null
|
|
231
|
+
);
|
|
232
|
+
this.code = 'MALFORMED_LOG';
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Unknown log pattern
|
|
238
|
+
*/
|
|
239
|
+
class UnknownPatternError extends ParseError {
|
|
240
|
+
constructor(line, details = {}) {
|
|
241
|
+
super(
|
|
242
|
+
'Log line does not match any known pattern',
|
|
243
|
+
{ ...details, line },
|
|
244
|
+
null
|
|
245
|
+
);
|
|
246
|
+
this.code = 'UNKNOWN_PATTERN';
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ============================================================================
|
|
251
|
+
// CORRELATION ERRORS
|
|
252
|
+
// ============================================================================
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Base class for correlation errors
|
|
256
|
+
*/
|
|
257
|
+
class CorrelationError extends PilafError {
|
|
258
|
+
constructor(message, details = {}, cause = null) {
|
|
259
|
+
super('CORRELATION_ERROR', message, details, cause);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Response correlation timeout
|
|
265
|
+
*/
|
|
266
|
+
class ResponseTimeoutError extends CorrelationError {
|
|
267
|
+
constructor(command, timeout, details = {}) {
|
|
268
|
+
// Call parent with generic message, then override code
|
|
269
|
+
super(`No response received within ${timeout}ms`, { ...details, command, timeout }, null);
|
|
270
|
+
// Override the parent's code
|
|
271
|
+
this.code = 'CORRELATION_TIMEOUT';
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Ambiguous match (multiple potential responses)
|
|
277
|
+
*/
|
|
278
|
+
class AmbiguousMatchError extends CorrelationError {
|
|
279
|
+
constructor(command, matches, details = {}) {
|
|
280
|
+
super(
|
|
281
|
+
`${matches.length} potential responses found for command`,
|
|
282
|
+
{ ...details, command, matchCount: matches.length },
|
|
283
|
+
null
|
|
284
|
+
);
|
|
285
|
+
this.code = 'AMBIGUOUS_MATCH';
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// ============================================================================
|
|
290
|
+
// RESOURCE ERRORS
|
|
291
|
+
// ============================================================================
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Base class for resource-related errors
|
|
295
|
+
*/
|
|
296
|
+
class ResourceError extends PilafError {
|
|
297
|
+
constructor(message, details = {}, cause = null) {
|
|
298
|
+
super('RESOURCE_ERROR', message, details, cause);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Buffer overflow
|
|
304
|
+
*/
|
|
305
|
+
class BufferOverflowError extends ResourceError {
|
|
306
|
+
constructor(size, limit, details = {}) {
|
|
307
|
+
super(
|
|
308
|
+
`Buffer size (${size}) exceeds limit (${limit})`,
|
|
309
|
+
{ ...details, size, limit },
|
|
310
|
+
null
|
|
311
|
+
);
|
|
312
|
+
this.code = 'BUFFER_OVERFLOW';
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Handle/file descriptor exhaustion
|
|
318
|
+
*/
|
|
319
|
+
class HandleExhaustedError extends ResourceError {
|
|
320
|
+
constructor(resourceType, details = {}) {
|
|
321
|
+
super(
|
|
322
|
+
`Unable to allocate ${resourceType} handle`,
|
|
323
|
+
{ ...details, resourceType },
|
|
324
|
+
null
|
|
325
|
+
);
|
|
326
|
+
this.code = 'HANDLE_EXHAUSTED';
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// ============================================================================
|
|
331
|
+
// EXPORTS
|
|
332
|
+
// ============================================================================
|
|
333
|
+
|
|
334
|
+
module.exports = {
|
|
335
|
+
// Base error
|
|
336
|
+
PilafError,
|
|
337
|
+
|
|
338
|
+
// Connection errors
|
|
339
|
+
ConnectionError,
|
|
340
|
+
RconConnectionError,
|
|
341
|
+
DockerConnectionError,
|
|
342
|
+
FileAccessError,
|
|
343
|
+
|
|
344
|
+
// Command errors
|
|
345
|
+
CommandExecutionError,
|
|
346
|
+
CommandTimeoutError,
|
|
347
|
+
CommandRejectedError,
|
|
348
|
+
|
|
349
|
+
// Parse errors
|
|
350
|
+
ParseError,
|
|
351
|
+
MalformedLogError,
|
|
352
|
+
UnknownPatternError,
|
|
353
|
+
|
|
354
|
+
// Correlation errors
|
|
355
|
+
CorrelationError,
|
|
356
|
+
ResponseTimeoutError,
|
|
357
|
+
AmbiguousMatchError,
|
|
358
|
+
|
|
359
|
+
// Resource errors
|
|
360
|
+
ResourceError,
|
|
361
|
+
BufferOverflowError,
|
|
362
|
+
HandleExhaustedError
|
|
363
|
+
};
|