Viewing is open to everyone. Downloading and starring need a GitHub sign-in. Sign in with GitHub

CKey.swift

v0.1.0-build.85 Latest Commit ede38f5

Size
4.8 KB
Lines
105
Language
swift
SHA-256
cf9df8a8edf5…
View on GitHub

Sign in with GitHub to download. Each download is recorded with your GitHub username.

1@_exported import CKeyScanKit
2import CKeyCodec
3import CKeyTelemetry
4import Foundation
5
6/// Telemetry modes. The numeric values are canonical across every CKey SDK
7/// (docs/adoption-and-telemetry.md).
8public enum CKeyTelemetryMode: Int, Sendable, CaseIterable, ExpressibleByIntegerLiteral {
9 /// 0: no counting, nothing sent. Switching to it purges every counter.
10 case off = 0
11 /// 1 (default): local aggregate counting; batches are sent to openckey.org
12 /// at most once an hour, never on the scan path.
13 case on = 1
14 /// 2: local aggregate counting only; nothing is ever sent.
15 case local = 2
16
17 /// Allows `CKey.telemetry = 0`. Only the literals 0, 1 and 2 are valid; any
18 /// other literal is a programming error and stops the program (it is
19 /// never silently treated as 1). For values known only at run time, use
20 /// `try CKey.setTelemetry(rawValue:)` or `CKeyTelemetryMode(rawValue:)`.
21 public init(integerLiteral value: Int) {
22 guard let mode = CKeyTelemetryMode(rawValue: value) else {
23 fatalError("CKey telemetry mode must be 0 (off), 1 (on) or 2 (local); got \(value)")
24 }
25 self = mode
26 }
27}
28
29/// Aggregate scan counters kept by the telemetry core (modes 1 and 2).
30public struct CKeyTelemetryCounters: Equatable, Sendable {
31 public struct Histogram: Equatable, Sendable {
32 public let count: UInt64
33 public let sum: UInt64
34 /// Ten buckets with inclusive upper edges (see docs/adoption-and-telemetry.md).
35 public let buckets: [UInt64]
36 }
37 public let sessionsStarted: UInt64
38 public let sessionsSucceeded: UInt64
39 public let sessionsFailed: UInt64
40 public let frames: UInt64
41 /// Decodes per profile, keyed "p0", "p0_1", "p1", "p2", "p3".
42 public let decoded: [String: UInt64]
43 public let timeToDecodeMilliseconds: Histogram
44 public let frameMilliseconds: Histogram
45}
46
47/// Package-level configuration.
48///
49/// `CKey` is both this module's name and this type's name; inside an app,
50/// `CKey.telemetry` refers to the type.
51public enum CKey {
52 /// The core's software version (the repository's VERSION).
53 public static var version: String { CKeyCoreInfo.softwareVersion }
54
55 /// The telemetry mode: `.on` (1, default), `.local` (2) or `.off` (0).
56 /// Opting out is one line: `CKey.telemetry = .off` (or `= 0`).
57 ///
58 /// Setting a mode applies the core's switching rules: `.off` purges all
59 /// counters; `.on` -> `.local` drops anything unsent (an in-flight batch's
60 /// result is ignored). The mode is process-wide and not persisted; set it
61 /// at launch, before scanning.
62 public static var telemetry: CKeyTelemetryMode {
63 get {
64 CKeyTelemetryRuntime.shared.start()
65 return CKeyTelemetryMode(rawValue: Int(ckey_telemetry_get_mode())) ?? .on
66 }
67 set {
68 CKeyTelemetryRuntime.shared.start()
69 // Every enum value is valid, so the core cannot refuse it.
70 _ = ckey_telemetry_set_mode(Int32(newValue.rawValue))
71 }
72 }
73
74 /// Sets the telemetry mode from a number (0, 1 or 2), e.g. from a
75 /// configuration file.
76 /// - Throws: `CKeyError` with code `.invalidConfiguration` for any other
77 /// value; the mode is left unchanged (never silently reset to 1).
78 public static func setTelemetry(rawValue: Int) throws {
79 guard let mode = CKeyTelemetryMode(rawValue: rawValue) else {
80 throw CKeyError(.invalidConfiguration,
81 "telemetry mode must be 0 (off), 1 (on) or 2 (local); got \(rawValue)")
82 }
83 telemetry = mode
84 }
85
86 /// The local aggregate totals since counting started (all zero in mode 0).
87 /// Available to the host in modes 1 and 2; nothing here identifies a
88 /// user, a device or a payload.
89 public static var telemetryCounters: CKeyTelemetryCounters {
90 var c = ckey_telemetry_counters()
91 _ = ckey_telemetry_snapshot(&c)
92 func histogram(_ h: ckey_telemetry_histogram) -> CKeyTelemetryCounters.Histogram {
93 let buckets = withUnsafeBytes(of: h.buckets) { Array($0.bindMemory(to: UInt64.self)) }
94 return .init(count: h.count, sum: h.sum, buckets: buckets)
95 }
96 let decoded = withUnsafeBytes(of: c.decoded) { Array($0.bindMemory(to: UInt64.self)) }
97 let keys = ["p0", "p0_1", "p1", "p2", "p3"]
98 var byProfile: [String: UInt64] = [:]
99 for (index, key) in keys.enumerated() where index < decoded.count { byProfile[key] = decoded[index] }
100 return CKeyTelemetryCounters(sessionsStarted: c.sessions_started, sessionsSucceeded: c.sessions_succeeded,
101 sessionsFailed: c.sessions_failed, frames: c.frames, decoded: byProfile,
102 timeToDecodeMilliseconds: histogram(c.time_to_decode_ms),
103 frameMilliseconds: histogram(c.frame_ms))
104 }
105}