@djangocfg/centrifugo 1.0.3 → 1.0.4
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 +534 -83
- package/package.json +5 -5
- package/src/components/CentrifugoMonitor/CentrifugoMonitor.tsx +137 -0
- package/src/components/CentrifugoMonitor/CentrifugoMonitorDialog.tsx +64 -0
- package/src/components/CentrifugoMonitor/CentrifugoMonitorFAB.tsx +81 -0
- package/src/components/CentrifugoMonitor/CentrifugoMonitorWidget.tsx +74 -0
- package/src/components/CentrifugoMonitor/index.ts +14 -0
- package/src/components/ConnectionStatus/ConnectionStatus.tsx +192 -0
- package/src/components/ConnectionStatus/ConnectionStatusCard.tsx +56 -0
- package/src/components/ConnectionStatus/index.ts +9 -0
- package/src/components/MessagesFeed/MessageFilters.tsx +163 -0
- package/src/components/MessagesFeed/MessagesFeed.tsx +383 -0
- package/src/components/MessagesFeed/index.ts +9 -0
- package/src/components/MessagesFeed/types.ts +31 -0
- package/src/components/SubscriptionsList/SubscriptionsList.tsx +179 -0
- package/src/components/SubscriptionsList/index.ts +7 -0
- package/src/components/index.ts +18 -0
- package/src/core/client/CentrifugoRPCClient.ts +212 -15
- package/src/core/logger/createLogger.ts +26 -3
- package/src/hooks/index.ts +3 -0
- package/src/hooks/useRPC.ts +149 -0
- package/src/hooks/useSubscription.ts +44 -10
- package/src/index.ts +3 -4
- package/src/providers/CentrifugoProvider/CentrifugoProvider.tsx +3 -20
package/README.md
CHANGED
|
@@ -1,41 +1,57 @@
|
|
|
1
1
|
# @djangocfg/centrifugo
|
|
2
2
|
|
|
3
|
-
Professional Centrifugo WebSocket client with React integration and comprehensive
|
|
3
|
+
Professional Centrifugo WebSocket client with React integration, composable UI components, and comprehensive monitoring tools.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- 🔌 **Robust WebSocket Connection** - Auto-reconnect, error handling, and connection state management
|
|
8
|
-
-
|
|
9
|
-
-
|
|
8
|
+
- 🔄 **RPC Pattern Support** - Request-response via correlation ID for synchronous-like communication
|
|
9
|
+
- 📊 **Advanced Logging System** - Circular buffer with dual output (consola + in-memory accumulation)
|
|
10
|
+
- 🧩 **Composable UI Components** - Flexible, reusable components for any use case
|
|
11
|
+
- 🐛 **Monitoring Tools** - Real-time connection status, message feed, and subscriptions list
|
|
10
12
|
- ⚛️ **React Integration** - Context providers and hooks for seamless integration
|
|
11
|
-
- 🎯 **Type-Safe** - Full TypeScript support with
|
|
13
|
+
- 🎯 **Type-Safe** - Full TypeScript support with proper Centrifuge types
|
|
12
14
|
- 🏗️ **Platform-Agnostic Core** - Core modules can be used without React
|
|
13
|
-
- 🎨 **Beautiful UI
|
|
15
|
+
- 🎨 **Beautiful UI** - Pre-built components using shadcn/ui
|
|
16
|
+
- 📅 **Moment.js Integration** - Consistent UTC time handling throughout
|
|
14
17
|
|
|
15
18
|
## Architecture
|
|
16
19
|
|
|
17
20
|
```
|
|
18
21
|
src/
|
|
19
|
-
├── core/
|
|
20
|
-
│ ├── client/
|
|
21
|
-
│ ├── logger/
|
|
22
|
-
│
|
|
23
|
-
|
|
24
|
-
│
|
|
22
|
+
├── core/ # Platform-agnostic (no React dependencies)
|
|
23
|
+
│ ├── client/ # CentrifugoRPCClient - WebSocket client
|
|
24
|
+
│ ├── logger/ # Logging system with circular buffer
|
|
25
|
+
│ │ ├── createLogger.ts # Logger factory (supports string prefix)
|
|
26
|
+
│ │ └── LogsStore.ts # In-memory logs accumulation
|
|
27
|
+
│ └── types/ # TypeScript type definitions
|
|
28
|
+
├── providers/ # React Context providers
|
|
29
|
+
│ ├── CentrifugoProvider/ # Main connection provider (no auto-FAB)
|
|
25
30
|
│ └── LogsProvider/ # Logs accumulation provider
|
|
26
|
-
├── hooks/
|
|
27
|
-
│
|
|
28
|
-
└──
|
|
29
|
-
|
|
30
|
-
├──
|
|
31
|
-
├──
|
|
32
|
-
└──
|
|
31
|
+
├── hooks/ # React hooks
|
|
32
|
+
│ ├── useSubscription.ts # Channel subscription hook
|
|
33
|
+
│ └── useRPC.ts # RPC request-response hook
|
|
34
|
+
└── components/ # Composable UI components
|
|
35
|
+
├── ConnectionStatus/ # Connection status display
|
|
36
|
+
│ ├── ConnectionStatus.tsx # Badge/inline/detailed variants
|
|
37
|
+
│ └── ConnectionStatusCard.tsx # Card wrapper for dashboards
|
|
38
|
+
├── MessagesFeed/ # Real-time message feed
|
|
39
|
+
│ ├── MessagesFeed.tsx # Main feed component
|
|
40
|
+
│ ├── MessageFilters.tsx # Filtering controls
|
|
41
|
+
│ └── types.ts # Message types
|
|
42
|
+
├── SubscriptionsList/ # Active subscriptions list
|
|
43
|
+
│ └── SubscriptionsList.tsx # List with controls
|
|
44
|
+
└── CentrifugoMonitor/ # Main monitoring component
|
|
45
|
+
├── CentrifugoMonitor.tsx # Composable monitor
|
|
46
|
+
├── CentrifugoMonitorDialog.tsx # Modal variant
|
|
47
|
+
├── CentrifugoMonitorFAB.tsx # FAB variant (manual)
|
|
48
|
+
└── CentrifugoMonitorWidget.tsx # Dashboard widget
|
|
33
49
|
```
|
|
34
50
|
|
|
35
51
|
## Installation
|
|
36
52
|
|
|
37
53
|
```bash
|
|
38
|
-
pnpm add @djangocfg/centrifugo
|
|
54
|
+
pnpm add @djangocfg/centrifugo moment
|
|
39
55
|
```
|
|
40
56
|
|
|
41
57
|
## Quick Start
|
|
@@ -43,7 +59,7 @@ pnpm add @djangocfg/centrifugo
|
|
|
43
59
|
### 1. Wrap your app with CentrifugoProvider
|
|
44
60
|
|
|
45
61
|
```tsx
|
|
46
|
-
import { CentrifugoProvider
|
|
62
|
+
import { CentrifugoProvider } from '@djangocfg/centrifugo';
|
|
47
63
|
|
|
48
64
|
function App() {
|
|
49
65
|
return (
|
|
@@ -52,15 +68,42 @@ function App() {
|
|
|
52
68
|
autoConnect={true}
|
|
53
69
|
>
|
|
54
70
|
<YourApp />
|
|
71
|
+
</CentrifugoProvider>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 2. Add Monitoring FAB (Optional)
|
|
77
|
+
|
|
78
|
+
The FAB is **not** automatically included. You control when and where to show it:
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import { CentrifugoProvider, CentrifugoMonitorFAB } from '@djangocfg/centrifugo';
|
|
82
|
+
import { useAuth } from '@djangocfg/layouts';
|
|
83
|
+
|
|
84
|
+
function CentrifugoMonitor() {
|
|
85
|
+
const { isAdminUser } = useAuth();
|
|
86
|
+
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
87
|
+
|
|
88
|
+
// Show FAB only for admins or in development
|
|
89
|
+
if (!isDevelopment && !isAdminUser) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return <CentrifugoMonitorFAB variant="full" />;
|
|
94
|
+
}
|
|
55
95
|
|
|
56
|
-
|
|
57
|
-
|
|
96
|
+
function App() {
|
|
97
|
+
return (
|
|
98
|
+
<CentrifugoProvider enabled={true} autoConnect={true}>
|
|
99
|
+
<YourApp />
|
|
100
|
+
<CentrifugoMonitor />
|
|
58
101
|
</CentrifugoProvider>
|
|
59
102
|
);
|
|
60
103
|
}
|
|
61
104
|
```
|
|
62
105
|
|
|
63
|
-
###
|
|
106
|
+
### 3. Use the connection in your components
|
|
64
107
|
|
|
65
108
|
```tsx
|
|
66
109
|
import { useCentrifugo } from '@djangocfg/centrifugo';
|
|
@@ -78,7 +121,7 @@ function YourComponent() {
|
|
|
78
121
|
}
|
|
79
122
|
```
|
|
80
123
|
|
|
81
|
-
###
|
|
124
|
+
### 4. Subscribe to channels
|
|
82
125
|
|
|
83
126
|
```tsx
|
|
84
127
|
import { useSubscription } from '@djangocfg/centrifugo';
|
|
@@ -185,65 +228,305 @@ interface UseSubscriptionOptions<T> {
|
|
|
185
228
|
}
|
|
186
229
|
```
|
|
187
230
|
|
|
188
|
-
###
|
|
231
|
+
### useRPC()
|
|
232
|
+
|
|
233
|
+
Hook for making RPC calls using correlation ID pattern.
|
|
234
|
+
|
|
235
|
+
**What is RPC Pattern?**
|
|
189
236
|
|
|
190
|
-
|
|
237
|
+
Centrifugo is pub/sub (fire-and-forget) and doesn't support RPC natively. We implement request-response pattern using **correlation ID** to match requests with responses:
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
1. Client generates unique correlation_id
|
|
241
|
+
2. Client subscribes to personal reply channel (user#{userId})
|
|
242
|
+
3. Client publishes request with correlation_id to rpc#{method}
|
|
243
|
+
4. Backend processes and publishes response with same correlation_id
|
|
244
|
+
5. Client matches response by correlation_id and resolves Promise
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Basic Usage:**
|
|
191
248
|
|
|
192
249
|
```tsx
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
250
|
+
import { useRPC } from '@djangocfg/centrifugo';
|
|
251
|
+
|
|
252
|
+
function MyComponent() {
|
|
253
|
+
const { call, isLoading, error } = useRPC();
|
|
254
|
+
|
|
255
|
+
const handleGetStats = async () => {
|
|
256
|
+
try {
|
|
257
|
+
const result = await call('tasks.get_stats', { bot_id: '123' });
|
|
258
|
+
console.log('Stats:', result);
|
|
259
|
+
} catch (error) {
|
|
260
|
+
console.error('RPC failed:', error);
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
return (
|
|
265
|
+
<button onClick={handleGetStats} disabled={isLoading}>
|
|
266
|
+
{isLoading ? 'Loading...' : 'Get Stats'}
|
|
267
|
+
</button>
|
|
268
|
+
);
|
|
269
|
+
}
|
|
201
270
|
```
|
|
202
271
|
|
|
203
|
-
|
|
272
|
+
**With Type Safety:**
|
|
204
273
|
|
|
205
|
-
|
|
274
|
+
```tsx
|
|
275
|
+
interface GetStatsRequest {
|
|
276
|
+
bot_id: string;
|
|
277
|
+
}
|
|
206
278
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
279
|
+
interface GetStatsResponse {
|
|
280
|
+
total_tasks: number;
|
|
281
|
+
completed: number;
|
|
282
|
+
failed: number;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const { call } = useRPC();
|
|
286
|
+
|
|
287
|
+
const result = await call<GetStatsRequest, GetStatsResponse>(
|
|
288
|
+
'tasks.get_stats',
|
|
289
|
+
{ bot_id: '123' }
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
console.log(result.total_tasks); // Type-safe!
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**With Custom Options:**
|
|
215
296
|
|
|
216
|
-
**Usage:**
|
|
217
297
|
```tsx
|
|
218
|
-
|
|
298
|
+
const { call, isLoading, error, reset } = useRPC({
|
|
299
|
+
timeout: 30000, // 30 seconds
|
|
300
|
+
onError: (error) => {
|
|
301
|
+
toast.error(`RPC failed: ${error.message}`);
|
|
302
|
+
},
|
|
303
|
+
});
|
|
219
304
|
|
|
220
|
-
|
|
305
|
+
// Reset state
|
|
306
|
+
reset();
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
**Options:**
|
|
310
|
+
```typescript
|
|
311
|
+
interface UseRPCOptions {
|
|
312
|
+
timeout?: number; // Default: 10000ms
|
|
313
|
+
replyChannel?: string; // Default: user#{userId}
|
|
314
|
+
onError?: (error: Error) => void;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
interface UseRPCResult {
|
|
318
|
+
call: <TRequest, TResponse>(
|
|
319
|
+
method: string,
|
|
320
|
+
params: TRequest,
|
|
321
|
+
options?: UseRPCOptions
|
|
322
|
+
) => Promise<TResponse>;
|
|
323
|
+
isLoading: boolean;
|
|
324
|
+
error: Error | null;
|
|
325
|
+
reset: () => void;
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**Backend Implementation:**
|
|
330
|
+
|
|
331
|
+
The backend should subscribe to `rpc#{method}` channels and publish responses:
|
|
332
|
+
|
|
333
|
+
```python
|
|
334
|
+
# Django backend example
|
|
335
|
+
from django_cfg.apps.integrations.centrifugo import get_centrifugo_publisher
|
|
336
|
+
|
|
337
|
+
publisher = get_centrifugo_publisher()
|
|
338
|
+
|
|
339
|
+
# Listen to RPC requests (via Centrifugo subscription)
|
|
340
|
+
async def handle_rpc_request(data):
|
|
341
|
+
correlation_id = data['correlation_id']
|
|
342
|
+
method = data['method']
|
|
343
|
+
params = data['params']
|
|
344
|
+
reply_to = data['reply_to']
|
|
345
|
+
|
|
346
|
+
try:
|
|
347
|
+
# Process request
|
|
348
|
+
result = await process_task_stats(params['bot_id'])
|
|
349
|
+
|
|
350
|
+
# Send response
|
|
351
|
+
await publisher.publish(
|
|
352
|
+
channel=reply_to,
|
|
353
|
+
data={
|
|
354
|
+
'correlation_id': correlation_id,
|
|
355
|
+
'result': result,
|
|
356
|
+
}
|
|
357
|
+
)
|
|
358
|
+
except Exception as e:
|
|
359
|
+
# Send error response
|
|
360
|
+
await publisher.publish(
|
|
361
|
+
channel=reply_to,
|
|
362
|
+
data={
|
|
363
|
+
'correlation_id': correlation_id,
|
|
364
|
+
'error': {'message': str(e)},
|
|
365
|
+
}
|
|
366
|
+
)
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
## UI Components
|
|
370
|
+
|
|
371
|
+
All components are composable and can be used independently or together.
|
|
372
|
+
|
|
373
|
+
### ConnectionStatus
|
|
374
|
+
|
|
375
|
+
Display connection status in various formats.
|
|
376
|
+
|
|
377
|
+
**Variants:**
|
|
378
|
+
- `badge` - Compact badge with status indicator
|
|
379
|
+
- `inline` - Inline text with icon
|
|
380
|
+
- `detailed` - Detailed view with uptime and subscriptions
|
|
381
|
+
|
|
382
|
+
```tsx
|
|
383
|
+
import { ConnectionStatus } from '@djangocfg/centrifugo';
|
|
384
|
+
|
|
385
|
+
// Badge variant
|
|
386
|
+
<ConnectionStatus variant="badge" />
|
|
387
|
+
|
|
388
|
+
// Detailed variant with uptime and subscriptions
|
|
389
|
+
<ConnectionStatus
|
|
390
|
+
variant="detailed"
|
|
391
|
+
showUptime={true}
|
|
392
|
+
showSubscriptions={true}
|
|
393
|
+
/>
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
**ConnectionStatusCard** - Card wrapper for dashboards:
|
|
397
|
+
|
|
398
|
+
```tsx
|
|
399
|
+
import { ConnectionStatusCard } from '@djangocfg/centrifugo';
|
|
400
|
+
|
|
401
|
+
<ConnectionStatusCard />
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### MessagesFeed
|
|
405
|
+
|
|
406
|
+
Real-time feed of Centrifugo messages with filtering and export.
|
|
407
|
+
|
|
408
|
+
```tsx
|
|
409
|
+
import { MessagesFeed } from '@djangocfg/centrifugo';
|
|
410
|
+
|
|
411
|
+
<MessagesFeed
|
|
412
|
+
maxMessages={100}
|
|
413
|
+
showFilters={true}
|
|
414
|
+
showControls={true}
|
|
415
|
+
autoScroll={true}
|
|
416
|
+
onMessageClick={(msg) => console.log(msg)}
|
|
417
|
+
/>
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Features:**
|
|
421
|
+
- Filter by type, level, channel
|
|
422
|
+
- Search functionality
|
|
423
|
+
- Pause/play auto-scroll
|
|
424
|
+
- Download messages as JSON
|
|
425
|
+
- Clear messages
|
|
426
|
+
|
|
427
|
+
### SubscriptionsList
|
|
428
|
+
|
|
429
|
+
List of active subscriptions with management controls.
|
|
430
|
+
|
|
431
|
+
```tsx
|
|
432
|
+
import { SubscriptionsList } from '@djangocfg/centrifugo';
|
|
433
|
+
|
|
434
|
+
<SubscriptionsList
|
|
435
|
+
showControls={true}
|
|
436
|
+
onSubscriptionClick={(channel) => console.log(channel)}
|
|
437
|
+
/>
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
**Features:**
|
|
441
|
+
- Real-time subscription updates
|
|
442
|
+
- Unsubscribe from channels
|
|
443
|
+
- Click to view channel details
|
|
444
|
+
|
|
445
|
+
### CentrifugoMonitor
|
|
446
|
+
|
|
447
|
+
Main monitoring component with multiple variants.
|
|
448
|
+
|
|
449
|
+
**Basic Usage:**
|
|
450
|
+
|
|
451
|
+
```tsx
|
|
452
|
+
import { CentrifugoMonitor } from '@djangocfg/centrifugo';
|
|
453
|
+
|
|
454
|
+
// Embedded in a page
|
|
455
|
+
<CentrifugoMonitor defaultTab="messages" />
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
**Dialog Variant:**
|
|
459
|
+
|
|
460
|
+
```tsx
|
|
461
|
+
import { CentrifugoMonitorDialog } from '@djangocfg/centrifugo';
|
|
462
|
+
|
|
463
|
+
function MyComponent() {
|
|
464
|
+
const [open, setOpen] = useState(false);
|
|
465
|
+
|
|
221
466
|
return (
|
|
222
467
|
<>
|
|
223
|
-
<
|
|
224
|
-
<
|
|
468
|
+
<button onClick={() => setOpen(true)}>Open Monitor</button>
|
|
469
|
+
<CentrifugoMonitorDialog
|
|
470
|
+
open={open}
|
|
471
|
+
onOpenChange={setOpen}
|
|
472
|
+
defaultTab="status"
|
|
473
|
+
/>
|
|
225
474
|
</>
|
|
226
475
|
);
|
|
227
476
|
}
|
|
228
477
|
```
|
|
229
478
|
|
|
230
|
-
|
|
479
|
+
**FAB Variant:**
|
|
480
|
+
|
|
481
|
+
```tsx
|
|
482
|
+
import { CentrifugoMonitorFAB } from '@djangocfg/centrifugo';
|
|
483
|
+
|
|
484
|
+
// Full variant with all tabs
|
|
485
|
+
<CentrifugoMonitorFAB variant="full" />
|
|
486
|
+
|
|
487
|
+
// Compact variant (status only)
|
|
488
|
+
<CentrifugoMonitorFAB variant="compact" />
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
**Widget Variant (for Dashboards):**
|
|
492
|
+
|
|
493
|
+
```tsx
|
|
494
|
+
import { CentrifugoMonitorWidget } from '@djangocfg/centrifugo';
|
|
495
|
+
|
|
496
|
+
<CentrifugoMonitorWidget defaultTab="subscriptions" />
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
**Props:**
|
|
500
|
+
```typescript
|
|
501
|
+
interface CentrifugoMonitorProps {
|
|
502
|
+
defaultTab?: 'status' | 'messages' | 'subscriptions';
|
|
503
|
+
className?: string;
|
|
504
|
+
}
|
|
505
|
+
```
|
|
231
506
|
|
|
232
507
|
## Logging System
|
|
233
508
|
|
|
234
509
|
The package includes a sophisticated logging system with:
|
|
235
510
|
|
|
236
511
|
- **Circular Buffer** - Stores up to 500 logs (configurable)
|
|
237
|
-
- **Dual Output** -
|
|
512
|
+
- **Dual Output** - Consola (dev only) + in-memory store (always)
|
|
238
513
|
- **Structured Logs** - Timestamp, level, source, message, and optional data
|
|
239
514
|
- **Real-time Updates** - Subscribe to log changes for React updates
|
|
515
|
+
- **Prefixed Output** - Logger name appears as `[YourComponent]` in console
|
|
240
516
|
|
|
241
517
|
**Creating a Logger:**
|
|
518
|
+
|
|
242
519
|
```typescript
|
|
243
520
|
import { createLogger } from '@djangocfg/centrifugo';
|
|
244
521
|
|
|
522
|
+
// Simple usage with string prefix
|
|
523
|
+
const logger = createLogger('MyComponent');
|
|
524
|
+
|
|
525
|
+
// Advanced usage with full config
|
|
245
526
|
const logger = createLogger({
|
|
246
|
-
source: '
|
|
527
|
+
source: 'client', // 'client' | 'provider' | 'subscription' | 'system'
|
|
528
|
+
tag: 'MyComponent',
|
|
529
|
+
isDevelopment: true,
|
|
247
530
|
});
|
|
248
531
|
|
|
249
532
|
logger.debug('Debug message', { extra: 'data' });
|
|
@@ -254,6 +537,7 @@ logger.error('Error message', error);
|
|
|
254
537
|
```
|
|
255
538
|
|
|
256
539
|
**Accessing Logs:**
|
|
540
|
+
|
|
257
541
|
```typescript
|
|
258
542
|
import { getGlobalLogsStore } from '@djangocfg/centrifugo';
|
|
259
543
|
|
|
@@ -271,6 +555,39 @@ const unsubscribe = logsStore.subscribe((logs) => {
|
|
|
271
555
|
logsStore.clear();
|
|
272
556
|
```
|
|
273
557
|
|
|
558
|
+
**Using LogsProvider:**
|
|
559
|
+
|
|
560
|
+
```tsx
|
|
561
|
+
import { useLogs } from '@djangocfg/centrifugo';
|
|
562
|
+
|
|
563
|
+
function CustomLogsView() {
|
|
564
|
+
const { logs, setFilter, clearLogs } = useLogs();
|
|
565
|
+
|
|
566
|
+
return (
|
|
567
|
+
<div>
|
|
568
|
+
<button onClick={() => setFilter({ level: 'error' })}>
|
|
569
|
+
Show Errors Only
|
|
570
|
+
</button>
|
|
571
|
+
<button onClick={() => setFilter({ source: 'client' })}>
|
|
572
|
+
Show Client Logs
|
|
573
|
+
</button>
|
|
574
|
+
<button onClick={() => setFilter({ search: 'WebSocket' })}>
|
|
575
|
+
Search "WebSocket"
|
|
576
|
+
</button>
|
|
577
|
+
<button onClick={clearLogs}>
|
|
578
|
+
Clear All
|
|
579
|
+
</button>
|
|
580
|
+
|
|
581
|
+
<ul>
|
|
582
|
+
{logs.map(log => (
|
|
583
|
+
<li key={log.id}>{log.message}</li>
|
|
584
|
+
))}
|
|
585
|
+
</ul>
|
|
586
|
+
</div>
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
```
|
|
590
|
+
|
|
274
591
|
## Advanced Usage
|
|
275
592
|
|
|
276
593
|
### Using the Core Client (without React)
|
|
@@ -278,41 +595,66 @@ logsStore.clear();
|
|
|
278
595
|
```typescript
|
|
279
596
|
import { CentrifugoRPCClient, createLogger } from '@djangocfg/centrifugo';
|
|
280
597
|
|
|
281
|
-
const logger = createLogger(
|
|
598
|
+
const logger = createLogger('MyApp');
|
|
282
599
|
const client = new CentrifugoRPCClient(
|
|
283
600
|
'ws://localhost:8000/ws',
|
|
284
601
|
'your-token',
|
|
285
602
|
'user-id',
|
|
286
603
|
30000, // timeout
|
|
287
|
-
logger
|
|
604
|
+
(entry) => logger.info(entry.message, entry.data)
|
|
288
605
|
);
|
|
289
606
|
|
|
290
607
|
await client.connect();
|
|
291
|
-
|
|
608
|
+
|
|
609
|
+
// Subscribe to channel
|
|
610
|
+
const unsubscribe = client.subscribe('channel-name', (data) => {
|
|
611
|
+
console.log('Message:', data);
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
// Get native Centrifuge client for low-level access
|
|
615
|
+
const centrifuge = client.getCentrifuge();
|
|
616
|
+
centrifuge.on('connected', () => console.log('Connected'));
|
|
292
617
|
```
|
|
293
618
|
|
|
294
|
-
### Custom
|
|
619
|
+
### Custom Dashboard Integration
|
|
295
620
|
|
|
296
621
|
```tsx
|
|
297
|
-
import {
|
|
622
|
+
import {
|
|
623
|
+
ConnectionStatusCard,
|
|
624
|
+
MessagesFeed,
|
|
625
|
+
SubscriptionsList,
|
|
626
|
+
} from '@djangocfg/centrifugo';
|
|
298
627
|
|
|
299
|
-
function
|
|
300
|
-
|
|
628
|
+
function Dashboard() {
|
|
629
|
+
return (
|
|
630
|
+
<div className="grid grid-cols-3 gap-4">
|
|
631
|
+
<ConnectionStatusCard />
|
|
632
|
+
|
|
633
|
+
<div className="col-span-2">
|
|
634
|
+
<MessagesFeed
|
|
635
|
+
maxMessages={50}
|
|
636
|
+
showFilters={false}
|
|
637
|
+
/>
|
|
638
|
+
</div>
|
|
639
|
+
|
|
640
|
+
<div className="col-span-3">
|
|
641
|
+
<SubscriptionsList showControls={true} />
|
|
642
|
+
</div>
|
|
643
|
+
</div>
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
### Embedded Monitor in Page
|
|
649
|
+
|
|
650
|
+
```tsx
|
|
651
|
+
import { CentrifugoMonitor } from '@djangocfg/centrifugo';
|
|
301
652
|
|
|
653
|
+
function MonitoringPage() {
|
|
302
654
|
return (
|
|
303
|
-
<div>
|
|
304
|
-
<
|
|
305
|
-
|
|
306
|
-
</button>
|
|
307
|
-
<button onClick={() => setFilter({ source: 'client' })}>
|
|
308
|
-
Show Client Logs
|
|
309
|
-
</button>
|
|
310
|
-
<button onClick={() => setFilter({ search: 'WebSocket' })}>
|
|
311
|
-
Search "WebSocket"
|
|
312
|
-
</button>
|
|
313
|
-
<button onClick={() => setFilter({})}>
|
|
314
|
-
Clear Filters
|
|
315
|
-
</button>
|
|
655
|
+
<div className="container mx-auto p-6">
|
|
656
|
+
<h1>WebSocket Monitoring</h1>
|
|
657
|
+
<CentrifugoMonitor defaultTab="messages" />
|
|
316
658
|
</div>
|
|
317
659
|
);
|
|
318
660
|
}
|
|
@@ -347,37 +689,144 @@ import type {
|
|
|
347
689
|
// Hooks
|
|
348
690
|
UseSubscriptionOptions,
|
|
349
691
|
UseSubscriptionResult,
|
|
692
|
+
|
|
693
|
+
// Components
|
|
694
|
+
ConnectionStatusProps,
|
|
695
|
+
MessagesFeedProps,
|
|
696
|
+
SubscriptionsListProps,
|
|
697
|
+
CentrifugoMonitorProps,
|
|
350
698
|
} from '@djangocfg/centrifugo';
|
|
351
699
|
```
|
|
352
700
|
|
|
353
|
-
|
|
701
|
+
**Proper Centrifuge Types:**
|
|
354
702
|
|
|
355
|
-
|
|
703
|
+
The package now uses proper types from the `centrifuge` library:
|
|
356
704
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
705
|
+
```typescript
|
|
706
|
+
import type { Subscription, SubscriptionState } from 'centrifuge';
|
|
707
|
+
|
|
708
|
+
// No more 'as any' - fully type-safe!
|
|
709
|
+
const centrifuge = client.getCentrifuge();
|
|
710
|
+
const subs = centrifuge.subscriptions();
|
|
711
|
+
|
|
712
|
+
for (const [channel, sub] of Object.entries(subs)) {
|
|
713
|
+
console.log(channel, sub.state); // SubscriptionState type
|
|
714
|
+
}
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
## Best Practices
|
|
718
|
+
|
|
719
|
+
### 1. Logger Usage
|
|
720
|
+
|
|
721
|
+
Always use the logger instead of `console`:
|
|
722
|
+
|
|
723
|
+
```typescript
|
|
724
|
+
// ❌ Bad
|
|
725
|
+
console.log('Message');
|
|
726
|
+
|
|
727
|
+
// ✅ Good
|
|
728
|
+
const logger = createLogger('MyComponent');
|
|
729
|
+
logger.info('Message');
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
### 2. Date Handling
|
|
733
|
+
|
|
734
|
+
Use `moment` with UTC for all date operations:
|
|
735
|
+
|
|
736
|
+
```typescript
|
|
737
|
+
import moment from 'moment';
|
|
738
|
+
|
|
739
|
+
// ❌ Bad
|
|
740
|
+
const now = new Date();
|
|
741
|
+
const timestamp = Date.now();
|
|
742
|
+
|
|
743
|
+
// ✅ Good
|
|
744
|
+
const now = moment.utc();
|
|
745
|
+
const timestamp = moment.utc().valueOf();
|
|
746
|
+
const formatted = moment.utc().format('YYYY-MM-DD HH:mm:ss');
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
### 3. FAB Control
|
|
750
|
+
|
|
751
|
+
Don't rely on auto-showing FAB. Control it explicitly:
|
|
752
|
+
|
|
753
|
+
```typescript
|
|
754
|
+
// ✅ Good - Developer has full control
|
|
755
|
+
function App() {
|
|
756
|
+
return (
|
|
757
|
+
<CentrifugoProvider enabled={true}>
|
|
758
|
+
<YourApp />
|
|
759
|
+
{shouldShowMonitor && <CentrifugoMonitorFAB />}
|
|
760
|
+
</CentrifugoProvider>
|
|
761
|
+
);
|
|
762
|
+
}
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
### 4. Component Composition
|
|
766
|
+
|
|
767
|
+
Use individual components for custom layouts:
|
|
768
|
+
|
|
769
|
+
```typescript
|
|
770
|
+
// ✅ Good - Compose as needed
|
|
771
|
+
<div className="monitoring-panel">
|
|
772
|
+
<ConnectionStatus variant="detailed" showUptime />
|
|
773
|
+
<MessagesFeed maxMessages={50} />
|
|
774
|
+
<SubscriptionsList />
|
|
775
|
+
</div>
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
## Migration Guide
|
|
779
|
+
|
|
780
|
+
### From Old DebugPanel
|
|
362
781
|
|
|
363
782
|
**Before:**
|
|
364
783
|
```tsx
|
|
365
|
-
import {
|
|
784
|
+
import { DebugPanel } from '@djangocfg/centrifugo';
|
|
785
|
+
|
|
786
|
+
// Auto-shown in development
|
|
787
|
+
<CentrifugoProvider>
|
|
788
|
+
<App />
|
|
789
|
+
</CentrifugoProvider>
|
|
366
790
|
```
|
|
367
791
|
|
|
368
792
|
**After:**
|
|
369
793
|
```tsx
|
|
370
|
-
import {
|
|
794
|
+
import { CentrifugoMonitorFAB } from '@djangocfg/centrifugo';
|
|
795
|
+
|
|
796
|
+
// Manual control
|
|
797
|
+
<CentrifugoProvider>
|
|
798
|
+
<App />
|
|
799
|
+
<CentrifugoMonitorFAB variant="full" />
|
|
800
|
+
</CentrifugoProvider>
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
### From date-fns to moment
|
|
804
|
+
|
|
805
|
+
**Before:**
|
|
806
|
+
```typescript
|
|
807
|
+
import { format } from 'date-fns';
|
|
808
|
+
|
|
809
|
+
const formatted = format(new Date(), 'yyyy-MM-dd HH:mm:ss');
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
**After:**
|
|
813
|
+
```typescript
|
|
814
|
+
import moment from 'moment';
|
|
815
|
+
|
|
816
|
+
const formatted = moment.utc().format('YYYY-MM-DD HH:mm:ss');
|
|
371
817
|
```
|
|
372
818
|
|
|
373
819
|
## Development
|
|
374
820
|
|
|
375
821
|
```bash
|
|
822
|
+
# Install dependencies
|
|
823
|
+
pnpm install
|
|
824
|
+
|
|
376
825
|
# Build the package
|
|
377
826
|
pnpm build
|
|
378
827
|
|
|
379
828
|
# Type check
|
|
380
|
-
pnpm
|
|
829
|
+
pnpm check
|
|
381
830
|
|
|
382
831
|
# Run in development mode
|
|
383
832
|
pnpm dev
|
|
@@ -386,9 +835,11 @@ pnpm dev
|
|
|
386
835
|
## Requirements
|
|
387
836
|
|
|
388
837
|
- React 18+
|
|
389
|
-
- `@djangocfg/ui` - UI components
|
|
838
|
+
- `@djangocfg/ui` - UI components (shadcn/ui based)
|
|
390
839
|
- `@djangocfg/layouts` - Layout components
|
|
391
840
|
- `centrifuge` - WebSocket client library
|
|
841
|
+
- `moment` - Date manipulation library
|
|
842
|
+
- `consola` - Beautiful console logging
|
|
392
843
|
|
|
393
844
|
## License
|
|
394
845
|
|