Files
Luma/Sources/Shared/XMPP/LumaConnectionStatsModule.swift
T
wt 711d0cb1fc
iOS CI / Build and Test SwiftUI App (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build Unsigned iOS IPA (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build macOS ZIP (push) Canceled after 0s
gix warnings
2026-08-21 20:11:05 +07:00

69 lines
2.1 KiB
Swift

import Foundation
import Martin
/// Counts XEP-0198 stanza statistics (sent / acknowledged / received) at the
/// stream level so the server-details screen can mirror Monal's connection
/// statistics. Registered as an `XmppStanzaFilter` *before* stream management
/// so it can also observe the server's `<a h='N'>` acknowledgements.
final class LumaConnectionStatsModule: XmppModuleBase, XmppModule, XmppStanzaFilter {
static let ID = "lumaConnectionStats"
static let smNamespace = "urn:xmpp:sm:3"
let criteria = Criteria.empty()
let features: [String] = []
private let lock = NSLock()
private var sent: UInt32 = 0
private var received: UInt32 = 0
private var acknowledged: UInt32 = 0
struct Snapshot: Equatable, Sendable {
let sent: UInt32
let acknowledged: UInt32
let received: UInt32
var unacknowledged: UInt32 {
sent > acknowledged ? sent - acknowledged : 0
}
}
var snapshot: Snapshot {
lock.lock()
defer { lock.unlock() }
return Snapshot(sent: sent, acknowledged: acknowledged, received: received)
}
func processIncoming(stanza: Stanza) -> Bool {
if stanza.xmlns == Self.smNamespace, stanza.name == "a" {
if let raw = stanza.attribute("h"), let value = UInt32(raw) {
lock.lock()
acknowledged = value
lock.unlock()
}
// Let StreamManagementModule consume the acknowledgement too.
return false
}
if Self.isCountable(stanza) {
lock.lock()
received += 1
lock.unlock()
}
return false
}
func processOutgoing(stanza: Stanza) {
guard Self.isCountable(stanza) else { return }
lock.lock()
sent += 1
lock.unlock()
}
func process(stanza: Stanza) throws {
// Criteria is empty, so this module is never selected by the dispatcher.
}
private static func isCountable(_ stanza: Stanza) -> Bool {
stanza.name == "iq" || stanza.name == "message" || stanza.name == "presence"
}
}