This repository has been archived by the owner. It is now read-only.
Permalink
Cannot retrieve contributors at this time
155 lines (129 sloc)
4.85 KB
| /* This Source Code Form is subject to the terms of the Mozilla Public | |
| * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| import Foundation | |
| import Shared | |
| import Storage | |
| import XCGLogger | |
| import SwiftyJSON | |
| // Int64.max / 1000. | |
| private let MaxSecondsToConvertInt64: Int64 = 9223372036854775 | |
| private let MaxSecondsToConvertDouble: Double = Double(9223372036854775 as Int64) | |
| private let log = Logger.browserLogger | |
| open class TabsPayload: CleartextPayloadJSON { | |
| open class Tab { | |
| let title: String | |
| let urlHistory: [String] | |
| let lastUsed: Timestamp | |
| let icon: String? | |
| fileprivate init(title: String, urlHistory: [String], lastUsed: Timestamp, icon: String?) { | |
| self.title = title | |
| self.urlHistory = urlHistory | |
| self.lastUsed = lastUsed | |
| self.icon = icon | |
| } | |
| func toRemoteTabForClient(_ guid: GUID) -> RemoteTab? { | |
| let urls = urlHistory.compactMap({ $0.asURL }) | |
| if urls.isEmpty { | |
| log.debug("Bug 1201875 - Discarding tab as history has no conforming URLs.") | |
| return nil | |
| } | |
| return RemoteTab(clientGUID: guid, URL: urls[0], title: self.title, history: urls, lastUsed: self.lastUsed, icon: self.icon?.asURL) | |
| } | |
| class func remoteTabFromJSON(_ json: JSON, clientGUID: GUID) -> RemoteTab? { | |
| return fromJSON(json)?.toRemoteTabForClient(clientGUID) | |
| } | |
| class func fromJSON(_ json: JSON) -> Tab? { | |
| func getLastUsed(_ json: JSON) -> Timestamp? { | |
| let lastUsed = json["lastUsed"] | |
| if lastUsed.isBool() { | |
| return nil | |
| } | |
| // This might be a string or a number. | |
| if let num = lastUsed.int64 { | |
| if num < 0 { | |
| // Timestamps are unsigned. | |
| return nil | |
| } | |
| if num > MaxSecondsToConvertInt64 { | |
| // This will overflow when multiplied. | |
| return nil | |
| } | |
| return Timestamp(num * 1000) | |
| } | |
| if let num = lastUsed.double { | |
| if num < 0 { | |
| // Timestamps are unsigned. | |
| return nil | |
| } | |
| if num > MaxSecondsToConvertDouble { | |
| // This will overflow when multiplied. | |
| return nil | |
| } | |
| return Timestamp(num * 1000) | |
| } | |
| if let num = lastUsed.string { | |
| // Try parsing. | |
| return someKindOfTimestampStringToTimestamp(num) | |
| } | |
| return nil | |
| } | |
| if let title = json["title"].string, | |
| let urlHistory = jsonsToStrings(json["urlHistory"].array), | |
| let lastUsed = getLastUsed(json) { | |
| return Tab(title: title, urlHistory: urlHistory, lastUsed: lastUsed, icon: json["icon"].string) | |
| } | |
| return nil | |
| } | |
| } | |
| override open func isValid() -> Bool { | |
| if !super.isValid() { | |
| return false | |
| } | |
| if self["deleted"].bool ?? false { | |
| return true | |
| } | |
| return self["clientName"].isString() && | |
| self["tabs"].isArray() | |
| } | |
| // Eventually it'd be nice to unify RemoteTab and Tab. We want to kill the GUID in RemoteTab, | |
| // at which point the only distinction between the two is that RemoteTab is "simple" and | |
| // lives in Storage, and Tab is more closely tied to TabsPayload. | |
| var remoteTabs: [RemoteTab] { | |
| if let clientGUID = self["id"].string { | |
| let payloadTabs = self["tabs"].arrayValue | |
| let remoteTabs = payloadTabs.compactMap({ Tab.remoteTabFromJSON($0, clientGUID: clientGUID) }) | |
| if payloadTabs.count != remoteTabs.count { | |
| log.debug("Bug 1201875 - Missing remote tabs from sync") | |
| } | |
| return remoteTabs | |
| } | |
| log.debug("no client ID for remote tabs") | |
| return [] | |
| } | |
| var tabs: [Tab] { | |
| return self["tabs"].arrayValue.compactMap(Tab.fromJSON) | |
| } | |
| var clientName: String { | |
| return self["clientName"].string! | |
| } | |
| override open func equalPayloads(_ obj: CleartextPayloadJSON) -> Bool { | |
| if !(obj is TabsPayload) { | |
| return false | |
| } | |
| if !super.equalPayloads(obj) { | |
| return false | |
| } | |
| let p = obj as! TabsPayload | |
| if p.clientName != self.clientName { | |
| return false | |
| } | |
| // TODO: compare tabs. | |
| /* | |
| if p.tabs != self.tabs { | |
| return false; | |
| } | |
| */ | |
| return true | |
| } | |
| } |