initial commit
This commit is contained in:
commit
8de962eeb8
44 changed files with 4843 additions and 0 deletions
79
DashboardViewModel.swift
Normal file
79
DashboardViewModel.swift
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
import Foundation
|
||||
import Observation
|
||||
|
||||
@MainActor
|
||||
@Observable
|
||||
final class DashboardViewModel {
|
||||
var phase: LoadPhase = .idle
|
||||
var onuCounts: [(state: ONULifecycleState, count: Int)] = []
|
||||
var onuTotal = 0
|
||||
var oltCount = 0
|
||||
var controllerCount = 0
|
||||
var severityCounts: [(severity: AlarmSeverity, count: Int)] = []
|
||||
|
||||
// Aggregates derived from the state docs already fetched for the counts above
|
||||
// — no extra API calls.
|
||||
var totalDownstreamBps = 0.0
|
||||
var totalUpstreamBps = 0.0
|
||||
var abnormalRxCount = 0 // ONUs with Rx optical < −28 or > −10 dBm
|
||||
var lasersOffCount = 0 // OLTs with the laser shut down
|
||||
var opticalAvailable = false // whether the bulk ONU-STATE response carried Rx levels
|
||||
|
||||
// The actual offenders, kept for drill-down (no re-fetch).
|
||||
var abnormalRxONUs: [ONUStateDoc] = []
|
||||
var lasersOffOLTs: [OLTStateDoc] = []
|
||||
|
||||
private let connection: MCMSConnection
|
||||
init(connection: MCMSConnection) { self.connection = connection }
|
||||
|
||||
/// Light by default: the ONU count, state breakdown, OLT traffic and
|
||||
/// laser-off count all come from the (small) OLT-STATE docs. The heavy
|
||||
/// per-ONU optical scan runs only when `extraStats` is on.
|
||||
func load(extraStats: Bool = false) async {
|
||||
phase = .loading
|
||||
do {
|
||||
// OLT-STATE drives the OLT count, ONU registration (dev guide
|
||||
// Procedure 2), total traffic, and laser state — all from a handful
|
||||
// of small docs.
|
||||
let olts = try await connection.olt.allStates()
|
||||
oltCount = olts.count
|
||||
|
||||
let registration = OLTRepository.registrationMap(from: olts)
|
||||
onuTotal = registration.count
|
||||
onuCounts = Dictionary(grouping: registration.values, by: { $0 })
|
||||
.map { (state: $0.key, count: $0.value.count) }
|
||||
.sorted { $0.count > $1.count }
|
||||
|
||||
totalDownstreamBps = olts.compactMap(\.txRateBps).reduce(0, +)
|
||||
totalUpstreamBps = olts.compactMap(\.rxRateBps).reduce(0, +)
|
||||
lasersOffOLTs = olts.filter(\.isLaserOff)
|
||||
lasersOffCount = lasersOffOLTs.count
|
||||
|
||||
controllerCount = (try? await connection.controller.allConfigs().count) ?? 0
|
||||
|
||||
if let alarms = try? await connection.onu.alarmHistories() {
|
||||
severityCounts = Dictionary(grouping: alarms, by: { $0.severity })
|
||||
.map { (severity: $0.key, count: $0.value.count) }
|
||||
.sorted { $0.severity.rank < $1.severity.rank }
|
||||
}
|
||||
|
||||
// Opt-in heavy scan: pull every ONU-STATE for the Rx optical check.
|
||||
if extraStats {
|
||||
let onus = try await connection.onu.allStates()
|
||||
opticalAvailable = onus.contains { $0.rxOpticalDBm != nil }
|
||||
abnormalRxONUs = onus.filter { onu in
|
||||
guard let rx = onu.rxOpticalDBm else { return false }
|
||||
return rx < -28 || rx > -10
|
||||
}
|
||||
abnormalRxCount = abnormalRxONUs.count
|
||||
} else {
|
||||
opticalAvailable = false
|
||||
abnormalRxONUs = []
|
||||
abnormalRxCount = 0
|
||||
}
|
||||
phase = .loaded
|
||||
} catch {
|
||||
phase = .failed((error as? APIError)?.localizedDescription ?? error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue