// // InstanceFeatures.swift // Tusker // // Created by Shadowfacts on 1/23/22. // Copyright © 2022 Shadowfacts. All rights reserved. // import Foundation import Pachyderm struct InstanceFeatures { private static let pleromaVersionRegex = try! NSRegularExpression(pattern: "\\(compatible; Pleroma (.*)\\)") private(set) var instanceType = InstanceType.mastodon private(set) var version: Version? private(set) var pleromaVersion: Version? private(set) var maxStatusChars = 500 var localOnlyPosts: Bool { instanceType == .hometown || instanceType == .glitch } var mastodonAttachmentRestrictions: Bool { instanceType.isMastodon } var pollsAndAttachments: Bool { instanceType == .pleroma } var boostToOriginalAudience: Bool { instanceType == .pleroma } var profilePinnedStatuses: Bool { instanceType != .pixelfed } var trends: Bool { instanceType == .mastodon } var trendingStatusesAndLinks: Bool { instanceType == .mastodon && hasVersion(3, 5, 0) } var reblogVisibility: Bool { (instanceType == .mastodon && hasVersion(2, 8, 0)) || (instanceType == .pleroma && hasVersion(2, 0, 0)) } mutating func update(instance: Instance, nodeInfo: NodeInfo?) { let ver = instance.version.lowercased() if ver.contains("glitch") { instanceType = .glitch } else if nodeInfo?.software.name == "hometown" { instanceType = .hometown } else if ver.contains("pleroma") { instanceType = .pleroma } else if ver.contains("pixelfed") { instanceType = .pixelfed } else { instanceType = .mastodon } version = Version(string: ver) if let match = InstanceFeatures.pleromaVersionRegex.firstMatch(in: ver, range: NSRange(location: 0, length: ver.utf16.count)) { pleromaVersion = Version(string: (ver as NSString).substring(with: match.range(at: 1))) } maxStatusChars = instance.maxStatusCharacters ?? 500 } func hasVersion(_ major: Int, _ minor: Int, _ patch: Int) -> Bool { if let version { return version >= Version(major, minor, patch) } else { return false } } } extension InstanceFeatures { enum InstanceType: Equatable { case mastodon // vanilla case pleroma case hometown case glitch case pixelfed var isMastodon: Bool { switch self { case .mastodon, .hometown, .glitch: return true default: return false } } } } extension InstanceFeatures { struct Version: Equatable, Comparable { private static let regex = try! NSRegularExpression(pattern: "^(\\d+)\\.(\\d+)\\.(\\d+).*$") let major: Int let minor: Int let patch: Int init(_ major: Int, _ minor: Int, _ patch: Int) { self.major = major self.minor = minor self.patch = patch } init?(string: String) { guard let match = Version.regex.firstMatch(in: string, range: NSRange(location: 0, length: string.utf16.count)), match.numberOfRanges == 4 else { return nil } let majorStr = (string as NSString).substring(with: match.range(at: 1)) let minorStr = (string as NSString).substring(with: match.range(at: 2)) let patchStr = (string as NSString).substring(with: match.range(at: 3)) guard let major = Int(majorStr), let minor = Int(minorStr), let patch = Int(patchStr) else { return nil } self.major = major self.minor = minor self.patch = patch } static func ==(lhs: Version, rhs: Version) -> Bool { return lhs.major == rhs.major && lhs.minor == rhs.minor && lhs.patch == rhs.patch } static func < (lhs: InstanceFeatures.Version, rhs: InstanceFeatures.Version) -> Bool { if lhs.major < rhs.major { return true } else if lhs.major > rhs.major { return false } else if lhs.minor < rhs.minor { return true } else if lhs.minor > rhs.minor { return false } else if lhs.patch < rhs.patch { return true } else { return false } } } }