Skip to content

Commit

Permalink
Make Vendors table faster, but code not DRY
Browse files Browse the repository at this point in the history
  • Loading branch information
halo committed Feb 7, 2024
1 parent e03dc46 commit 9b721ab
Show file tree
Hide file tree
Showing 11 changed files with 180 additions and 54 deletions.
52 changes: 36 additions & 16 deletions LinkLiar.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

40 changes: 20 additions & 20 deletions LinkLiar/Classes/Backends/MACVendors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,26 @@ struct MACVendors {

private static var dictionary: [String: String] = [:]

static func load() {
Log.debug("Loading MAC vendors asynchronously...")
DispatchQueue.global(qos: .background).async(execute: { () -> Void in
if dictionary = JSONReader(filePath: path).dictionary as [String: String] else {
Log.debug("Could not parse MAC vendors.")
return
}
Log.debug("MAC vendors loading completed. I got \(dictionary.count) prefixes.")
})
}

static func name(address: MACAddress) -> String {
Log.debug("Looking up vendor of MAC \(address.formatted)")
guard let name = dictionary[address.prefix] else {
return "No Vendor"
}
return name
}

private static var path = Bundle.main.url(forResource: "oui", withExtension: "json")!.path
// static func load() {
// Log.debug("Loading MAC vendors asynchronously...")
// DispatchQueue.global(qos: .background).async(execute: { () -> Void in
// if dictionary = JSONReader(filePath: path).dictionary as [String: String] else {
// Log.debug("Could not parse MAC vendors.")
// return
// }
// Log.debug("MAC vendors loading completed. I got \(dictionary.count) prefixes.")
// })
// }
//
// static func name(address: MACAddress) -> String {
// Log.debug("Looking up vendor of MAC \(address.formatted)")
// guard let name = dictionary[address.prefix] else {
// return "No Vendor"
// }
// return name
// }
//
// private static var path = Bundle.main.url(forResource: "oui", withExtension: "json")!.path

/*
let bundle = Bundle(for: type(of: self))
Expand Down
41 changes: 41 additions & 0 deletions LinkLiar/Classes/Backends/PopularVendorNames.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) halo https://github.com/halo/LinkLiar
// SPDX-License-Identifier: MIT

import Foundation

struct PopularVendorNames {
// MARK: Class Properties

///
/// Looks up a Vendor by its ID.
/// If no vendor was found, or it has no valid prefixes, returns nil.
///
/// The ID is really just a nickname as String, nothing official.
/// It is used as a convenience shortcut in the LinkLiar config file.
///
/// - parameter id: The ID of the vendor (e.g. "ibm").
///
/// - returns: A ``Vendor`` if found and `nil` if missing.
///
static func find(_ id: String) -> Vendor? {
let id = id.filter("0123456789abcdefghijklmnopqrstuvwxyz".contains)
guard let vendorData = PopularVendorsDatabase.dictionaryWithCounts[id] else { return nil }

guard let rawPrefixCount = vendorData.values.first else { return nil }
guard let name = vendorData.keys.first else { return nil }

return Vendor(id: id, name: name, prefixCount: rawPrefixCount)
}

static func find(_ ids: [String]) -> [Vendor] {
ids.compactMap { find($0) }.sorted()
}

// MARK: Private Class Properties

static var all: [Vendor] {
PopularVendorsDatabase.dictionaryWithCounts.keys.reversed().compactMap {
find($0)
}.sorted()
}
}
2 changes: 1 addition & 1 deletion LinkLiar/Views/Settings/Sections/VendorsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ extension SettingsView {
you can tell it here from which vendors it should pick a prefix.
""") // .multilineTextAlignment(.leading)

Table(state.config.vendors.popular) {
Table(state.config.vendors.popularNames) {

TableColumn("On") { vendor in
let isChosen = Binding<Bool>(
Expand Down
57 changes: 51 additions & 6 deletions LinkTools/Backends/PopularVendorsDatabase.swift

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion LinkTools/Config/Arbiter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ extension Config {
return config.vendors.chosenPopular.flatMap { $0.prefixes }
}

return PopularVendors.find(Config.Key.apple.rawValue)!.prefixes
// return PopularVendors.find(Config.Key.apple.rawValue)!.prefixes
return []
}

var address: MAC? {
Expand Down
11 changes: 8 additions & 3 deletions LinkTools/Config/Vendors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@ extension Config {

var dictionary: [String: Any]

var popular: [Vendor] {
PopularVendors.all
// Proxy them, so that the state is observed.
var popularNames: [Vendor] {
PopularVendorNames.all
}

// var popularWithOUI: [Vendor] {
// PopularVendorOUIs.all
// }

func isChosen(_ vendor: Vendor) -> Bool {
guard let chosenIDs = dictionary[Config.Key.vendors.rawValue] as? [String] else {
return vendor.id == Config.Key.apple.rawValue
Expand All @@ -23,7 +28,7 @@ extension Config {
guard let vendorIDs = dictionary[Config.Key.vendors.rawValue] as? [String] else { return [] }

let vendors = Set(vendorIDs).compactMap { string -> Vendor? in
PopularVendors.find(string)
PopularVendorNames.find(string)
}

return Array(vendors).sorted()
Expand Down
5 changes: 4 additions & 1 deletion LinkTools/Models/Vendor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,20 @@ import Foundation
class Vendor: Identifiable, Hashable {
// MARK: Class Methods

init(id: String, name: String, prefixes: [OUI]) {
init(id: String, name: String, prefixes: [OUI] = [], prefixCount: Int = 0) {
self.id = id
self.name = name
self.prefixes = prefixes
// This is just a cache, in case the actual prefixes are absent.
self.prefixCount = prefixCount == 0 ? prefixes.count : prefixCount
}

// MARK: Instance Properties

var name: String
var id: String
var prefixes: [OUI]
var prefixCount = 0

var isChosen: Bool = false

Expand Down
12 changes: 9 additions & 3 deletions bin/vendors
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,17 @@ result.push ""
result.push "// This file was auto-generated #{Date.today} using `bin/vendors`."
result.push "// If this file changes, don't forget to restart the daemon for the changes to take effect."
result.push ''
result.push 'struct PopularVendorDatabase {'
result.push 'struct PopularVendorsDatabase {'
result.push ' static var dictionaryWithCounts: [String: [String: Int]] {'
result.push ' return ['
result.push Macs::Vendors.all.map(&:to_swift_counts)
result.push ' ]'
result.push ' }'
result.push ''
result.push ' // swiftlint:disable line_length'
result.push ' static var dictionary: [String: [String:[UInt32]]] {'
result.push ' static var dictionaryWithOUIs: [String: [String: [UInt32]]] {'
result.push ' return ['
result.push Macs::Vendors.all.map(&:to_swift)
result.push Macs::Vendors.all.map(&:to_swift_ouis)
result.push ' ]'
result.push ' }'
result.push ' // swiftlint:enable line_length'
Expand Down
7 changes: 6 additions & 1 deletion lib/macs/vendor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,17 @@ def to_s
[name, id, prefixes.count].join(' – ')
end

def to_swift
def to_swift_ouis
# E.g. `"ibm": ["IBM": [0x3440b5,0x40f2e9,0x98be94,0xa897dc]],`
%| // #{@name} #{prefixes.join(',')}| + "\n" +
%| "#{id}": ["#{name}": [#{prefixes.map { "0x#{_1.to_i(16).to_s(16).to_s.rjust(6, '0')}" }.join(',')}]],|
end

def to_swift_counts
# E.g. `"ibm": ["IBM": 42],`
%| "#{id}": ["#{name}": #{prefixes.count}],|
end

def add_prefix(prefix)
prefixes.push prefix.downcase
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ struct PopularVendors {
///
static func find(_ id: String) -> Vendor? {
let id = id.filter("0123456789abcdefghijklmnopqrstuvwxyz".contains)
guard let vendorData = PopularVendorsDatabase.dictionary[id] else { return nil }
guard let vendorData = PopularVendorsDatabase.dictionaryWithOUIs[id] else { return nil }

guard let rawPrefixes = vendorData.values.first else { return nil }
guard let name = vendorData.keys.first else { return nil }
Expand All @@ -40,7 +40,7 @@ struct PopularVendors {
// MARK: Private Class Properties

static var all: [Vendor] {
PopularVendorsDatabase.dictionary.keys.reversed().compactMap {
PopularVendorsDatabase.dictionaryWithOUIs.keys.reversed().compactMap {
find($0)
}.sorted()
}
Expand Down

0 comments on commit 9b721ab

Please sign in to comment.