123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- // _____ _
- // |_ _| |_ _ _ ___ ___ _ __ __ _
- // | | | ' \| '_/ -_) -_) ' \/ _` |_
- // |_| |_||_|_| \___\___|_|_|_\__,_(_)
- //
- // Threema iOS Client
- // Copyright (c) 2018-2020 Threema GmbH
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Affero General Public License, version 3,
- // as published by the Free Software Foundation.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Affero General Public License for more details.
- //
- // You should have received a copy of the GNU Affero General Public License
- // along with this program. If not, see <https://www.gnu.org/licenses/>.
- import Foundation
- import CocoaLumberjackSwift
- class WebUpdateConnectionInfoRequest: NSObject, NSCoding {
-
- let id: Data
- let resume: WebConnection?
-
- init(message:WebAbstractMessage) {
- let data = message.data as! [AnyHashable: Any?]
- id = data["id"] as! Data
- if let tmpResume = data["resume"] as? [String: Any] {
- resume = WebConnection.init(connection: tmpResume)
- } else {
- resume = nil
- }
- }
-
- func maybeResume(session: WCSession) {
- if let connectionInfoResponse = session.connectionInfoResponse() {
- if connectionInfoResponse.id != id {
- ValidationLogger.shared().logString("Threema Web: Wrong connection id, stop session.")
- session.stop(close: true, forget: false, sendDisconnect: true, reason: .error)
- return
- }
-
- if resume != nil, let context = session.connectionContext() {
- if context.previousConnectionContext?.connectionId() == resume!.id {
- do {
- // should be previousContext
- try context.previousConnectionContext?.prune(theirSequenceNumber: resume!.sequenceNumber!)
- }
- catch {
- // do error stuff
- ValidationLogger.shared().logString("Threema Web: Could not prune cache: \(error).")
- session.stop(close: true, forget: false, sendDisconnect: true, reason: .error)
- return
- }
-
- if session.connectionStatus() == .ready {
- if context.previousConnectionContext != nil {
- context.transfer(fromCache: context.previousConnectionContext!.chunkCache.chunks())
- ValidationLogger.shared().logString("Threema Web: Transfer \(context.chunkCache.chunks().count) chunks.")
- for chunk in context.chunkCache.chunks() {
- session.sendChunk(chunk: chunk!, msgpack: nil, connectionInfo: false)
- }
- context.updateUnchunker(oldUnchunker: context.previousConnectionContext!.unchunker)
- context.previousConnectionContext = nil
- }
- session.messageQueue.processQueue()
- context.runTimer()
- }
- ValidationLogger.shared().logString("Threema Web: Resume connection.")
- let responseBatteryStatus = WebBatteryStatusUpdate.init()
- session.sendMessageToWeb(blacklisted: true, msgpack: responseBatteryStatus.messagePack())
- DDLogVerbose("Threema Web: MessagePack -> Send update/batteryStatus")
- return
- }
- }
-
- if resume == nil {
- ValidationLogger.shared().logString("Threema Web: Resume is nil.")
- }
- if session.connectionContext() == nil {
- ValidationLogger.shared().logString("Threema Web: Connection context is nil.")
- }
- // do not resume
- session.clearAllRequestedLists()
- if session.connectionStatus() == .ready {
- ValidationLogger.shared().logString("Threema Web: Connection state is ready -> process queue and reset previous connection context.")
- session.messageQueue.processQueue()
- session.connectionContext()?.previousConnectionContext = nil
- session.connectionContext()?.runTimer()
- }
- return
- }
- }
-
- required init?(coder aDecoder: NSCoder) {
- self.id = aDecoder.decodeObject(forKey: "id") as! Data
- self.resume = aDecoder.decodeObject(forKey: "resume") as? WebConnection
- }
-
- func encode(with aCoder: NSCoder) {
- aCoder.encode(id, forKey: "id")
- aCoder.encode(resume, forKey: "resume")
- }
- }
- class WebConnection: NSObject, NSCoding {
- var id: Data
- var sequenceNumber: UInt32? // chunk id
-
- init(connection:[String: Any]) {
- id = connection["id"] as! Data
- if connection["sequenceNumber"] != nil {
- sequenceNumber = WebConnection.convertToUInt32(sn: connection["sequenceNumber"]!)
- }
- }
-
- // MARK: NSCoding
- required public init?(coder aDecoder: NSCoder) {
- self.id = aDecoder.decodeObject(forKey: "id") as! Data
- self.sequenceNumber = UInt32(aDecoder.decodeInt32(forKey: "sequenceNumber"))
- }
-
- public func encode(with aCoder: NSCoder) {
- aCoder.encode(id, forKey: "id")
- if sequenceNumber != nil {
- aCoder.encode(Int32(sequenceNumber!), forKey: "sequenceNumber")
- }
- }
-
- func objectDict() -> [String: Any] {
- return ["id": id, "sequenceNumber": sequenceNumber ?? 0]
- }
-
- class func convertToUInt32(sn: Any) -> UInt32 {
- var converted: UInt32 = 0
- if let sq = sn as? UInt8 {
- converted = UInt32(sq)
- }
- else if let sq = sn as? Int8 {
- converted = UInt32(sq)
- }
- else if let sq = sn as? UInt16 {
- converted = UInt32(sq)
- }
- else if let sq = sn as? Int16 {
- converted = UInt32(sq)
- }
- else if let sq = sn as? UInt32 {
- converted = sq
- }
- else if let sq = sn as? Int32 {
- converted = UInt32(sq)
- }
- else if let sq = sn as? UInt64 {
- if sq > UINT32_MAX {
- // error
- } else {
- converted = UInt32(sq)
- }
- }
- else if let sq = sn as? Int64 {
- if sq > UINT32_MAX {
- // error
- } else {
- converted = UInt32(sq)
- }
- }
- else {
- // error
- }
- return converted
- }
- }
- extension Data {
-
- /// Hexadecimal string representation of `Data` object.
-
- var hexadecimal: String {
- return map { String(format: "%02x", $0) }
- .joined()
- }
- }
|