- MongoDB storage: cwmp_exchanges collection with indexes (deviceId+timestamp, deviceId+sequenceNumber unique, TTL 24h) - ExchangeStoreService: CWMP method extraction, per-device queue for ordering, retry logic, message cap (5000/device) - Exchange API: GET/DELETE/SSE stream endpoints with Last-Event-ID reconnection - CwmpLoggerMiddleware: dual-write (MongoDB + legacy files) with fire-and-forget - Frontend: SequenceViewer (CPE↔ACS lifelines, arrows, auto-scroll, virtual scroll) + InspectorPanel (formatted XML, copy, syntax highlighting) - Tr069Trace page: integrated new viewer with col-6/col-6 layout - DeviceDetail page: collapsible exchange section when device is traced - 14 property-based tests, 40+ unit tests, 5 integration tests - Health check includes index verification - Config: feature flags, SSE timeouts, retry policy
65 lines
1.6 KiB
TypeScript
65 lines
1.6 KiB
TypeScript
import type { ApplicationService } from '@adonisjs/core/types'
|
|
import { Db, MongoClient } from 'mongodb'
|
|
|
|
declare module '@adonisjs/core/types' {
|
|
interface ContainerBindings {
|
|
mongodb: Db
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Singleton reference to the MongoDB Db instance.
|
|
* Set during provider boot, used synchronously by BaseModel.
|
|
*/
|
|
let dbInstance: Db | null = null
|
|
|
|
export function getMongoDb(): Db {
|
|
if (!dbInstance) {
|
|
throw new Error('MongoDB is not connected. Ensure MongodbProvider has booted.')
|
|
}
|
|
return dbInstance
|
|
}
|
|
|
|
export default class MongodbProvider {
|
|
private client: MongoClient | null = null
|
|
|
|
constructor(protected app: ApplicationService) {}
|
|
|
|
async boot() {
|
|
const config = await import('#config/database')
|
|
const { uri, dbName } = config.default
|
|
|
|
this.client = new MongoClient(uri, {
|
|
monitorCommands: true,
|
|
serverSelectionTimeoutMS: 5000,
|
|
})
|
|
|
|
await this.client.connect()
|
|
const db = this.client.db(dbName)
|
|
|
|
dbInstance = db
|
|
this.app.container.bindValue('mongodb', db)
|
|
|
|
// Verify cwmp_exchanges indexes after boot
|
|
const { verifyIndexesAtStartup } = await import('#services/exchange_index_checker')
|
|
await verifyIndexesAtStartup(db, {
|
|
warn: (msg: string) => console.warn(msg),
|
|
info: (msg: string) => console.info(msg),
|
|
}).catch((err) => {
|
|
console.warn(`[ExchangeIndexCheck] Failed to verify indexes: ${(err as Error).message}`)
|
|
})
|
|
}
|
|
|
|
async shutdown() {
|
|
if (this.client) {
|
|
try {
|
|
await this.client.close()
|
|
} catch {
|
|
// Connection may already be closed
|
|
}
|
|
this.client = null
|
|
dbInstance = null
|
|
}
|
|
}
|
|
}
|