Revision control

Copy as Markdown

/* 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]
) {
self.name = name
self.reasonCodes = reasonCodes
self.innerPing = PingType(
name,
includeClientId,
sendIfEmpty,
preciseTimestamps,
includeInfoSections,
enabled,
schedulesPings,
reasonCodes
)
}
/// **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)
}
}