2020-04-04 02:33:41 -05:00
|
|
|
//
|
|
|
|
// CloudKitPublicZone.swift
|
|
|
|
// Account
|
|
|
|
//
|
|
|
|
// Created by Maurice Parker on 4/4/20.
|
|
|
|
// Copyright © 2020 Ranchero Software, LLC. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
import CloudKit
|
|
|
|
import os.log
|
|
|
|
|
|
|
|
final class CloudKitPublicZone: CloudKitZone {
|
|
|
|
|
|
|
|
static var zoneID: CKRecordZone.ID {
|
|
|
|
return CKRecordZone.default().zoneID
|
|
|
|
}
|
|
|
|
|
|
|
|
var log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "CloudKit")
|
|
|
|
|
|
|
|
weak var container: CKContainer?
|
|
|
|
weak var database: CKDatabase?
|
|
|
|
var delegate: CloudKitZoneDelegate?
|
|
|
|
|
|
|
|
struct CloudKitWebFeed {
|
|
|
|
static let recordType = "WebFeed"
|
|
|
|
struct Fields {
|
|
|
|
static let url = "url"
|
|
|
|
static let httpLastModified = "httpLastModified"
|
|
|
|
static let httpEtag = "httpEtag"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-04 15:04:38 -05:00
|
|
|
struct CloudKitWebFeedCheck {
|
2020-04-04 13:33:49 -05:00
|
|
|
static let recordType = "WebFeedCheck"
|
|
|
|
struct Fields {
|
|
|
|
static let webFeed = "webFeed"
|
|
|
|
static let lastCheck = "lastCheck"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-04 02:33:41 -05:00
|
|
|
struct CloudKitUserSubscription {
|
|
|
|
static let recordType = "UserSubscription"
|
|
|
|
struct Fields {
|
2020-04-04 13:33:49 -05:00
|
|
|
static let userRecordID = "userRecordID"
|
2020-04-04 02:33:41 -05:00
|
|
|
static let webFeed = "webFeed"
|
|
|
|
static let subscriptionID = "subscriptionID"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-04 05:02:33 -05:00
|
|
|
init(container: CKContainer) {
|
|
|
|
self.container = container
|
|
|
|
self.database = container.publicCloudDatabase
|
|
|
|
}
|
|
|
|
|
2020-04-04 13:33:49 -05:00
|
|
|
func subscribeToZoneChanges() {}
|
2020-04-04 02:33:41 -05:00
|
|
|
|
|
|
|
func receiveRemoteNotification(userInfo: [AnyHashable : Any], completion: @escaping () -> Void) {
|
2020-04-04 05:15:43 -05:00
|
|
|
completion()
|
2020-04-04 02:33:41 -05:00
|
|
|
}
|
|
|
|
|
2020-04-04 15:04:38 -05:00
|
|
|
/// Create a CloudKit subscription for the webfeed and any other supporting records that we need
|
2020-04-04 05:15:43 -05:00
|
|
|
func createSubscription(_ webFeed: WebFeed, completion: @escaping (Result<Void, Error>) -> Void) {
|
2020-04-04 13:33:49 -05:00
|
|
|
|
2020-04-04 15:04:38 -05:00
|
|
|
func createSubscription(_ webFeedRecordRef: CKRecord.Reference) {
|
|
|
|
let predicate = NSPredicate(format: "webFeed = %@", webFeedRecordRef)
|
|
|
|
let subscription = CKQuerySubscription(recordType: CloudKitWebFeed.recordType, predicate: predicate, options: [.firesOnRecordUpdate])
|
|
|
|
|
|
|
|
let info = CKSubscription.NotificationInfo()
|
|
|
|
info.shouldSendContentAvailable = true
|
|
|
|
info.desiredKeys = [CloudKitWebFeed.Fields.httpLastModified, CloudKitWebFeed.Fields.httpEtag]
|
|
|
|
subscription.notificationInfo = info
|
|
|
|
|
|
|
|
self.save(subscription) { result in
|
|
|
|
switch result {
|
|
|
|
case .success(let subscription):
|
|
|
|
|
|
|
|
let userSubscriptionRecord = CKRecord(recordType: CloudKitUserSubscription.recordType, recordID: self.generateRecordID())
|
|
|
|
userSubscriptionRecord[CloudKitUserSubscription.Fields.userRecordID] = self.container?.userRecordID
|
|
|
|
userSubscriptionRecord[CloudKitUserSubscription.Fields.webFeed] = webFeedRecordRef
|
|
|
|
userSubscriptionRecord[CloudKitUserSubscription.Fields.subscriptionID] = subscription.subscriptionID
|
|
|
|
|
|
|
|
self.save(userSubscriptionRecord, completion: completion)
|
|
|
|
|
|
|
|
case .failure(let error):
|
|
|
|
completion(.failure(error))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fetch(externalID: webFeed.url.md5String) { result in
|
2020-04-04 13:33:49 -05:00
|
|
|
switch result {
|
2020-04-04 15:04:38 -05:00
|
|
|
case .success(let record):
|
2020-04-04 13:33:49 -05:00
|
|
|
|
2020-04-04 15:04:38 -05:00
|
|
|
let webFeedRecordRef = CKRecord.Reference(record: record, action: .none)
|
|
|
|
createSubscription(webFeedRecordRef)
|
2020-04-04 13:33:49 -05:00
|
|
|
|
2020-04-04 15:04:38 -05:00
|
|
|
case .failure:
|
2020-04-04 13:33:49 -05:00
|
|
|
|
2020-04-04 15:04:38 -05:00
|
|
|
let webFeedRecordID = CKRecord.ID(recordName: webFeed.url.md5String, zoneID: Self.zoneID)
|
|
|
|
let webFeedRecordRef = CKRecord.Reference(recordID: webFeedRecordID, action: .none)
|
|
|
|
let webFeedRecord = CKRecord(recordType: CloudKitWebFeed.recordType, recordID: webFeedRecordID)
|
|
|
|
webFeedRecord[CloudKitWebFeed.Fields.url] = webFeed.url
|
|
|
|
webFeedRecord[CloudKitWebFeed.Fields.httpLastModified] = ""
|
|
|
|
webFeedRecord[CloudKitWebFeed.Fields.httpEtag] = ""
|
|
|
|
|
|
|
|
let webFeedCheckRecord = CKRecord(recordType: CloudKitWebFeedCheck.recordType, recordID: self.generateRecordID())
|
|
|
|
webFeedRecord[CloudKitWebFeedCheck.Fields.webFeed] = webFeedRecordRef
|
|
|
|
webFeedRecord[CloudKitWebFeedCheck.Fields.lastCheck] = Date.distantPast
|
2020-04-04 13:33:49 -05:00
|
|
|
|
2020-04-04 15:04:38 -05:00
|
|
|
self.save([webFeedRecord, webFeedCheckRecord]) { result in
|
|
|
|
switch result {
|
|
|
|
case .success:
|
|
|
|
createSubscription(webFeedRecordRef)
|
2020-04-04 13:33:49 -05:00
|
|
|
case .failure(let error):
|
|
|
|
completion(.failure(error))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2020-04-04 15:04:38 -05:00
|
|
|
|
2020-04-04 05:15:43 -05:00
|
|
|
}
|
2020-04-04 05:02:33 -05:00
|
|
|
|
2020-04-04 13:33:49 -05:00
|
|
|
/// Remove the subscription for the given feed along with its supporting record
|
2020-04-04 05:15:43 -05:00
|
|
|
func removeSubscription(_ webFeed: WebFeed, completion: @escaping (Result<Void, Error>) -> Void) {
|
2020-04-04 15:04:38 -05:00
|
|
|
guard let userRecordID = self.container?.userRecordID else {
|
2020-04-04 13:33:49 -05:00
|
|
|
completion(.failure(CloudKitZoneError.invalidParameter))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
let webFeedRecordID = CKRecord.ID(recordName: webFeed.url.md5String, zoneID: Self.zoneID)
|
|
|
|
let webFeedRecordRef = CKRecord.Reference(recordID: webFeedRecordID, action: .none)
|
2020-04-04 15:04:38 -05:00
|
|
|
let predicate = NSPredicate(format: "userRecordID = %@ AND webFeed = %@", userRecordID, webFeedRecordRef)
|
2020-04-04 13:33:49 -05:00
|
|
|
let ckQuery = CKQuery(recordType: CloudKitUserSubscription.recordType, predicate: predicate)
|
|
|
|
|
|
|
|
query(ckQuery) { result in
|
|
|
|
switch result {
|
|
|
|
case .success(let records):
|
|
|
|
|
|
|
|
if records.count > 0, let subscriptionID = records[0][CloudKitUserSubscription.Fields.subscriptionID] as? String {
|
|
|
|
self.delete(subscriptionID: subscriptionID) { result in
|
|
|
|
switch result {
|
|
|
|
case .success:
|
|
|
|
self.delete(recordID: records[0].recordID, completion: completion)
|
|
|
|
case .failure(let error):
|
|
|
|
completion(.failure(error))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
2020-04-04 15:04:38 -05:00
|
|
|
os_log(.error, log: self.log, "Remove subscription error. The subscription wasn't found.")
|
|
|
|
completion(.success(()))
|
2020-04-04 13:33:49 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
case .failure(let error):
|
|
|
|
completion(.failure(error))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-04 05:02:33 -05:00
|
|
|
}
|
|
|
|
|
2020-04-04 02:33:41 -05:00
|
|
|
}
|