<commit_before>//
// Created by <NAME> on 8/29/18.
// Copyright © 2018 Particle. All rights reserved.
//

import UIKit
import SwiftProtobuf

typealias MeshSetupNetworkInfo = Particle_Ctrl_Mesh_NetworkInfo
typealias CloudConnectionStatus = Particle_Ctrl_Cloud_ConnectionStatus
typealias MeshSetupNetworkInterfaceEntry = Particle_Ctrl_InterfaceEntry
typealias MeshSetupNetworkInterface = Particle_Ctrl_Interface
typealias SystemCapability = Particle_Ctrl_SystemCapabilityFlag

class MeshSetupProtocolTransceiver: NSObject, MeshSetupBluetoothConnectionDataDelegate {

    private struct PendingMessage {
        var messageId: UInt16
        var data: Data
        var writeWithResponse: Bool
        var callback: (ReplyMessage?) -> ()
    }

    var isBusy: Bool {
        get {
            return waitingForReply
        }
    }

    private var bluetoothConnection: MeshSetupBluetoothConnection
    private var encryptionManager: MeshSetupEncryptionManager

    private var requestMessageId: UInt16 = 1
    private var waitingForReply: Bool = false

    private var pendingMessages: [PendingMessage] = []

    private var rxBuffer: Data = Data()


    var connection: MeshSetupBluetoothConnection {
        get {
            return bluetoothConnection
        }
    }

    func triggerTimeout() {
        if let callback = pendingMessages.first?.callback {

            //to avoid message idx getting out of sync with device
            requestMessageId = requestMessageId - UInt16(pendingMessages.count)

            pendingMessages.removeAll()
            waitingForReply = false
            callback(nil)
        }
    }


    required init(connection: MeshSetupBluetoothConnection) {
        self.bluetoothConnection = connection
        self.encryptionManager = MeshSetupEncryptionManager(derivedSecret: bluetoothConnection.derivedSecret!)

        super.init()

        self.bluetoothConnection.dataDelegate = self // take over didReceiveData delegate
    }

    private func log(_ message: String) {
        if (MeshSetup.LogTransceiver) {
            NSLog("MeshSetupTransceiverDelegate: \(message)")
        }
    }

    private func prepareRequestMessage(type: ControlRequestMessageType, payload: Data) -> (UInt16, Data) {
        let requestMsg = RequestMessage(id: self.requestMessageId, type: type, data: payload)

        // add to state machine dict to know which type of reply to deserialize
        //self.replyRequestTypeDict[requestMsg.id] = requestMsg.type

        let response = (self.requestMessageId, encryptionManager.encrypt(requestMsg))

        self.requestMessageId += 1
        if (requestMessageId >= 0xff00) {
            self.requestMessageId = 1
        }

        return response
    }

    private func sendRequestMessage(data: (UInt16, Data), onReply: @escaping (ReplyMessage?) -> ()) {
        if (self.bluetoothConnection.cbPeripheral.state == .disconnected || self.bluetoothConnection.cbPeripheral.state == .disconnecting) {
            self.requestMessageId -= 1 //to avoid message idx getting out of sync with device
            onReply(nil)
            return
        }

        self.pendingMessages.append(PendingMessage(messageId: data.0, data: data.1, writeWithResponse: true, callback: onReply))
        self.sendNextMessage()
    }

    private func sendOTARequestMessage(data: (UInt16, Data), onReply: @escaping (ReplyMessage?) -> ()) {
        if (self.bluetoothConnection.cbPeripheral.state == .disconnected || self.bluetoothConnection.cbPeripheral.state == .disconnecting) {
            self.requestMessageId -= 1 //to avoid message idx getting out of sync with device
            onReply(nil)
            return
        }

        self.pendingMessages.append(PendingMessage(messageId: data.0, data: data.1, writeWithResponse: false, callback: onReply))
        self.sendNextMessage()
    }

    private func sendNextMessage() {
        if self.pendingMessages.count > 0, self.waitingForReply == false {
            self.waitingForReply = true
            let message = self.pendingMessages.first!
            self.bluetoothConnection.send(data: message.data, writeType: message.writeWithResponse ? .withResponse : .withoutResponse)
        }
    }


    private func serialize(message: SwiftProtobuf.Message) -> Data {
        guard let messageData = try? message.serializedData() else {
            fatalError("Could not serialize protobuf \(type(of: message)) message")
        }

        return messageData
    }

    //MARK: MeshSetupBluetoothConnectionDataDelegate
    func bluetoothConnectionDidReceiveData(sender: MeshSetupBluetoothConnection, data: Data) {
        rxBuffer.append(contentsOf: data)

        //if received data is less than handshake data header length
        if (rxBuffer.count < 2) {
            return
        }

        //read the length of the message
        var length: Int16 = rxBuffer.withUnsafeBytes { (pointer: UnsafePointer<Int16>) -> Int16 in
            return Int16(pointer[0])
        }

        //we didn't receive the full message yet.
        if (rxBuffer.count < length + 16) {
            return
        }

        guard let pendingMessage = self.pendingMessages.first else {
            fatalError("This can't happen!")
        }

        let rm = encryptionManager.decrypt(data, messageId: pendingMessage.messageId)
        rxBuffer.removeAll()

        self.waitingForReply = false


<commit_msg>fix app crash when scanning networks with more than 5 networks in range<commit_after>//
// Created by <NAME> on 8/29/18.
// Copyright © 2018 Particle. All rights reserved.
//

import UIKit
import SwiftProtobuf

typealias MeshSetupNetworkInfo = Particle_Ctrl_Mesh_NetworkInfo
typealias CloudConnectionStatus = Particle_Ctrl_Cloud_ConnectionStatus
typealias MeshSetupNetworkInterfaceEntry = Particle_Ctrl_InterfaceEntry
typealias MeshSetupNetworkInterface = Particle_Ctrl_Interface
typealias SystemCapability = Particle_Ctrl_SystemCapabilityFlag

class MeshSetupProtocolTransceiver: NSObject, MeshSetupBluetoothConnectionDataDelegate {

    private struct PendingMessage {
        var messageId: UInt16
        var data: Data
        var writeWithResponse: Bool
        var callback: (ReplyMessage?) -> ()
    }

    var isBusy: Bool {
        get {
            return waitingForReply
        }
    }

    private var bluetoothConnection: MeshSetupBluetoothConnection
    private var encryptionManager: MeshSetupEncryptionManager

    private var requestMessageId: UInt16 = 1
    private var waitingForReply: Bool = false

    private var pendingMessages: [PendingMessage] = []

    private var rxBuffer: Data = Data()


    var connection: MeshSetupBluetoothConnection {
        get {
            return bluetoothConnection
        }
    }

    func triggerTimeout() {
        if let callback = pendingMessages.first?.callback {

            //to avoid message idx getting out of sync with device
            requestMessageId = requestMessageId - UInt16(pendingMessages.count)

            pendingMessages.removeAll()
            waitingForReply = false
            callback(nil)
        }
    }


    required init(connection: MeshSetupBluetoothConnection) {
        self.bluetoothConnection = connection
        self.encryptionManager = MeshSetupEncryptionManager(derivedSecret: bluetoothConnection.derivedSecret!)

        super.init()

        self.bluetoothConnection.dataDelegate = self // take over didReceiveData delegate
    }

    private func log(_ message: String) {
        if (MeshSetup.LogTransceiver) {
            NSLog("MeshSetupTransceiverDelegate: \(message)")
        }
    }

    private func prepareRequestMessage(type: ControlRequestMessageType, payload: Data) -> (UInt16, Data) {
        let requestMsg = RequestMessage(id: self.requestMessageId, type: type, data: payload)

        // add to state machine dict to know which type of reply to deserialize
        //self.replyRequestTypeDict[requestMsg.id] = requestMsg.type

        let response = (self.requestMessageId, encryptionManager.encrypt(requestMsg))

        self.requestMessageId += 1
        if (requestMessageId >= 0xff00) {
            self.requestMessageId = 1
        }

        return response
    }

    private func sendRequestMessage(data: (UInt16, Data), onReply: @escaping (ReplyMessage?) -> ()) {
        if (self.bluetoothConnection.cbPeripheral.state == .disconnected || self.bluetoothConnection.cbPeripheral.state == .disconnecting) {
            self.requestMessageId -= 1 //to avoid message idx getting out of sync with device
            onReply(nil)
            return
        }

        self.pendingMessages.append(PendingMessage(messageId: data.0, data: data.1, writeWithResponse: true, callback: onReply))
        self.sendNextMessage()
    }

    private func sendOTARequestMessage(data: (UInt16, Data), onReply: @escaping (ReplyMessage?) -> ()) {
        if (self.bluetoothConnection.cbPeripheral.state == .disconnected || self.bluetoothConnection.cbPeripheral.state == .disconnecting) {
            self.requestMessageId -= 1 //to avoid message idx getting out of sync with device
            onReply(nil)
            return
        }

        self.pendingMessages.append(PendingMessage(messageId: data.0, data: data.1, writeWithResponse: false, callback: onReply))
        self.sendNextMessage()
    }

    private func sendNextMessage() {
        if self.pendingMessages.count > 0, self.waitingForReply == false {
            self.waitingForReply = true
            let message = self.pendingMessages.first!
            self.bluetoothConnection.send(data: message.data, writeType: message.writeWithResponse ? .withResponse : .withoutResponse)
        }
    }


    private func serialize(message: SwiftProtobuf.Message) -> Data {
        guard let messageData = try? message.serializedData() else {
            fatalError("Could not serialize protobuf \(type(of: message)) message")
        }

        return messageData
    }

    //MARK: MeshSetupBluetoothConnectionDataDelegate
    func bluetoothConnectionDidReceiveData(sender: MeshSetupBluetoothConnection, data: Data) {
        rxBuffer.append(contentsOf: data)

        //if received data is less than handshake data header length
        if (rxBuffer.count < 2) {
            return
        }

        //read the length of the message
        var length: Int16 = rxBuffer.withUnsafeBytes { (pointer: UnsafePointer<Int16>) -> Int16 in
            return Int16(pointer[0])
        }

        //we didn't receive the full message yet.
        if (rxBuffer.count < length + 16) {
            return
        }

        guard let pendingMessage = self.pendingMessages.first else {
            fatalError("This can't happen!")
        }

        let rm = encryptionManager.decrypt(rxBuffer, messageId: pendingMessage.messageId)
        rxBuffer.removeAll()

        self.waitingForReply = false



{'fraction_non_alphanumeric': 0.07937384898710866, 'fraction_numerical': 0.00856353591160221, 'mean_word_length': 2.762036716314513, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5320606', 'n_tokens_mistral': 2916, 'n_tokens_neox': 2756, 'n_words': 730}