@pilaf/backends 1.0.2 → 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.
@@ -0,0 +1,233 @@
1
+ /**
2
+ * UsernameCorrelationStrategy - Correlates events by player username
3
+ *
4
+ * This correlation strategy groups events by player username to track
5
+ * player sessions across all their activities. Useful for:
6
+ *
7
+ * - Tracking player session lifecycle (join -> actions -> leave)
8
+ * - Monitoring player behavior patterns
9
+ * - Generating per-player statistics
10
+ * - Debugging player-specific issues
11
+ *
12
+ * Example use case:
13
+ * - Player joins: entity.join event with data.player = "Steve"
14
+ * - Player dies: entity.death.slain event with data.player = "Steve"
15
+ * - Player leaves: entity.leave event with data.player = "Steve"
16
+ * - Strategy groups all events under username "Steve"
17
+ *
18
+ * Features:
19
+ * - Configurable username extraction function
20
+ * - Session tracking (start/end times)
21
+ * - Active/inactive session status
22
+ * - Automatic session cleanup on leave
23
+ *
24
+ * Usage Example:
25
+ * const strategy = new UsernameCorrelationStrategy({
26
+ * usernameExtractor: (event) => event.data?.player
27
+ * });
28
+ *
29
+ * const joinEvent = { type: 'entity.join', data: { player: 'Steve' } };
30
+ * const correlation = strategy.correlate(joinEvent);
31
+ * // correlation: { username: 'Steve', events: [joinEvent], sessionStart: Date.now(), isActive: true }
32
+ */
33
+
34
+ const { EventEmitter } = require('events');
35
+
36
+ /**
37
+ * UsernameCorrelationStrategy class for username-based event correlation
38
+ * @extends EventEmitter
39
+ */
40
+ class UsernameCorrelationStrategy extends EventEmitter {
41
+ /**
42
+ * Create a UsernameCorrelationStrategy
43
+ *
44
+ * @param {Object} options - Strategy options
45
+ * @param {Function} [options.usernameExtractor] - Function to extract username from event
46
+ * Default: (event) => event.data?.player
47
+ * @param {boolean} [options.includeMetadata=true] - Include session metadata (start/end times)
48
+ * @param {boolean} [options.autoCleanup=true] - Auto-remove inactive sessions
49
+ */
50
+ constructor(options = {}) {
51
+ super();
52
+
53
+ /**
54
+ * Function to extract username from event
55
+ * @private
56
+ * @type {Function}
57
+ */
58
+ this._usernameExtractor = options.usernameExtractor || ((event) => event.data?.player);
59
+
60
+ /**
61
+ * Whether to include session metadata
62
+ * @private
63
+ * @type {boolean}
64
+ */
65
+ this._includeMetadata = options.includeMetadata !== false;
66
+
67
+ /**
68
+ * Whether to auto-remove inactive sessions
69
+ * @private
70
+ * @type {boolean}
71
+ */
72
+ this._autoCleanup = options.autoCleanup !== false;
73
+
74
+ /**
75
+ * Map of active player sessions
76
+ * @private
77
+ * @type {Map<string, Object>}
78
+ */
79
+ this._sessions = new Map();
80
+ }
81
+
82
+ /**
83
+ * Correlate an event by username
84
+ *
85
+ * @param {Object} event - Parsed event object
86
+ * @returns {Object|null} - Session object with username, events, session metadata, or null if no username
87
+ */
88
+ correlate(event) {
89
+ if (!event) {
90
+ return null;
91
+ }
92
+
93
+ const username = this._usernameExtractor(event);
94
+ if (!username) {
95
+ return null;
96
+ }
97
+
98
+ const now = Date.now();
99
+
100
+ if (!this._sessions.has(username)) {
101
+ this._sessions.set(username, {
102
+ username,
103
+ events: [],
104
+ sessionStart: this._includeMetadata ? now : undefined,
105
+ sessionEnd: undefined,
106
+ isActive: true
107
+ });
108
+ }
109
+
110
+ const session = this._sessions.get(username);
111
+ session.events.push(event);
112
+
113
+ // Mark session as inactive on leave event
114
+ if (event.type === 'entity.leave') {
115
+ session.isActive = false;
116
+ if (this._includeMetadata) {
117
+ session.sessionEnd = now;
118
+ }
119
+
120
+ // Auto-cleanup inactive sessions if enabled
121
+ if (this._autoCleanup) {
122
+ this._sessions.delete(username);
123
+ }
124
+ }
125
+
126
+ // Emit session update event
127
+ this.emit('session', session);
128
+
129
+ return session;
130
+ }
131
+
132
+ /**
133
+ * Get all active sessions
134
+ *
135
+ * @returns {Array<Object>} - Array of session objects
136
+ */
137
+ getActiveCorrelations() {
138
+ return Array.from(this._sessions.values());
139
+ }
140
+
141
+ /**
142
+ * Get session by username
143
+ *
144
+ * @param {string} username - Username to look up
145
+ * @returns {Object|undefined} - Session object or undefined
146
+ */
147
+ getSession(username) {
148
+ return this._sessions.get(username);
149
+ }
150
+
151
+ /**
152
+ * Check if a player has an active session
153
+ *
154
+ * @param {string} username - Username to check
155
+ * @returns {boolean} - True if player has an active session
156
+ */
157
+ hasActiveSession(username) {
158
+ const session = this._sessions.get(username);
159
+ return !!(session && session.isActive);
160
+ }
161
+
162
+ /**
163
+ * Get all currently online players
164
+ *
165
+ * @returns {Array<string>} - Array of usernames with active sessions
166
+ */
167
+ getOnlinePlayers() {
168
+ return Array.from(this._sessions.values())
169
+ .filter(session => session.isActive)
170
+ .map(session => session.username);
171
+ }
172
+
173
+ /**
174
+ * Reset all session state
175
+ *
176
+ * @returns {void}
177
+ */
178
+ reset() {
179
+ this._sessions.clear();
180
+ this.emit('reset');
181
+ }
182
+
183
+ /**
184
+ * End a specific session manually
185
+ *
186
+ * @param {string} username - Username to end session for
187
+ * @returns {boolean} - True if session was ended, false if not found
188
+ */
189
+ endSession(username) {
190
+ const session = this._sessions.get(username);
191
+ if (!session) {
192
+ return false;
193
+ }
194
+
195
+ session.isActive = false;
196
+ if (this._includeMetadata) {
197
+ session.sessionEnd = Date.now();
198
+ }
199
+
200
+ // Auto-cleanup inactive sessions if enabled
201
+ if (this._autoCleanup) {
202
+ this._sessions.delete(username);
203
+ }
204
+
205
+ this.emit('sessionEnd', session);
206
+ return true;
207
+ }
208
+
209
+ /**
210
+ * Get session statistics
211
+ *
212
+ * @returns {Object} - Statistics object with total, active, inactive counts
213
+ */
214
+ getStatistics() {
215
+ const sessions = Array.from(this._sessions.values());
216
+ return {
217
+ total: sessions.length,
218
+ active: sessions.filter(s => s.isActive).length,
219
+ inactive: sessions.filter(s => !s.isActive).length
220
+ };
221
+ }
222
+
223
+ /**
224
+ * Get the number of active sessions
225
+ *
226
+ * @type {number}
227
+ */
228
+ get size() {
229
+ return this._sessions.size;
230
+ }
231
+ }
232
+
233
+ module.exports = { UsernameCorrelationStrategy };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Correlation Strategies
3
+ *
4
+ * Concrete implementations of CorrelationStrategy for various correlation patterns.
5
+ */
6
+
7
+ const { TagCorrelationStrategy } = require('./TagCorrelationStrategy.js');
8
+ const { UsernameCorrelationStrategy } = require('./UsernameCorrelationStrategy.js');
9
+
10
+ module.exports = {
11
+ TagCorrelationStrategy,
12
+ UsernameCorrelationStrategy
13
+ };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Log Monitoring Module
3
+ *
4
+ * Provides continuous log monitoring with event processing and correlation.
5
+ */
6
+
7
+ const { CircularBuffer } = require('./CircularBuffer.js');
8
+ const { LogMonitor } = require('./LogMonitor.js');
9
+ const { TagCorrelationStrategy, UsernameCorrelationStrategy } = require('./correlations/index.js');
10
+
11
+ module.exports = {
12
+ CircularBuffer,
13
+ LogMonitor,
14
+ TagCorrelationStrategy,
15
+ UsernameCorrelationStrategy
16
+ };