glean-core/ios/Glean/Metrics/Ping.swift (62 lines of code) (raw):

/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /// The reasons a ping may be sent. /// Reason codes can be of any type, but need to adhere to a protocol. /// /// For user-defined custom pings associated reason codes will be defined as `enums`. public protocol ReasonCodes: Hashable { /// The index of the reason code, used to index the string array passed at /// `Ping` instantiation. func index() -> Int } /// Default of no reason codes for pings. /// /// An enum with no values for convenient use as the default set of reason codes /// that an `Ping` can accept. public enum NoReasonCodes: ReasonCodes { public func index() -> Int { return 0 } } /// This implements the developer facing API for custom pings. /// /// Instances of this class type are automatically generated by the parsers at build time. /// /// The Ping API only exposes the `Ping.sumbit()` method, which collects and /// schedules a ping for eventual upload. public class Ping<ReasonCodesEnum: ReasonCodes> { let name: String let reasonCodes: [String] let innerPing: PingType var testCallback: ((ReasonCodesEnum?) throws -> Void)? /// The public constructor used by automatically generated metrics. public init( name: String, includeClientId: Bool, sendIfEmpty: Bool, preciseTimestamps: Bool, includeInfoSections: Bool, enabled: Bool, schedulesPings: [String], reasonCodes: [String], followsCollectionEnabled: Bool, uploaderCapabilities: [String] ) { self.name = name self.reasonCodes = reasonCodes self.innerPing = PingType( name, includeClientId, sendIfEmpty, preciseTimestamps, includeInfoSections, enabled, schedulesPings, reasonCodes, followsCollectionEnabled, uploaderCapabilities ) } /// **Test-only API** /// /// Attach a callback to be called right before a new ping is submitted. /// The provided function is called exactly once before submitting a ping. /// /// Note: The callback will be called on any call to submit. /// A ping might not be sent afterwards, e.g. if the ping is otherwise empty (and /// `send_if_empty` is `false`). public func testBeforeNextSubmit(cb: @escaping (ReasonCodesEnum?) throws -> Void) { self.testCallback = cb } /// Collect and submit the ping for eventual uploading. /// /// While the collection of metrics into pings happens synchronously, the /// ping queuing and ping uploading happens asyncronously. /// There are no guarantees that this will happen immediately. /// /// If the ping currently contains no content, it will not be queued. /// /// - parameters: /// * reason: The reason the ping is being submitted. public func submit(reason: ReasonCodesEnum? = nil) { if let cb = self.testCallback { do { try cb(reason) } catch { assert(false, "Callback threw before submitting ping \(name).") } self.testCallback = nil } var reasonString: String? if reason != nil { reasonString = self.reasonCodes[reason!.index()] } innerPing.submit(reasonString) } /// Enable or disable a ping. /// /// Disabling a ping causes all data for that ping to be removed from storage /// and all pending pings of that type to be deleted. public func setEnabled(enabled: Bool) { innerPing.setEnabled(enabled) } }