mirror of
https://github.com/aljazceru/breez-sdk-liquid.git
synced 2025-12-22 16:34:23 +01:00
* Add BOLT12 receive payment handling * Handle BOLT12 invoice requests via WS * Fix invoice request subscription on stream initialisation * Store the BOLT12 offer used to receive a payment * Address review feedback * Separate into create BOLT12 invoice fn * Update all BOLT12 offers when webhook URL changes * Deprecate Lightning for Bolt11Invoice
109 lines
4.6 KiB
Swift
109 lines
4.6 KiB
Swift
import UserNotifications
|
|
|
|
public protocol TaskProtocol : EventListener {
|
|
var payload: String { get set }
|
|
var contentHandler: ((UNNotificationContent) -> Void)? { get set }
|
|
var bestAttemptContent: UNMutableNotificationContent? { get set }
|
|
|
|
func start(liquidSDK: BindingLiquidSdk) throws
|
|
func onShutdown()
|
|
}
|
|
|
|
extension TaskProtocol {
|
|
func removePushNotifications(threadIdentifier: String, logger: ServiceLogger) {
|
|
let semaphore = DispatchSemaphore(value: 0)
|
|
let notificationCenter = UNUserNotificationCenter.current()
|
|
|
|
notificationCenter.getDeliveredNotifications(completionHandler: { notifications in
|
|
defer {
|
|
semaphore.signal()
|
|
}
|
|
|
|
let removableNotifications = notifications.filter({ $0.request.content.threadIdentifier == threadIdentifier })
|
|
guard !removableNotifications.isEmpty else {
|
|
return
|
|
}
|
|
// The call to removeDeliveredNotifications() is async in a background thread and
|
|
// needs to be complete before calling contentHandler()
|
|
notificationCenter.removeDeliveredNotifications(withIdentifiers: removableNotifications.map({ $0.request.identifier }))
|
|
logger.log(tag: "TaskProtocol", line:"removePushNotifications: \(removableNotifications.count)", level: "INFO")
|
|
})
|
|
|
|
semaphore.wait()
|
|
}
|
|
|
|
func displayPushNotification(title: String, body: String? = nil, logger: ServiceLogger, threadIdentifier: String? = nil) {
|
|
logger.log(tag: "TaskProtocol", line:"displayPushNotification \(title)", level: "INFO")
|
|
guard
|
|
let contentHandler = contentHandler,
|
|
let bestAttemptContent = bestAttemptContent
|
|
else {
|
|
return
|
|
}
|
|
|
|
removePushNotifications(threadIdentifier: Constants.NOTIFICATION_THREAD_REPLACEABLE, logger: logger)
|
|
|
|
if let body = body {
|
|
bestAttemptContent.body = body
|
|
}
|
|
|
|
if let threadIdentifier = threadIdentifier {
|
|
bestAttemptContent.threadIdentifier = threadIdentifier
|
|
}
|
|
|
|
bestAttemptContent.title = title
|
|
// The call to contentHandler() needs to be done with a slight delay otherwise
|
|
// it will be killed before its finished removing the notifications
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
|
contentHandler(bestAttemptContent)
|
|
}
|
|
}
|
|
}
|
|
|
|
class ReplyableTask : TaskProtocol {
|
|
var payload: String
|
|
var contentHandler: ((UNNotificationContent) -> Void)?
|
|
var bestAttemptContent: UNMutableNotificationContent?
|
|
var logger: ServiceLogger
|
|
var successNotificationTitle: String
|
|
var failNotificationTitle: String
|
|
|
|
init(payload: String, logger: ServiceLogger, contentHandler: ((UNNotificationContent) -> Void)? = nil, bestAttemptContent: UNMutableNotificationContent? = nil, successNotificationTitle: String, failNotificationTitle: String) {
|
|
self.payload = payload
|
|
self.contentHandler = contentHandler
|
|
self.bestAttemptContent = bestAttemptContent
|
|
self.logger = logger
|
|
self.successNotificationTitle = successNotificationTitle;
|
|
self.failNotificationTitle = failNotificationTitle;
|
|
}
|
|
|
|
func start(liquidSDK: BindingLiquidSdk) throws {}
|
|
|
|
public func onEvent(e: SdkEvent) {}
|
|
|
|
func onShutdown() {
|
|
displayPushNotification(title: self.failNotificationTitle, logger: self.logger, threadIdentifier: Constants.NOTIFICATION_THREAD_REPLACEABLE)
|
|
}
|
|
|
|
func replyServer(encodable: Encodable, replyURL: String) {
|
|
guard let serverReplyURL = URL(string: replyURL) else {
|
|
self.displayPushNotification(title: self.failNotificationTitle, logger: self.logger, threadIdentifier: Constants.NOTIFICATION_THREAD_REPLACEABLE)
|
|
return
|
|
}
|
|
var request = URLRequest(url: serverReplyURL)
|
|
request.httpMethod = "POST"
|
|
request.httpBody = try! JSONEncoder().encode(encodable)
|
|
let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
|
let statusCode = (response as! HTTPURLResponse).statusCode
|
|
|
|
if statusCode == 200 {
|
|
self.displayPushNotification(title: self.successNotificationTitle, logger: self.logger, threadIdentifier: Constants.NOTIFICATION_THREAD_REPLACEABLE)
|
|
} else {
|
|
self.displayPushNotification(title: self.failNotificationTitle, logger: self.logger, threadIdentifier: Constants.NOTIFICATION_THREAD_REPLACEABLE)
|
|
return
|
|
}
|
|
}
|
|
task.resume()
|
|
}
|
|
}
|