@serve.zone/dcrouter 11.23.5 → 12.1.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 (128) hide show
  1. package/dist_serve/bundle.js +1052 -939
  2. package/dist_ts/00_commitinfo_data.js +2 -2
  3. package/dist_ts/classes.cert-provision-scheduler.d.ts +6 -8
  4. package/dist_ts/classes.cert-provision-scheduler.js +37 -17
  5. package/dist_ts/classes.dcrouter.d.ts +26 -29
  6. package/dist_ts/classes.dcrouter.js +101 -91
  7. package/dist_ts/classes.storage-cert-manager.d.ts +3 -6
  8. package/dist_ts/classes.storage-cert-manager.js +35 -25
  9. package/dist_ts/config/classes.api-token-manager.d.ts +1 -3
  10. package/dist_ts/config/classes.api-token-manager.js +45 -15
  11. package/dist_ts/config/classes.route-config-manager.d.ts +1 -3
  12. package/dist_ts/config/classes.route-config-manager.js +62 -24
  13. package/dist_ts/{cache → db}/classes.cache.cleaner.d.ts +3 -3
  14. package/dist_ts/db/classes.cache.cleaner.js +130 -0
  15. package/dist_ts/{cache → db}/classes.cached.document.js +1 -1
  16. package/dist_ts/db/classes.dcrouter-db.d.ts +70 -0
  17. package/dist_ts/db/classes.dcrouter-db.js +146 -0
  18. package/dist_ts/db/documents/classes.accounting-session.doc.d.ts +32 -0
  19. package/dist_ts/db/documents/classes.accounting-session.doc.js +214 -0
  20. package/dist_ts/db/documents/classes.acme-cert.doc.d.ts +13 -0
  21. package/dist_ts/db/documents/classes.acme-cert.doc.js +109 -0
  22. package/dist_ts/db/documents/classes.api-token.doc.d.ts +18 -0
  23. package/dist_ts/db/documents/classes.api-token.doc.js +127 -0
  24. package/dist_ts/{cache → db}/documents/classes.cached.email.js +3 -3
  25. package/dist_ts/{cache → db}/documents/classes.cached.ip.reputation.js +3 -3
  26. package/dist_ts/db/documents/classes.cert-backoff.doc.d.ts +11 -0
  27. package/dist_ts/db/documents/classes.cert-backoff.doc.js +97 -0
  28. package/dist_ts/db/documents/classes.proxy-cert.doc.d.ts +12 -0
  29. package/dist_ts/db/documents/classes.proxy-cert.doc.js +103 -0
  30. package/dist_ts/db/documents/classes.remote-ingress-edge.doc.d.ts +17 -0
  31. package/dist_ts/db/documents/classes.remote-ingress-edge.doc.js +130 -0
  32. package/dist_ts/db/documents/classes.route-override.doc.d.ts +10 -0
  33. package/dist_ts/db/documents/classes.route-override.doc.js +91 -0
  34. package/dist_ts/db/documents/classes.stored-route.doc.d.ts +12 -0
  35. package/dist_ts/db/documents/classes.stored-route.doc.js +103 -0
  36. package/dist_ts/db/documents/classes.vlan-mappings.doc.d.ts +15 -0
  37. package/dist_ts/db/documents/classes.vlan-mappings.doc.js +77 -0
  38. package/dist_ts/db/documents/classes.vpn-client.doc.d.ts +26 -0
  39. package/dist_ts/db/documents/classes.vpn-client.doc.js +184 -0
  40. package/dist_ts/db/documents/classes.vpn-server-keys.doc.d.ts +10 -0
  41. package/dist_ts/db/documents/classes.vpn-server-keys.doc.js +94 -0
  42. package/dist_ts/db/documents/index.d.ts +13 -0
  43. package/dist_ts/db/documents/index.js +20 -0
  44. package/dist_ts/{cache → db}/index.d.ts +1 -1
  45. package/dist_ts/db/index.js +9 -0
  46. package/dist_ts/opsserver/handlers/certificate.handler.js +66 -66
  47. package/dist_ts/opsserver/handlers/config.handler.js +14 -15
  48. package/dist_ts/opsserver/handlers/vpn.handler.js +35 -1
  49. package/dist_ts/paths.d.ts +0 -1
  50. package/dist_ts/paths.js +1 -2
  51. package/dist_ts/radius/classes.accounting.manager.d.ts +4 -12
  52. package/dist_ts/radius/classes.accounting.manager.js +80 -93
  53. package/dist_ts/radius/classes.radius.server.d.ts +1 -3
  54. package/dist_ts/radius/classes.radius.server.js +4 -6
  55. package/dist_ts/radius/classes.vlan.manager.d.ts +3 -7
  56. package/dist_ts/radius/classes.vlan.manager.js +21 -28
  57. package/dist_ts/radius/index.d.ts +1 -1
  58. package/dist_ts/radius/index.js +1 -1
  59. package/dist_ts/remoteingress/classes.remoteingress-manager.d.ts +3 -5
  60. package/dist_ts/remoteingress/classes.remoteingress-manager.js +41 -21
  61. package/dist_ts/security/classes.ipreputationchecker.d.ts +6 -21
  62. package/dist_ts/security/classes.ipreputationchecker.js +59 -138
  63. package/dist_ts/vpn/classes.vpn-manager.d.ts +37 -22
  64. package/dist_ts/vpn/classes.vpn-manager.js +161 -51
  65. package/dist_ts_interfaces/data/vpn.d.ts +8 -0
  66. package/dist_ts_interfaces/requests/vpn.d.ts +16 -0
  67. package/dist_ts_oci_container/index.js +4 -4
  68. package/dist_ts_web/00_commitinfo_data.js +2 -2
  69. package/dist_ts_web/appstate.d.ts +16 -0
  70. package/dist_ts_web/appstate.js +17 -1
  71. package/dist_ts_web/elements/ops-view-vpn.js +155 -3
  72. package/package.json +3 -3
  73. package/readme.storage.md +55 -91
  74. package/ts/00_commitinfo_data.ts +1 -1
  75. package/ts/classes.cert-provision-scheduler.ts +35 -17
  76. package/ts/classes.dcrouter.ts +129 -125
  77. package/ts/classes.storage-cert-manager.ts +34 -22
  78. package/ts/config/classes.api-token-manager.ts +42 -11
  79. package/ts/config/classes.route-config-manager.ts +56 -21
  80. package/ts/{cache → db}/classes.cache.cleaner.ts +6 -6
  81. package/ts/db/classes.dcrouter-db.ts +179 -0
  82. package/ts/db/documents/classes.accounting-session.doc.ts +106 -0
  83. package/ts/db/documents/classes.acme-cert.doc.ts +41 -0
  84. package/ts/db/documents/classes.api-token.doc.ts +56 -0
  85. package/ts/{cache → db}/documents/classes.cached.email.ts +2 -2
  86. package/ts/{cache → db}/documents/classes.cached.ip.reputation.ts +2 -2
  87. package/ts/db/documents/classes.cert-backoff.doc.ts +35 -0
  88. package/ts/db/documents/classes.proxy-cert.doc.ts +38 -0
  89. package/ts/db/documents/classes.remote-ingress-edge.doc.ts +54 -0
  90. package/ts/db/documents/classes.route-override.doc.ts +32 -0
  91. package/ts/db/documents/classes.stored-route.doc.ts +38 -0
  92. package/ts/db/documents/classes.vlan-mappings.doc.ts +32 -0
  93. package/ts/db/documents/classes.vpn-client.doc.ts +81 -0
  94. package/ts/db/documents/classes.vpn-server-keys.doc.ts +31 -0
  95. package/ts/db/documents/index.ts +24 -0
  96. package/ts/{cache → db}/index.ts +6 -2
  97. package/ts/opsserver/handlers/certificate.handler.ts +67 -65
  98. package/ts/opsserver/handlers/config.handler.ts +13 -14
  99. package/ts/opsserver/handlers/vpn.handler.ts +37 -0
  100. package/ts/paths.ts +0 -1
  101. package/ts/radius/classes.accounting.manager.ts +81 -103
  102. package/ts/radius/classes.radius.server.ts +3 -6
  103. package/ts/radius/classes.vlan.manager.ts +20 -32
  104. package/ts/radius/index.ts +1 -1
  105. package/ts/remoteingress/classes.remoteingress-manager.ts +40 -22
  106. package/ts/security/classes.ipreputationchecker.ts +103 -196
  107. package/ts/vpn/classes.vpn-manager.ts +187 -81
  108. package/ts_web/00_commitinfo_data.ts +1 -1
  109. package/ts_web/appstate.ts +32 -0
  110. package/ts_web/elements/ops-view-vpn.ts +153 -2
  111. package/dist_ts/cache/classes.cache.cleaner.js +0 -130
  112. package/dist_ts/cache/classes.cachedb.d.ts +0 -60
  113. package/dist_ts/cache/classes.cachedb.js +0 -126
  114. package/dist_ts/cache/documents/index.d.ts +0 -2
  115. package/dist_ts/cache/documents/index.js +0 -3
  116. package/dist_ts/cache/index.js +0 -7
  117. package/dist_ts/storage/classes.storagemanager.d.ts +0 -83
  118. package/dist_ts/storage/classes.storagemanager.js +0 -348
  119. package/dist_ts/storage/index.d.ts +0 -1
  120. package/dist_ts/storage/index.js +0 -3
  121. package/ts/cache/classes.cachedb.ts +0 -155
  122. package/ts/cache/documents/index.ts +0 -2
  123. package/ts/storage/classes.storagemanager.ts +0 -404
  124. package/ts/storage/index.ts +0 -2
  125. /package/dist_ts/{cache → db}/classes.cached.document.d.ts +0 -0
  126. /package/dist_ts/{cache → db}/documents/classes.cached.email.d.ts +0 -0
  127. /package/dist_ts/{cache → db}/documents/classes.cached.ip.reputation.d.ts +0 -0
  128. /package/ts/{cache → db}/classes.cached.document.ts +0 -0
@@ -31,6 +31,14 @@ export class VpnHandler {
31
31
  createdAt: c.createdAt,
32
32
  updatedAt: c.updatedAt,
33
33
  expiresAt: c.expiresAt,
34
+ forceDestinationSmartproxy: c.forceDestinationSmartproxy ?? true,
35
+ destinationAllowList: c.destinationAllowList,
36
+ destinationBlockList: c.destinationBlockList,
37
+ useHostIp: c.useHostIp,
38
+ useDhcp: c.useDhcp,
39
+ staticIp: c.staticIp,
40
+ forceVlan: c.forceVlan,
41
+ vlanId: c.vlanId,
34
42
  }));
35
43
  return { clients };
36
44
  },
@@ -114,8 +122,21 @@ export class VpnHandler {
114
122
  clientId: dataArg.clientId,
115
123
  serverDefinedClientTags: dataArg.serverDefinedClientTags,
116
124
  description: dataArg.description,
125
+ forceDestinationSmartproxy: dataArg.forceDestinationSmartproxy,
126
+ destinationAllowList: dataArg.destinationAllowList,
127
+ destinationBlockList: dataArg.destinationBlockList,
128
+ useHostIp: dataArg.useHostIp,
129
+ useDhcp: dataArg.useDhcp,
130
+ staticIp: dataArg.staticIp,
131
+ forceVlan: dataArg.forceVlan,
132
+ vlanId: dataArg.vlanId,
117
133
  });
118
134
 
135
+ // Retrieve the persisted doc to get dcrouter-level fields
136
+ const persistedClient = manager.listClients().find(
137
+ (c) => c.clientId === bundle.entry.clientId,
138
+ );
139
+
119
140
  return {
120
141
  success: true,
121
142
  client: {
@@ -127,6 +148,14 @@ export class VpnHandler {
127
148
  createdAt: Date.now(),
128
149
  updatedAt: Date.now(),
129
150
  expiresAt: bundle.entry.expiresAt,
151
+ forceDestinationSmartproxy: persistedClient?.forceDestinationSmartproxy ?? true,
152
+ destinationAllowList: persistedClient?.destinationAllowList,
153
+ destinationBlockList: persistedClient?.destinationBlockList,
154
+ useHostIp: persistedClient?.useHostIp,
155
+ useDhcp: persistedClient?.useDhcp,
156
+ staticIp: persistedClient?.staticIp,
157
+ forceVlan: persistedClient?.forceVlan,
158
+ vlanId: persistedClient?.vlanId,
130
159
  },
131
160
  wireguardConfig: bundle.wireguardConfig,
132
161
  };
@@ -151,6 +180,14 @@ export class VpnHandler {
151
180
  await manager.updateClient(dataArg.clientId, {
152
181
  description: dataArg.description,
153
182
  serverDefinedClientTags: dataArg.serverDefinedClientTags,
183
+ forceDestinationSmartproxy: dataArg.forceDestinationSmartproxy,
184
+ destinationAllowList: dataArg.destinationAllowList,
185
+ destinationBlockList: dataArg.destinationBlockList,
186
+ useHostIp: dataArg.useHostIp,
187
+ useDhcp: dataArg.useDhcp,
188
+ staticIp: dataArg.staticIp,
189
+ forceVlan: dataArg.forceVlan,
190
+ vlanId: dataArg.vlanId,
154
191
  });
155
192
  return { success: true };
156
193
  } catch (err: unknown) {
package/ts/paths.ts CHANGED
@@ -34,7 +34,6 @@ export function resolvePaths(baseDir?: string) {
34
34
  dcrouterHomeDir: root,
35
35
  dataDir: resolvedDataDir,
36
36
  defaultTsmDbPath: plugins.path.join(root, 'tsmdb'),
37
- defaultStoragePath: plugins.path.join(root, 'storage'),
38
37
  dnsRecordsDir: plugins.path.join(resolvedDataDir, 'dns'),
39
38
  };
40
39
  }
@@ -1,6 +1,6 @@
1
1
  import * as plugins from '../plugins.js';
2
2
  import { logger } from '../logger.js';
3
- import type { StorageManager } from '../storage/index.js';
3
+ import { AccountingSessionDoc } from '../db/index.js';
4
4
 
5
5
  /**
6
6
  * RADIUS accounting session
@@ -84,8 +84,6 @@ export interface IAccountingSummary {
84
84
  * Accounting manager configuration
85
85
  */
86
86
  export interface IAccountingManagerConfig {
87
- /** Storage key prefix */
88
- storagePrefix?: string;
89
87
  /** Session retention period in days (default: 30) */
90
88
  retentionDays?: number;
91
89
  /** Enable detailed session logging */
@@ -106,7 +104,6 @@ export interface IAccountingManagerConfig {
106
104
  export class AccountingManager {
107
105
  private activeSessions: Map<string, IAccountingSession> = new Map();
108
106
  private config: Required<IAccountingManagerConfig>;
109
- private storageManager?: StorageManager;
110
107
  private staleSessionSweepTimer?: ReturnType<typeof setInterval>;
111
108
 
112
109
  // Counters for statistics
@@ -118,24 +115,20 @@ export class AccountingManager {
118
115
  interimUpdatesReceived: 0,
119
116
  };
120
117
 
121
- constructor(config?: IAccountingManagerConfig, storageManager?: StorageManager) {
118
+ constructor(config?: IAccountingManagerConfig) {
122
119
  this.config = {
123
- storagePrefix: config?.storagePrefix ?? '/radius/accounting',
124
120
  retentionDays: config?.retentionDays ?? 30,
125
121
  detailedLogging: config?.detailedLogging ?? false,
126
122
  maxActiveSessions: config?.maxActiveSessions ?? 10000,
127
123
  staleSessionTimeoutHours: config?.staleSessionTimeoutHours ?? 24,
128
124
  };
129
- this.storageManager = storageManager;
130
125
  }
131
126
 
132
127
  /**
133
128
  * Initialize the accounting manager
134
129
  */
135
130
  async initialize(): Promise<void> {
136
- if (this.storageManager) {
137
- await this.loadActiveSessions();
138
- }
131
+ await this.loadActiveSessions();
139
132
 
140
133
  // Start periodic sweep to evict stale sessions (every 15 minutes)
141
134
  this.staleSessionSweepTimer = setInterval(() => {
@@ -176,9 +169,7 @@ export class AccountingManager {
176
169
  session.endTime = Date.now();
177
170
  session.sessionTime = Math.floor((session.endTime - session.startTime) / 1000);
178
171
 
179
- if (this.storageManager) {
180
- this.archiveSession(session).catch(() => {});
181
- }
172
+ this.persistSession(session).catch(() => {});
182
173
 
183
174
  this.activeSessions.delete(sessionId);
184
175
  swept++;
@@ -250,9 +241,7 @@ export class AccountingManager {
250
241
  }
251
242
 
252
243
  // Persist session
253
- if (this.storageManager) {
254
- await this.persistSession(session);
255
- }
244
+ await this.persistSession(session);
256
245
  }
257
246
 
258
247
  /**
@@ -298,9 +287,7 @@ export class AccountingManager {
298
287
  }
299
288
 
300
289
  // Update persisted session
301
- if (this.storageManager) {
302
- await this.persistSession(session);
303
- }
290
+ await this.persistSession(session);
304
291
  }
305
292
 
306
293
  /**
@@ -353,10 +340,8 @@ export class AccountingManager {
353
340
  logger.log('info', `Accounting Stop: session=${data.sessionId}, duration=${session.sessionTime}s, in=${session.inputOctets}, out=${session.outputOctets}`);
354
341
  }
355
342
 
356
- // Archive the session
357
- if (this.storageManager) {
358
- await this.archiveSession(session);
359
- }
343
+ // Update status in the database (single collection, no active->archive move needed)
344
+ await this.persistSession(session);
360
345
 
361
346
  // Remove from active sessions
362
347
  this.activeSessions.delete(data.sessionId);
@@ -493,23 +478,16 @@ export class AccountingManager {
493
478
  * Clean up old archived sessions based on retention policy
494
479
  */
495
480
  async cleanupOldSessions(): Promise<number> {
496
- if (!this.storageManager) {
497
- return 0;
498
- }
499
-
500
481
  const cutoffTime = Date.now() - this.config.retentionDays * 24 * 60 * 60 * 1000;
501
482
  let deletedCount = 0;
502
483
 
503
484
  try {
504
- const keys = await this.storageManager.list(`${this.config.storagePrefix}/archive/`);
485
+ const oldDocs = await AccountingSessionDoc.findStoppedBefore(cutoffTime);
505
486
 
506
- for (const key of keys) {
487
+ for (const doc of oldDocs) {
507
488
  try {
508
- const session = await this.storageManager.getJSON<IAccountingSession>(key);
509
- if (session && session.endTime > 0 && session.endTime < cutoffTime) {
510
- await this.storageManager.delete(key);
511
- deletedCount++;
512
- }
489
+ await doc.delete();
490
+ deletedCount++;
513
491
  } catch (error) {
514
492
  // Ignore individual errors
515
493
  }
@@ -552,9 +530,7 @@ export class AccountingManager {
552
530
  session.terminateCause = 'SessionEvicted';
553
531
  session.endTime = Date.now();
554
532
 
555
- if (this.storageManager) {
556
- await this.archiveSession(session);
557
- }
533
+ await this.persistSession(session);
558
534
 
559
535
  this.activeSessions.delete(sessionId);
560
536
  logger.log('warn', `Evicted session ${sessionId} due to capacity limit`);
@@ -562,25 +538,38 @@ export class AccountingManager {
562
538
  }
563
539
 
564
540
  /**
565
- * Load active sessions from storage
541
+ * Load active sessions from database
566
542
  */
567
543
  private async loadActiveSessions(): Promise<void> {
568
- if (!this.storageManager) {
569
- return;
570
- }
571
-
572
544
  try {
573
- const keys = await this.storageManager.list(`${this.config.storagePrefix}/active/`);
574
-
575
- for (const key of keys) {
576
- try {
577
- const session = await this.storageManager.getJSON<IAccountingSession>(key);
578
- if (session && session.status === 'active') {
579
- this.activeSessions.set(session.sessionId, session);
580
- }
581
- } catch (error) {
582
- // Ignore individual errors
583
- }
545
+ const docs = await AccountingSessionDoc.findActive();
546
+
547
+ for (const doc of docs) {
548
+ const session: IAccountingSession = {
549
+ sessionId: doc.sessionId,
550
+ username: doc.username,
551
+ macAddress: doc.macAddress,
552
+ nasIpAddress: doc.nasIpAddress,
553
+ nasPort: doc.nasPort,
554
+ nasPortType: doc.nasPortType,
555
+ nasIdentifier: doc.nasIdentifier,
556
+ vlanId: doc.vlanId,
557
+ framedIpAddress: doc.framedIpAddress,
558
+ calledStationId: doc.calledStationId,
559
+ callingStationId: doc.callingStationId,
560
+ startTime: doc.startTime,
561
+ endTime: doc.endTime,
562
+ lastUpdateTime: doc.lastUpdateTime,
563
+ status: doc.status,
564
+ terminateCause: doc.terminateCause,
565
+ inputOctets: doc.inputOctets,
566
+ outputOctets: doc.outputOctets,
567
+ inputPackets: doc.inputPackets,
568
+ outputPackets: doc.outputPackets,
569
+ sessionTime: doc.sessionTime,
570
+ serviceType: doc.serviceType,
571
+ };
572
+ this.activeSessions.set(session.sessionId, session);
584
573
  }
585
574
  } catch (error: unknown) {
586
575
  logger.log('warn', `Failed to load active sessions: ${(error as Error).message}`);
@@ -588,70 +577,59 @@ export class AccountingManager {
588
577
  }
589
578
 
590
579
  /**
591
- * Persist a session to storage
580
+ * Persist a session to the database (create or update)
592
581
  */
593
582
  private async persistSession(session: IAccountingSession): Promise<void> {
594
- if (!this.storageManager) {
595
- return;
596
- }
597
-
598
- const key = `${this.config.storagePrefix}/active/${session.sessionId}.json`;
599
583
  try {
600
- await this.storageManager.setJSON(key, session);
584
+ let doc = await AccountingSessionDoc.findBySessionId(session.sessionId);
585
+ if (!doc) {
586
+ doc = new AccountingSessionDoc();
587
+ }
588
+ Object.assign(doc, session);
589
+ await doc.save();
601
590
  } catch (error: unknown) {
602
591
  logger.log('error', `Failed to persist session ${session.sessionId}: ${(error as Error).message}`);
603
592
  }
604
593
  }
605
594
 
606
595
  /**
607
- * Archive a completed session
608
- */
609
- private async archiveSession(session: IAccountingSession): Promise<void> {
610
- if (!this.storageManager) {
611
- return;
612
- }
613
-
614
- try {
615
- // Remove from active
616
- const activeKey = `${this.config.storagePrefix}/active/${session.sessionId}.json`;
617
- await this.storageManager.delete(activeKey);
618
-
619
- // Add to archive with date-based path
620
- const date = new Date(session.endTime);
621
- const archiveKey = `${this.config.storagePrefix}/archive/${date.getFullYear()}/${String(date.getMonth() + 1).padStart(2, '0')}/${String(date.getDate()).padStart(2, '0')}/${session.sessionId}.json`;
622
- await this.storageManager.setJSON(archiveKey, session);
623
- } catch (error: unknown) {
624
- logger.log('error', `Failed to archive session ${session.sessionId}: ${(error as Error).message}`);
625
- }
626
- }
627
-
628
- /**
629
- * Get archived sessions for a time period
596
+ * Get archived (stopped/terminated) sessions for a time period
630
597
  */
631
598
  private async getArchivedSessions(startTime: number, endTime: number): Promise<IAccountingSession[]> {
632
- if (!this.storageManager) {
633
- return [];
634
- }
635
-
636
599
  const sessions: IAccountingSession[] = [];
637
600
 
638
601
  try {
639
- const keys = await this.storageManager.list(`${this.config.storagePrefix}/archive/`);
640
-
641
- for (const key of keys) {
642
- try {
643
- const session = await this.storageManager.getJSON<IAccountingSession>(key);
644
- if (
645
- session &&
646
- session.endTime > 0 &&
647
- session.startTime <= endTime &&
648
- session.endTime >= startTime
649
- ) {
650
- sessions.push(session);
651
- }
652
- } catch (error) {
653
- // Ignore individual errors
654
- }
602
+ const docs = await AccountingSessionDoc.getInstances({
603
+ status: { $in: ['stopped', 'terminated'] } as any,
604
+ endTime: { $gt: 0, $gte: startTime } as any,
605
+ startTime: { $lte: endTime } as any,
606
+ });
607
+
608
+ for (const doc of docs) {
609
+ sessions.push({
610
+ sessionId: doc.sessionId,
611
+ username: doc.username,
612
+ macAddress: doc.macAddress,
613
+ nasIpAddress: doc.nasIpAddress,
614
+ nasPort: doc.nasPort,
615
+ nasPortType: doc.nasPortType,
616
+ nasIdentifier: doc.nasIdentifier,
617
+ vlanId: doc.vlanId,
618
+ framedIpAddress: doc.framedIpAddress,
619
+ calledStationId: doc.calledStationId,
620
+ callingStationId: doc.callingStationId,
621
+ startTime: doc.startTime,
622
+ endTime: doc.endTime,
623
+ lastUpdateTime: doc.lastUpdateTime,
624
+ status: doc.status,
625
+ terminateCause: doc.terminateCause,
626
+ inputOctets: doc.inputOctets,
627
+ outputOctets: doc.outputOctets,
628
+ inputPackets: doc.inputPackets,
629
+ outputPackets: doc.outputPackets,
630
+ sessionTime: doc.sessionTime,
631
+ serviceType: doc.serviceType,
632
+ });
655
633
  }
656
634
  } catch (error: unknown) {
657
635
  logger.log('warn', `Failed to get archived sessions: ${(error as Error).message}`);
@@ -1,6 +1,5 @@
1
1
  import * as plugins from '../plugins.js';
2
2
  import { logger } from '../logger.js';
3
- import type { StorageManager } from '../storage/index.js';
4
3
  import { VlanManager, type IMacVlanMapping, type IVlanManagerConfig } from './classes.vlan.manager.js';
5
4
  import { AccountingManager, type IAccountingSession, type IAccountingManagerConfig } from './classes.accounting.manager.js';
6
5
 
@@ -92,7 +91,6 @@ export class RadiusServer {
92
91
  private vlanManager: VlanManager;
93
92
  private accountingManager: AccountingManager;
94
93
  private config: IRadiusServerConfig;
95
- private storageManager?: StorageManager;
96
94
  private clientSecrets: Map<string, string> = new Map();
97
95
  private running: boolean = false;
98
96
 
@@ -105,20 +103,19 @@ export class RadiusServer {
105
103
  startTime: 0,
106
104
  };
107
105
 
108
- constructor(config: IRadiusServerConfig, storageManager?: StorageManager) {
106
+ constructor(config: IRadiusServerConfig) {
109
107
  this.config = {
110
108
  authPort: config.authPort ?? 1812,
111
109
  acctPort: config.acctPort ?? 1813,
112
110
  bindAddress: config.bindAddress ?? '0.0.0.0',
113
111
  ...config,
114
112
  };
115
- this.storageManager = storageManager;
116
113
 
117
114
  // Initialize VLAN manager
118
- this.vlanManager = new VlanManager(config.vlanAssignment, storageManager);
115
+ this.vlanManager = new VlanManager(config.vlanAssignment);
119
116
 
120
117
  // Initialize accounting manager
121
- this.accountingManager = new AccountingManager(config.accounting, storageManager);
118
+ this.accountingManager = new AccountingManager(config.accounting);
122
119
  }
123
120
 
124
121
  /**
@@ -1,6 +1,6 @@
1
1
  import * as plugins from '../plugins.js';
2
2
  import { logger } from '../logger.js';
3
- import type { StorageManager } from '../storage/index.js';
3
+ import { VlanMappingsDoc } from '../db/index.js';
4
4
 
5
5
  /**
6
6
  * MAC address to VLAN mapping
@@ -42,8 +42,6 @@ export interface IVlanManagerConfig {
42
42
  defaultVlan?: number;
43
43
  /** Whether to allow unknown MACs (assign default VLAN) or reject */
44
44
  allowUnknownMacs?: boolean;
45
- /** Storage key prefix for persistence */
46
- storagePrefix?: string;
47
45
  }
48
46
 
49
47
  /**
@@ -56,27 +54,22 @@ export interface IVlanManagerConfig {
56
54
  export class VlanManager {
57
55
  private mappings: Map<string, IMacVlanMapping> = new Map();
58
56
  private config: Required<IVlanManagerConfig>;
59
- private storageManager?: StorageManager;
60
57
 
61
58
  // Cache for normalized MAC lookups
62
59
  private normalizedMacCache: Map<string, string> = new Map();
63
60
 
64
- constructor(config?: IVlanManagerConfig, storageManager?: StorageManager) {
61
+ constructor(config?: IVlanManagerConfig) {
65
62
  this.config = {
66
63
  defaultVlan: config?.defaultVlan ?? 1,
67
64
  allowUnknownMacs: config?.allowUnknownMacs ?? true,
68
- storagePrefix: config?.storagePrefix ?? '/radius/vlan-mappings',
69
65
  };
70
- this.storageManager = storageManager;
71
66
  }
72
67
 
73
68
  /**
74
69
  * Initialize the VLAN manager and load persisted mappings
75
70
  */
76
71
  async initialize(): Promise<void> {
77
- if (this.storageManager) {
78
- await this.loadMappings();
79
- }
72
+ await this.loadMappings();
80
73
  logger.log('info', `VlanManager initialized with ${this.mappings.size} mappings, default VLAN: ${this.config.defaultVlan}`);
81
74
  }
82
75
 
@@ -157,10 +150,8 @@ export class VlanManager {
157
150
 
158
151
  this.mappings.set(normalizedMac, fullMapping);
159
152
 
160
- // Persist to storage
161
- if (this.storageManager) {
162
- await this.saveMappings();
163
- }
153
+ // Persist to database
154
+ await this.saveMappings();
164
155
 
165
156
  logger.log('info', `VLAN mapping ${existingMapping ? 'updated' : 'added'}: ${normalizedMac} -> VLAN ${mapping.vlan}`);
166
157
  return fullMapping;
@@ -173,7 +164,7 @@ export class VlanManager {
173
164
  const normalizedMac = this.normalizeMac(mac);
174
165
  const removed = this.mappings.delete(normalizedMac);
175
166
 
176
- if (removed && this.storageManager) {
167
+ if (removed) {
177
168
  await this.saveMappings();
178
169
  logger.log('info', `VLAN mapping removed: ${normalizedMac}`);
179
170
  }
@@ -333,39 +324,36 @@ export class VlanManager {
333
324
  }
334
325
 
335
326
  /**
336
- * Load mappings from storage
327
+ * Load mappings from database
337
328
  */
338
329
  private async loadMappings(): Promise<void> {
339
- if (!this.storageManager) {
340
- return;
341
- }
342
-
343
330
  try {
344
- const data = await this.storageManager.getJSON<IMacVlanMapping[]>(this.config.storagePrefix);
345
- if (data && Array.isArray(data)) {
346
- for (const mapping of data) {
331
+ const doc = await VlanMappingsDoc.load();
332
+ if (doc && Array.isArray(doc.mappings)) {
333
+ for (const mapping of doc.mappings) {
347
334
  this.mappings.set(this.normalizeMac(mapping.mac), mapping);
348
335
  }
349
- logger.log('info', `Loaded ${data.length} VLAN mappings from storage`);
336
+ logger.log('info', `Loaded ${doc.mappings.length} VLAN mappings from database`);
350
337
  }
351
338
  } catch (error: unknown) {
352
- logger.log('warn', `Failed to load VLAN mappings from storage: ${(error as Error).message}`);
339
+ logger.log('warn', `Failed to load VLAN mappings from database: ${(error as Error).message}`);
353
340
  }
354
341
  }
355
342
 
356
343
  /**
357
- * Save mappings to storage
344
+ * Save mappings to database
358
345
  */
359
346
  private async saveMappings(): Promise<void> {
360
- if (!this.storageManager) {
361
- return;
362
- }
363
-
364
347
  try {
365
348
  const mappings = Array.from(this.mappings.values());
366
- await this.storageManager.setJSON(this.config.storagePrefix, mappings);
349
+ let doc = await VlanMappingsDoc.load();
350
+ if (!doc) {
351
+ doc = new VlanMappingsDoc();
352
+ }
353
+ doc.mappings = mappings;
354
+ await doc.save();
367
355
  } catch (error: unknown) {
368
- logger.log('error', `Failed to save VLAN mappings to storage: ${(error as Error).message}`);
356
+ logger.log('error', `Failed to save VLAN mappings to database: ${(error as Error).message}`);
369
357
  }
370
358
  }
371
359
  }
@@ -6,7 +6,7 @@
6
6
  * - VLAN assignment based on MAC addresses
7
7
  * - OUI (vendor prefix) pattern matching for device categorization
8
8
  * - RADIUS accounting for session tracking and billing
9
- * - Integration with StorageManager for persistence
9
+ * - Integration with smartdata document classes for persistence
10
10
  */
11
11
 
12
12
  export * from './classes.radius.server.js';
@@ -1,8 +1,6 @@
1
1
  import * as plugins from '../plugins.js';
2
- import type { StorageManager } from '../storage/classes.storagemanager.js';
3
2
  import type { IRemoteIngress, IDcRouterRouteConfig } from '../../ts_interfaces/data/remoteingress.js';
4
-
5
- const STORAGE_PREFIX = '/remote-ingress/';
3
+ import { RemoteIngressEdgeDoc } from '../db/index.js';
6
4
 
7
5
  /**
8
6
  * Flatten a port range (number | number[] | Array<{from, to}>) to a sorted unique number array.
@@ -27,33 +25,40 @@ function extractPorts(portRange: number | Array<number | { from: number; to: num
27
25
 
28
26
  /**
29
27
  * Manages CRUD for remote ingress edge registrations.
30
- * Persists edge configs via StorageManager and provides
28
+ * Persists edge configs via smartdata document classes and provides
31
29
  * the allowed edges list for the Rust hub.
32
30
  */
33
31
  export class RemoteIngressManager {
34
- private storageManager: StorageManager;
35
32
  private edges: Map<string, IRemoteIngress> = new Map();
36
33
  private routes: IDcRouterRouteConfig[] = [];
37
34
 
38
- constructor(storageManager: StorageManager) {
39
- this.storageManager = storageManager;
35
+ constructor() {
40
36
  }
41
37
 
42
38
  /**
43
- * Load all edge registrations from storage into memory.
39
+ * Load all edge registrations from the database into memory.
44
40
  */
45
41
  public async initialize(): Promise<void> {
46
- const keys = await this.storageManager.list(STORAGE_PREFIX);
47
- for (const key of keys) {
48
- const edge = await this.storageManager.getJSON<IRemoteIngress>(key);
49
- if (edge) {
50
- // Migration: old edges without autoDerivePorts default to true
51
- if ((edge as any).autoDerivePorts === undefined) {
52
- edge.autoDerivePorts = true;
53
- await this.storageManager.setJSON(key, edge);
54
- }
55
- this.edges.set(edge.id, edge);
42
+ const docs = await RemoteIngressEdgeDoc.findAll();
43
+ for (const doc of docs) {
44
+ // Migration: old edges without autoDerivePorts default to true
45
+ if ((doc as any).autoDerivePorts === undefined) {
46
+ doc.autoDerivePorts = true;
47
+ await doc.save();
56
48
  }
49
+ const edge: IRemoteIngress = {
50
+ id: doc.id,
51
+ name: doc.name,
52
+ secret: doc.secret,
53
+ listenPorts: doc.listenPorts,
54
+ listenPortsUdp: doc.listenPortsUdp,
55
+ enabled: doc.enabled,
56
+ autoDerivePorts: doc.autoDerivePorts,
57
+ tags: doc.tags,
58
+ createdAt: doc.createdAt,
59
+ updatedAt: doc.updatedAt,
60
+ };
61
+ this.edges.set(edge.id, edge);
57
62
  }
58
63
  }
59
64
 
@@ -189,7 +194,9 @@ export class RemoteIngressManager {
189
194
  updatedAt: now,
190
195
  };
191
196
 
192
- await this.storageManager.setJSON(`${STORAGE_PREFIX}${id}`, edge);
197
+ const doc = new RemoteIngressEdgeDoc();
198
+ Object.assign(doc, edge);
199
+ await doc.save();
193
200
  this.edges.set(id, edge);
194
201
  return edge;
195
202
  }
@@ -233,7 +240,11 @@ export class RemoteIngressManager {
233
240
  if (updates.tags !== undefined) edge.tags = updates.tags;
234
241
  edge.updatedAt = Date.now();
235
242
 
236
- await this.storageManager.setJSON(`${STORAGE_PREFIX}${id}`, edge);
243
+ const doc = await RemoteIngressEdgeDoc.findById(id);
244
+ if (doc) {
245
+ Object.assign(doc, edge);
246
+ await doc.save();
247
+ }
237
248
  this.edges.set(id, edge);
238
249
  return edge;
239
250
  }
@@ -245,7 +256,10 @@ export class RemoteIngressManager {
245
256
  if (!this.edges.has(id)) {
246
257
  return false;
247
258
  }
248
- await this.storageManager.delete(`${STORAGE_PREFIX}${id}`);
259
+ const doc = await RemoteIngressEdgeDoc.findById(id);
260
+ if (doc) {
261
+ await doc.delete();
262
+ }
249
263
  this.edges.delete(id);
250
264
  return true;
251
265
  }
@@ -262,7 +276,11 @@ export class RemoteIngressManager {
262
276
  edge.secret = plugins.crypto.randomBytes(32).toString('hex');
263
277
  edge.updatedAt = Date.now();
264
278
 
265
- await this.storageManager.setJSON(`${STORAGE_PREFIX}${id}`, edge);
279
+ const doc = await RemoteIngressEdgeDoc.findById(id);
280
+ if (doc) {
281
+ Object.assign(doc, edge);
282
+ await doc.save();
283
+ }
266
284
  this.edges.set(id, edge);
267
285
  return edge.secret;
268
286
  }