[ABANDONED] Mastodon iOS client.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

235 lines
8.8 KiB

//
// InstancesDataManager.swift
// elpha-ios
//
// Created by Dwayne Harris on 9/18/18.
// Copyright © 2018 Elpha. All rights reserved.
//
import CoreData
import Foundation
import UIKit
class InstancesDataManager {
static let shared = InstancesDataManager()
let instanceRequestCount = 20
var instances: [ISInstanceMO] = []
var finished = false
var nextID: String? = nil
static func upsertLanguage(string: String) -> ISLanguageMO? {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let request = NSFetchRequest<ISLanguageMO>(entityName: "ISLanguage")
request.predicate = NSPredicate(format: "id == %@", string)
do {
let results: [ISLanguageMO] = try context.fetch(request)
switch results.count {
case 0:
let language = ISLanguageMO(context: context)
language.id = string
try context.save()
return language
case 1:
return results.first
default:
print("Duplicate ISLanguage entity")
return nil
}
} catch {
print("\(error)")
return nil
}
}
static func upsertCategory(string: String) -> ISCategoryMO? {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let request = NSFetchRequest<ISCategoryMO>(entityName: "ISCategory")
request.predicate = NSPredicate(format: "id == %@", string)
do {
let results: [ISCategoryMO] = try context.fetch(request)
switch results.count {
case 0:
let category = ISCategoryMO(context: context)
category.id = string
try context.save()
return category
case 1:
return results.first
default:
print("Duplicate ISCategory entity")
return nil
}
} catch {
print("\(error)")
return nil
}
}
static func setAttributes(on i: ISInstanceMO, attributes: [String: Any]) {
guard let id = attributes["id"] as? String, let name = attributes["name"] as? String else {
print("Error")
return
}
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
i.id = id
i.name = name
i.url = URL(string: "https://\(name)")!
i.uptime = attributes["uptime"] as! Int32
i.up = attributes["up"] as! Bool
i.dead = attributes["dead"] as! Bool
i.version = attributes["version"] as? String
i.ipv6 = attributes["ipv6"] as! Bool
i.users = Int64(attributes["users"] as! String)!
i.statuses = Int64(attributes["statuses"] as! String)!
i.connections = Int64(attributes["connections"] as! String)!
i.openRegistrations = attributes["open_registrations"] as! Bool
if let activeUsers = attributes["active_users"] as? Int64 {
i.activeUsers = activeUsers
}
if let updatedAt = attributes["updated_at"] as? String {
i.updatedAt = dateFormatter.date(from: updatedAt)
}
if let checkedAt = attributes["checked_at"] as? String {
i.checkedAt = dateFormatter.date(from: checkedAt)
}
if let thumbnail = attributes["thumbnail"] as? String {
i.thumbnail = URL(string: thumbnail)!
}
if let info = attributes["info"] as? [String: Any] {
i.shortDesc = info["short_description"] as? String
i.fullDescription = info["full_description"] as? String
i.topic = info["topic"] as? String
for language in info["languages"] as! [String] {
if let l = upsertLanguage(string: language) {
i.mutableSetValue(forKey: "languages").add(l)
}
}
for category in info["categories"] as! [String] {
if let c = upsertCategory(string: category) {
i.mutableSetValue(forKey: "categories").add(c)
}
}
}
}
func reloadInstances(completion: @escaping (Error?) -> Void) {
finished = false
nextID = nil
loadInstances(completion: completion)
}
func loadInstances(completion: @escaping (Error?) -> Void) {
var params = [
"count=\(instanceRequestCount)",
"sort_by=users",
"sort_order=desc",
"include_closed=true",
"include_down=false",
]
if let nextID = nextID {
params.append("min_id=\(nextID)")
}
let requestURL = "\(Config.instancesServiceUrl)\(Config.instancesServiceEndpoint)?\(params.joined(separator: "&"))"
print("loading instances: requestURL: \(requestURL)")
var request = URLRequest(url: URL(string: requestURL)!)
request.addValue("Bearer \(Config.instancesServiceSecret)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { data, response, error in
guard error == nil else {
completion(error)
return
}
guard let response = response as? HTTPURLResponse else {
print("No HTTP response")
completion(NSError())
return
}
switch response.statusCode {
case 200..<300:
guard let data = data else {
print("No HTTP response")
completion(NSError())
return
}
DispatchQueue.main.async {
do {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let instancesResult = try JSONSerialization.jsonObject(with: data) as! [String: Any]
if let pagination = instancesResult["pagination"] as? [String: Any] {
if let nextID = pagination["next_id"] as? String {
self.nextID = nextID
} else {
self.nextID = nil
self.finished = true
}
}
if let instances = instancesResult["instances"] as? [Any] {
for case let instance as [String: Any] in instances {
if let id = instance["id"] as? String {
let request = NSFetchRequest<ISInstanceMO>(entityName: "ISInstance")
request.predicate = NSPredicate(format: "id == %@", id)
let results: [ISInstanceMO] = try context.fetch(request)
switch results.count {
case 0:
let i = ISInstanceMO(context: context)
InstancesDataManager.setAttributes(on: i, attributes: instance)
case 1:
if let i = results.first {
InstancesDataManager.setAttributes(on: i, attributes: instance)
}
default:
print("Duplicate Instance entity")
}
}
}
do {
try context.save()
} catch {
completion(error)
return
}
}
completion(nil)
} catch {
completion(error)
return
}
}
case 400:
print("instances.social: 400")
completion(NSError())
default:
completion(nil)
return
}
}.resume()
}
}