123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- // _____ _
- // |_ _| |_ _ _ ___ ___ _ __ __ _
- // | | | ' \| '_/ -_) -_) ' \/ _` |_
- // |_| |_||_|_| \___\___|_|_|_\__,_(_)
- //
- // 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
- protocol WebConnectionContextDelegate: class {
- func currentWCSession() -> WCSession
- }
- class WebConnectionContext: NSObject, NSCoding, NSCopying {
-
- var delegate: WebConnectionContextDelegate
- var chunkCache: WebChunkCache = WebChunkCache(sequenceNumber: WebSequenceNumber(minValue: 0, maxValue: UInt64(UINT32_MAX)))
- var connectionInfoRequest: WebUpdateConnectionInfoRequest?
- var unchunker: Unchunker = Unchunker()
- var messageCounter: UInt32 = 0
- var incomingSequenceNumber: UInt32 = 0
- var cacheTimer: Timer?
- var previousConnectionContext: WebConnectionContext? {
- get {
- return _previousContext
- }
- set(previous) {
- _previousContext = previous
- _previousContext?.previousConnectionContext = nil
- }
- }
-
- private var _connectionId: Data
- private var _previousContext: WebConnectionContext?
-
- init(connectionId:Data, delegate: WCConnection) {
- _connectionId = connectionId
- self.delegate = delegate
- }
-
- init(connectionId: Data, chunkCache: WebChunkCache, connectionInfoRequest: WebUpdateConnectionInfoRequest?, unchunker: Unchunker, messageCounter: UInt32, incomingSequenceNumber: UInt32, cacheTimer: Timer?, delegate: WCConnection) {
- self.chunkCache = chunkCache
- self.connectionInfoRequest = connectionInfoRequest
- self.unchunker = unchunker
- self.messageCounter = messageCounter
- self.incomingSequenceNumber = incomingSequenceNumber
- self.cacheTimer = cacheTimer
- self._connectionId = connectionId
- self.delegate = delegate
- }
-
- func connectionId() -> Data {
- return _connectionId
- }
-
- func runTimer() {
- cacheTimer?.invalidate()
- DispatchQueue.main.async {
- self.cacheTimer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(self.sendConnectionAck), userInfo: nil, repeats: true)
- }
- }
-
- func cancelTimer() {
- cacheTimer?.invalidate()
- cacheTimer = nil
- }
-
- @objc func sendConnectionAck() {
- let responseConnectionAck = WebConnectionAckUpdateResponse.init(requestId: nil, incomingSequenceNumber: incomingSequenceNumber)
- DDLogVerbose("Threema Web: MessagePack -> Send update/connectionAck")
- if delegate.currentWCSession().connectionStatus() == .ready {
- delegate.currentWCSession().sendMessageToWeb(blacklisted: true, msgpack: responseConnectionAck.messagePack())
- }
- }
-
- func transfer(fromCache: [[UInt8]?]) {
- chunkCache.transfer(fromCache: fromCache)
- }
-
- func append(chunk: [UInt8]?) {
- chunkCache.append(chunk: chunk)
- }
-
- func prune(theirSequenceNumber: UInt32) throws {
- try chunkCache.prune(theirSequenceNumber: theirSequenceNumber)
- }
-
- func updateUnchunker(oldUnchunker: Unchunker) {
- let unchunkerSerialize: [[UInt8]] = oldUnchunker.serialize()
- for chunk in unchunkerSerialize {
- let chunkData = Data.init(chunk)
- do {
- try unchunker.addChunk(bytes: chunkData)
- }
- catch {
- // error can't add old chunk
- }
- }
- }
-
- // MARK: NSCoding
- required init?(coder aDecoder: NSCoder) {
- // super.init(coder:) is optional, see notes below
- self.chunkCache = aDecoder.decodeObject(forKey: "chunkCache") as! WebChunkCache
- if let unchunkerSerialize = aDecoder.decodeObject(forKey: "unchunker") as? [[UInt8]] {
- for chunk in unchunkerSerialize {
- let chunkData = Data.init(chunk)
- do {
- try unchunker.addChunk(bytes: chunkData)
- }
- catch {
- // error can't add old chunk
- }
- }
- }
- self.messageCounter = UInt32(aDecoder.decodeInt32(forKey: "messageCounter"))
- self.incomingSequenceNumber = UInt32(aDecoder.decodeInt32(forKey: "incomingSequenceNumber"))
- self._connectionId = aDecoder.decodeObject(forKey: "_connectionId") as! Data
- if let previousContext = aDecoder.decodeObject(forKey: "previousConnectionContext") as? WebConnectionContext {
- self._previousContext = previousContext
- }
- self.delegate = aDecoder.decodeObject(forKey: "delegate") as! WebConnectionContextDelegate
- }
-
- func encode(with aCoder: NSCoder) {
- // super.encodeWithCoder(aCoder) is optional, see notes below
- aCoder.encode(chunkCache, forKey: "chunkCache")
- _ = unchunker.gc(maxAge: 20)
- aCoder.encode(unchunker.serialize(), forKey: "unchunker")
- aCoder.encode(Int32(messageCounter), forKey: "messageCounter")
- aCoder.encode(Int32(incomingSequenceNumber), forKey: "incomingSequenceNumber")
- aCoder.encode(_connectionId, forKey: "_connectionId")
- if _previousContext != nil {
- _previousContext!.previousConnectionContext = nil
- aCoder.encode(_previousContext, forKey: "previousConnectionContext")
- }
- aCoder.encode(delegate, forKey: "delegate")
- }
-
- func copy(with zone: NSZone? = nil) -> Any {
- let copy = WebConnectionContext.init(connectionId: _connectionId, chunkCache: chunkCache, connectionInfoRequest: connectionInfoRequest, unchunker: unchunker, messageCounter: messageCounter, incomingSequenceNumber: incomingSequenceNumber, cacheTimer: cacheTimer, delegate: delegate as! WCConnection)
- return copy
- }
- }
|