@gotza02/sequential-thinking 10000.1.0 → 10000.1.2

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.
@@ -1,132 +1,77 @@
1
1
  /**
2
2
  * REALTIME DATA MANAGER
3
- * WebSocket/SSE based real-time data streaming with fallback polling
3
+ * Polling-based real-time data streaming
4
4
  */
5
5
  import { EventEmitter } from 'events';
6
6
  import { CacheService } from './cache.js';
7
- import { logger } from '../../../utils.js';
8
7
  import { REALTIME_CONFIG, CACHE_CONFIG } from './constants.js';
8
+ // Simple logger fallback
9
+ const logger = {
10
+ info: (...args) => console.error('[INFO]', ...args),
11
+ warn: (...args) => console.warn('[WARN]', ...args),
12
+ error: (...args) => console.error('[ERROR]', ...args),
13
+ debug: (...args) => { }
14
+ };
9
15
  export class RealtimeDataManager extends EventEmitter {
10
16
  cache;
11
- wsConnections = new Map();
12
17
  pollingIntervals = new Map();
13
- reconnectAttempts = new Map();
14
18
  isRunning = false;
15
19
  constructor() {
16
20
  super();
17
21
  this.cache = new CacheService();
18
22
  this.setMaxListeners(100);
19
23
  }
20
- /**
21
- * Start the realtime manager
22
- */
23
24
  async start() {
24
25
  if (this.isRunning)
25
26
  return;
26
27
  this.isRunning = true;
27
28
  logger.info('[RealtimeManager] Started');
28
- // Start polling for live data
29
29
  this.startLiveScoresPolling();
30
30
  this.startOddsPolling();
31
31
  }
32
- /**
33
- * Stop the realtime manager
34
- */
35
32
  stop() {
36
33
  this.isRunning = false;
37
- // Close all WebSocket connections
38
- for (const [matchId, ws] of this.wsConnections.entries()) {
39
- ws.close();
40
- }
41
- this.wsConnections.clear();
42
- // Clear all polling intervals
43
34
  for (const [key, interval] of this.pollingIntervals.entries()) {
44
35
  clearInterval(interval);
45
36
  }
46
37
  this.pollingIntervals.clear();
47
38
  logger.info('[RealtimeManager] Stopped');
48
39
  }
49
- /**
50
- * Subscribe to a specific match's events
51
- */
52
40
  subscribeToMatch(matchId, callback) {
53
41
  const eventName = `match:${matchId}`;
54
42
  this.on(eventName, callback);
55
- // Try to establish WebSocket connection if available
56
- this.connectToMatchStream(matchId);
57
- // Return unsubscribe function
43
+ this.startMatchEventsPolling(matchId);
58
44
  return () => {
59
45
  this.off(eventName, callback);
60
46
  this.unsubscribeFromMatch(matchId);
61
47
  };
62
48
  }
63
- /**
64
- * Subscribe to odds changes for a match
65
- */
66
49
  subscribeToOdds(matchId, callback) {
67
50
  const eventName = `odds:${matchId}`;
68
51
  this.on(eventName, callback);
69
- return () => {
70
- this.off(eventName, callback);
71
- };
52
+ return () => this.off(eventName, callback);
72
53
  }
73
- /**
74
- * Subscribe to all live events
75
- */
76
54
  subscribeToAllEvents(callback) {
77
55
  this.on('event', callback);
78
56
  return () => this.off('event', callback);
79
57
  }
80
- /**
81
- * Process and broadcast an event
82
- */
83
58
  processEvent(event) {
84
- // Update cache
85
59
  this.updateCache(event);
86
- // Emit to specific match listeners
87
60
  this.emit(`match:${event.matchId}`, event);
88
- // Emit to odds listeners if it's an odds change
89
61
  if (event.type === 'odds_change') {
90
62
  this.emit(`odds:${event.matchId}`, event);
91
63
  }
92
- // Emit to global listeners
93
64
  this.emit('event', event);
94
- // Log event
95
- logger.debug(`[Realtime] Event: ${event.type} | Match: ${event.matchId} | Min: ${event.minute}`);
96
65
  }
97
- /**
98
- * Get current live matches
99
- */
100
66
  getLiveMatches() {
101
67
  const cached = this.cache.get('live:all');
102
68
  return cached || [];
103
69
  }
104
- /**
105
- * Get match events history
106
- */
107
70
  getMatchEvents(matchId) {
108
71
  const cached = this.cache.get(`events:${matchId}`);
109
72
  return cached || [];
110
73
  }
111
- /**
112
- * Connect to match stream (WebSocket or polling)
113
- */
114
- async connectToMatchStream(matchId) {
115
- // For now, use polling fallback
116
- // In production, this would try WebSocket first
117
- this.startMatchEventsPolling(matchId);
118
- }
119
- /**
120
- * Unsubscribe from a match
121
- */
122
74
  unsubscribeFromMatch(matchId) {
123
- // Close WebSocket if exists
124
- const ws = this.wsConnections.get(matchId);
125
- if (ws) {
126
- ws.close();
127
- this.wsConnections.delete(matchId);
128
- }
129
- // Clear polling if no more listeners
130
75
  const listenerCount = this.listenerCount(`match:${matchId}`);
131
76
  if (listenerCount === 0) {
132
77
  const interval = this.pollingIntervals.get(`events:${matchId}`);
@@ -136,22 +81,14 @@ export class RealtimeDataManager extends EventEmitter {
136
81
  }
137
82
  }
138
83
  }
139
- /**
140
- * Start polling for live scores
141
- */
142
84
  startLiveScoresPolling() {
143
85
  const interval = setInterval(async () => {
144
86
  if (!this.isRunning)
145
87
  return;
146
88
  try {
147
- // Fetch live scores from API
148
- // This would call your API provider
149
89
  const liveScores = await this.fetchLiveScores();
150
- // Update cache
151
90
  this.cache.set('live:all', liveScores, CACHE_CONFIG.TTL.LIVE_SCORES);
152
- // Emit update
153
91
  this.emit('live_scores', liveScores);
154
- // Check for score changes and emit events
155
92
  this.detectScoreChanges(liveScores);
156
93
  }
157
94
  catch (error) {
@@ -160,9 +97,6 @@ export class RealtimeDataManager extends EventEmitter {
160
97
  }, REALTIME_CONFIG.POLLING_INTERVALS.LIVE_SCORES);
161
98
  this.pollingIntervals.set('live_scores', interval);
162
99
  }
163
- /**
164
- * Start polling for odds
165
- */
166
100
  startOddsPolling() {
167
101
  const interval = setInterval(async () => {
168
102
  if (!this.isRunning)
@@ -174,7 +108,6 @@ export class RealtimeDataManager extends EventEmitter {
174
108
  if (odds) {
175
109
  const cachedOdds = this.cache.get(`odds:${match.id}`);
176
110
  if (cachedOdds) {
177
- // Detect changes
178
111
  this.detectOddsChanges(match.id, cachedOdds, odds);
179
112
  }
180
113
  this.cache.set(`odds:${match.id}`, odds, CACHE_CONFIG.TTL.ODDS);
@@ -187,9 +120,6 @@ export class RealtimeDataManager extends EventEmitter {
187
120
  }, REALTIME_CONFIG.POLLING_INTERVALS.ODDS);
188
121
  this.pollingIntervals.set('odds', interval);
189
122
  }
190
- /**
191
- * Start polling for specific match events
192
- */
193
123
  startMatchEventsPolling(matchId) {
194
124
  if (this.pollingIntervals.has(`events:${matchId}`))
195
125
  return;
@@ -199,7 +129,6 @@ export class RealtimeDataManager extends EventEmitter {
199
129
  try {
200
130
  const events = await this.fetchMatchEvents(matchId);
201
131
  const cachedEvents = this.getMatchEvents(matchId);
202
- // Find new events
203
132
  const newEvents = events.filter(e => !cachedEvents.some(ce => ce.timestamp === e.timestamp && ce.type === e.type));
204
133
  for (const event of newEvents) {
205
134
  this.processEvent(event);
@@ -211,49 +140,32 @@ export class RealtimeDataManager extends EventEmitter {
211
140
  }, REALTIME_CONFIG.POLLING_INTERVALS.MATCH_EVENTS);
212
141
  this.pollingIntervals.set(`events:${matchId}`, interval);
213
142
  }
214
- /**
215
- * Detect score changes and emit goal events
216
- */
217
143
  detectScoreChanges(matches) {
218
144
  for (const match of matches) {
219
145
  const cachedMatch = this.cache.get(`match:${match.id}`);
220
146
  if (cachedMatch && cachedMatch.score && match.score) {
221
- // Check for home team goal
222
147
  if (match.score.home > cachedMatch.score.home) {
223
148
  this.processEvent({
224
149
  type: 'goal',
225
150
  matchId: match.id,
226
151
  timestamp: Date.now(),
227
152
  minute: match.minute,
228
- data: {
229
- team: 'home',
230
- score: match.score,
231
- previousScore: cachedMatch.score,
232
- },
153
+ data: { team: 'home', score: match.score, previousScore: cachedMatch.score },
233
154
  });
234
155
  }
235
- // Check for away team goal
236
156
  if (match.score.away > cachedMatch.score.away) {
237
157
  this.processEvent({
238
158
  type: 'goal',
239
159
  matchId: match.id,
240
160
  timestamp: Date.now(),
241
161
  minute: match.minute,
242
- data: {
243
- team: 'away',
244
- score: match.score,
245
- previousScore: cachedMatch.score,
246
- },
162
+ data: { team: 'away', score: match.score, previousScore: cachedMatch.score },
247
163
  });
248
164
  }
249
165
  }
250
- // Update match cache
251
166
  this.cache.set(`match:${match.id}`, match, CACHE_CONFIG.TTL.MATCH_DETAILS);
252
167
  }
253
168
  }
254
- /**
255
- * Detect odds changes and emit events
256
- */
257
169
  detectOddsChanges(matchId, oldOdds, newOdds) {
258
170
  const markets = [
259
171
  { key: 'homeWin', name: 'Home Win' },
@@ -265,7 +177,6 @@ export class RealtimeDataManager extends EventEmitter {
265
177
  const newValue = newOdds[market.key];
266
178
  if (oldValue && newValue && oldValue !== newValue) {
267
179
  const change = ((newValue - oldValue) / oldValue) * 100;
268
- // Only emit if change is significant (>5%)
269
180
  if (Math.abs(change) > 5) {
270
181
  this.processEvent({
271
182
  type: 'odds_change',
@@ -285,47 +196,27 @@ export class RealtimeDataManager extends EventEmitter {
285
196
  }
286
197
  }
287
198
  }
288
- /**
289
- * Update cache with event
290
- */
291
199
  updateCache(event) {
292
- // Invalidate related cache entries
293
200
  this.cache.invalidatePattern(`match:${event.matchId}*`);
294
- // Store event in history
295
201
  const eventsKey = `events:${event.matchId}`;
296
202
  const existingEvents = this.cache.get(eventsKey) || [];
297
203
  existingEvents.push(event);
298
- // Keep only last 100 events
299
- if (existingEvents.length > 100) {
204
+ if (existingEvents.length > 100)
300
205
  existingEvents.shift();
301
- }
302
206
  this.cache.set(eventsKey, existingEvents, CACHE_CONFIG.TTL.LIVE_EVENTS);
303
207
  }
304
- // Placeholder methods - implement with actual API calls
305
- async fetchLiveScores() {
306
- // Implement with your API provider
307
- return [];
308
- }
309
- async fetchOdds(matchId) {
310
- // Implement with your API provider
311
- return null;
312
- }
313
- async fetchMatchEvents(matchId) {
314
- // Implement with your API provider
315
- return [];
316
- }
208
+ async fetchLiveScores() { return []; }
209
+ async fetchOdds(matchId) { return null; }
210
+ async fetchMatchEvents(matchId) { return []; }
317
211
  }
318
- // Singleton instance
319
212
  let globalRealtimeManager = null;
320
213
  export function getRealtimeManager() {
321
- if (!globalRealtimeManager) {
214
+ if (!globalRealtimeManager)
322
215
  globalRealtimeManager = new RealtimeDataManager();
323
- }
324
216
  return globalRealtimeManager;
325
217
  }
326
218
  export function resetRealtimeManager() {
327
- if (globalRealtimeManager) {
219
+ if (globalRealtimeManager)
328
220
  globalRealtimeManager.stop();
329
- }
330
221
  globalRealtimeManager = null;
331
222
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gotza02/sequential-thinking",
3
- "version": "10000.1.0",
3
+ "version": "10000.1.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },