<commit_before>﻿// Copyright 2014-2019 Sound Metrics Corp. All Rights Reserved.

namespace SoundMetrics.Common

open ArisBeaconDetails
open SoundMetrics.Network
open System

module internal BeaconListener =
    open System.Collections.ObjectModel
    open Serilog
    open Serilog.Events

    type SonarAvailability  = Aris.Availability
    type DefenderAvailability = Defender.Availability
    type CMBeacon = Aris.CommandModuleBeacon
    type ProtobufSystemType = Aris.Availability.Types.SystemType

    let toSoftwareVersion (ver: SonarAvailability.Types.SoftwareVersion) =
        { Major = int ver.Major; Minor = int ver.Minor; BuildNumber = int ver.Buildnumber }

    let toDefenderSoftwareVersion (ver: DefenderAvailability.Types.SoftwareVersion) =
        { Major = int ver.Major; Minor = int ver.Minor; BuildNumber = int ver.Buildnumber }

    let toArisExplorerOrVoyagerBeacon (pkt : UdpReceived) : ArisBeacon option =
        try
            let av = SonarAvailability.Parser.ParseFrom(pkt.UdpResult.Buffer)
            let beacon =
                let model =
                    defaultArg
                        (av.SystemVariants // possibly null
                            |> Option.ofObj
                            |> Option.map (fun variants ->
                                if variants.Enabled |> Seq.contains VoyagerVariant then
                                    Voyager
                                else
                                    Explorer
                            ))
                        Explorer

                {
                    Model =             model
                    SystemType =        enum (int av.SystemType)
                    SerialNumber =      av.SerialNumber
                    SoftwareVersion =   toSoftwareVersion av.SoftwareVersion
                    Timestamp =         pkt.Timestamp
                    IPAddress =         pkt.UdpResult.RemoteEndPoint.Address
                    ConnectionState =   enum (int av.ConnectionState)
                    CpuTemp =           av.CpuTemp
                }
            Some beacon
        with
            _ -> None

    let toArisDefenderBeacon (pkt : UdpReceived) : ArisBeacon option =
        try
            let av = DefenderAvailability.Parser.ParseFrom(pkt.UdpResult.Buffer)
            let defenderState = {
                RecordState =   enum (int av.RecordState)
                StorageState =  enum (int av.StorageState)
                StorageLevel =  av.StorageLevel
                BatteryState =  enum (int av.BatteryState)
                BatteryLevel =  av.BatteryLevel
            }

            let beacon =
                {
                    Model =             Defender defenderState
                    SystemType =    enum (int av.SystemType)
                    SerialNumber =      av.SerialNumber
                    SoftwareVersion =   toDefenderSoftwareVersion av.SoftwareVersion
                    Timestamp =         pkt.Timestamp
                    IPAddress =         pkt.UdpResult.RemoteEndPoint.Address
                    ConnectionState =   enum (int av.ConnectionState)
                    CpuTemp =           Single.NaN
                }
            Some beacon
        with
            _ -> None

    let toArisCommandModuleBeacon (pkt : UdpReceived) : ArisCommandModuleBeacon option =

        try
            let cms = Aris.CommandModuleBeacon.Parser.ParseFrom(pkt.UdpResult.Buffer)
            let beacon =
                {
                    IPAddress = pkt.UdpResult.RemoteEndPoint.Address
                    ArisCurrent =   cms.ArisCurrent
                    ArisPower =     cms.ArisPower
                    ArisVoltage =   cms.ArisVoltage
                    CpuTemp =       cms.CpuTemp
                    Revision =      cms.Revision
                    Timestamp =     pkt.Timestamp
                }

            if Log.IsEnabled(LogEventLevel.Verbose) then
                Log.Verbose("CM Beacon: {cmBeacon}", sprintf "%A" beacon)
            Some beacon
        with
            _ -> None


    let inline addOrUpdateBeacon (beacons : ObservableCollection<'B>)
                                 (isSame : 'B -> 'B -> bool)
                                 (isLess : 'B -> 'B -> bool)
                                 (updateB : 'B) =
        // N is small, so just operate linearly.
        let indexedBeacons = beacons |> Seq.mapi (fun i b -> i, b) |> Seq.cache

        match indexedBeacons |> Seq.tryFind (fun (_, b) -> isSame b updateB) with
        | Some (i, _) -> beacons.[i] <- updateB
        | None ->
            match indexedBeacons |> Seq.tryFind (fun (_, b) -> isLess updateB b) with
            | Some (i, _) -> beacons.Insert(i, updateB)
            | None -> beacons.Add(updateB)

    let processExplorerBeaconPacket (collection : ObservableCollection<ArisBeacon>)
                                    (shouldInclude : NetworkDevice -> bool)
                                    (pkt : UdpReceived) =

            match toArisExplorerOrVoyagerBeacon pkt with<commit_msg>Add temporary logging to collect debugging data<commit_after>﻿// Copyright 2014-2019 Sound Metrics Corp. All Rights Reserved.

namespace SoundMetrics.Common

open ArisBeaconDetails
open SoundMetrics.Network
open System

module internal BeaconListener =
    open System.Collections.ObjectModel
    open Serilog
    open Serilog.Events

    type SonarAvailability  = Aris.Availability
    type DefenderAvailability = Defender.Availability
    type CMBeacon = Aris.CommandModuleBeacon
    type ProtobufSystemType = Aris.Availability.Types.SystemType

    let toSoftwareVersion (ver: SonarAvailability.Types.SoftwareVersion) =
        { Major = int ver.Major; Minor = int ver.Minor; BuildNumber = int ver.Buildnumber }

    let toDefenderSoftwareVersion (ver: DefenderAvailability.Types.SoftwareVersion) =
        { Major = int ver.Major; Minor = int ver.Minor; BuildNumber = int ver.Buildnumber }

    let toArisExplorerOrVoyagerBeacon (pkt : UdpReceived) : ArisBeacon option =
        try
            let av = SonarAvailability.Parser.ParseFrom(pkt.UdpResult.Buffer)
            let beacon =
                let model =
                    defaultArg
                        (av.SystemVariants // possibly null
                            |> Option.ofObj
                            |> Option.map (fun variants ->
                                if variants.Enabled |> Seq.contains VoyagerVariant then
                                    Voyager
                                else
                                    Explorer
                            ))
                        Explorer

                {
                    Model =             model
                    SystemType =        enum (int av.SystemType)
                    SerialNumber =      av.SerialNumber
                    SoftwareVersion =   toSoftwareVersion av.SoftwareVersion
                    Timestamp =         pkt.Timestamp
                    IPAddress =         pkt.UdpResult.RemoteEndPoint.Address
                    ConnectionState =   enum (int av.ConnectionState)
                    CpuTemp =           av.CpuTemp
                }
            Some beacon
        with
            _ -> None

    let toArisDefenderBeacon (pkt : UdpReceived) : ArisBeacon option =
        try
            let av = DefenderAvailability.Parser.ParseFrom(pkt.UdpResult.Buffer)
            let defenderState = {
                RecordState =   enum (int av.RecordState)
                StorageState =  enum (int av.StorageState)
                StorageLevel =  av.StorageLevel
                BatteryState =  enum (int av.BatteryState)
                BatteryLevel =  av.BatteryLevel
            }

            let beacon =
                {
                    Model =             Defender defenderState
                    SystemType =    enum (int av.SystemType)
                    SerialNumber =      av.SerialNumber
                    SoftwareVersion =   toDefenderSoftwareVersion av.SoftwareVersion
                    Timestamp =         pkt.Timestamp
                    IPAddress =         pkt.UdpResult.RemoteEndPoint.Address
                    ConnectionState =   enum (int av.ConnectionState)
                    CpuTemp =           Single.NaN
                }
            Some beacon
        with
            _ -> None

    let toArisCommandModuleBeacon (pkt : UdpReceived) : ArisCommandModuleBeacon option =

        try
            let cms = Aris.CommandModuleBeacon.Parser.ParseFrom(pkt.UdpResult.Buffer)
            let beacon =
                {
                    IPAddress = pkt.UdpResult.RemoteEndPoint.Address
                    ArisCurrent =   cms.ArisCurrent
                    ArisPower =     cms.ArisPower
                    ArisVoltage =   cms.ArisVoltage
                    CpuTemp =       cms.CpuTemp
                    Revision =      cms.Revision
                    Timestamp =     pkt.Timestamp
                }

            if Log.IsEnabled(LogEventLevel.Verbose) then
                Log.Verbose("CM Beacon, length of {length}: {cmBeacon}",
                    pkt.UdpResult.Buffer.Length, sprintf "%A" beacon)
                let bytes =
                    let ss =
                        pkt.UdpResult.Buffer
                        |> Seq.map (fun b -> sprintf "0x%X" b)
                    String.Join(", ", ss)

                Log.Verbose("bytes: {bytes}", bytes)
            Some beacon
        with
            _ -> None


    let inline addOrUpdateBeacon (beacons : ObservableCollection<'B>)
                                 (isSame : 'B -> 'B -> bool)
                                 (isLess : 'B -> 'B -> bool)
                                 (updateB : 'B) =
        // N is small, so just operate linearly.
        let indexedBeacons = beacons |> Seq.mapi (fun i b -> i, b) |> Seq.cache

        match indexedBeacons |> Seq.tryFind (fun (_, b) -> isSame b updateB) with
        | Some (i, _) -> beacons.[i] <- updateB
        | None ->
            match indexedBeacons |> Seq.tryFind (fun (_, b) -> isLess updateB b) with
            | Some (i, _) -> beacons.Insert(i, updateB)
            | None -> beacons.Add(updateB)

    let processExplorerBeaconPacket (collection : ObservableCollection<ArisBeacon>)
                                    (shouldInclude : NetworkDevice -> bool)
                                    (pkt : UdpReceived) =

            match toArisExplorerOrVoyagerBeacon pkt with
{'fraction_non_alphanumeric': 0.06660949113779302, 'fraction_numerical': 0.0016199733180865257, 'mean_word_length': 1.3096390845070423, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '979127', 'n_tokens_mistral': 2729, 'n_tokens_neox': 2518, 'n_words': 603}