103 lines
2.7 KiB
Swift
103 lines
2.7 KiB
Swift
//
|
|
// DispatchTimerSubscription.swift
|
|
// Malinka
|
|
//
|
|
// Created by Juraldinio on 11/17/22.
|
|
// Copyright © 2022 NUT.Tech. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import Combine
|
|
import WalletFoundation
|
|
|
|
/// Configuration for timing
|
|
struct DispatchTimerConfiguration {
|
|
/// Queue on which fire
|
|
let queue: DispatchQueue?
|
|
/// Firing interval
|
|
let interval: DispatchTimeInterval
|
|
/// Allowed delta for system delay
|
|
let leeway: DispatchTimeInterval
|
|
/// How many times to fire
|
|
let times: Subscribers.Demand
|
|
}
|
|
|
|
struct DispatchTimer: Publisher {
|
|
|
|
typealias Output = DispatchTime
|
|
typealias Failure = Never
|
|
|
|
let configuration: DispatchTimerConfiguration
|
|
|
|
init(configuration: DispatchTimerConfiguration) {
|
|
self.configuration = configuration
|
|
}
|
|
|
|
func receive<S: Subscriber>(subscriber: S) where Failure == S.Failure, Output == S.Input {
|
|
|
|
let subscription = DispatchTimerSubscription(subscriber: subscriber,
|
|
configuration: configuration)
|
|
|
|
subscriber.receive(subscription: subscription)
|
|
|
|
}
|
|
}
|
|
|
|
|
|
private final class DispatchTimerSubscription<S: Subscriber>: Subscription where S.Input == DispatchTime {
|
|
|
|
let configuration: DispatchTimerConfiguration
|
|
|
|
var times: Subscribers.Demand
|
|
var requested: Subscribers.Demand = .none
|
|
var source: DispatchSourceTimer?
|
|
var subscriber: S?
|
|
|
|
init(subscriber: S, configuration: DispatchTimerConfiguration) {
|
|
self.subscriber = subscriber
|
|
self.configuration = configuration
|
|
self.times = configuration.times
|
|
}
|
|
|
|
func request(_ demand: Subscribers.Demand) {
|
|
|
|
guard self.times > .none else {
|
|
self.subscriber?.receive(completion: .finished)
|
|
return
|
|
}
|
|
|
|
self.requested += demand
|
|
|
|
if !self.source.isExist, self.requested > .none {
|
|
|
|
let source = DispatchSource.makeTimerSource(queue: configuration.queue)
|
|
source.schedule(deadline: .now() + configuration.interval,
|
|
repeating: configuration.interval,
|
|
leeway: configuration.leeway)
|
|
|
|
source.setEventHandler { [weak self] in
|
|
|
|
guard let self = self,
|
|
self.requested > .none else { return }
|
|
|
|
self.requested -= .max(1)
|
|
self.times -= .max(1)
|
|
|
|
_ = self.subscriber?.receive(.now())
|
|
|
|
if self.times == .none {
|
|
self.subscriber?.receive(completion: .finished)
|
|
}
|
|
}
|
|
|
|
self.source = source
|
|
source.activate()
|
|
}
|
|
}
|
|
|
|
func cancel() {
|
|
self.source = nil
|
|
self.subscriber = nil
|
|
}
|
|
}
|