wireless-rb 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +49 -0
  3. data/README-zh.md +37 -2
  4. data/README.md +34 -3
  5. data/docs/architecture-zh.md +4 -4
  6. data/lib/wireless/ap_session.rb +113 -52
  7. data/lib/wireless/collector.rb +49 -36
  8. data/lib/wireless/configuration.rb +0 -2
  9. data/lib/wireless/coverage.rb +15 -5
  10. data/lib/wireless/fields.rb +25 -20
  11. data/lib/wireless/h3c/{authentication_parser.rb → authentication.rb} +4 -4
  12. data/lib/wireless/h3c/command_output.rb +44 -3
  13. data/lib/wireless/h3c/configuration.rb +21 -5
  14. data/lib/wireless/h3c/document.rb +32 -0
  15. data/lib/wireless/h3c/parsers/display_current_configuration.rb +143 -69
  16. data/lib/wireless/h3c/parsers/display_dot1x_connection.rb +4 -2
  17. data/lib/wireless/h3c/parsers/display_lldp_neighbor_information_verbose.rb +34 -10
  18. data/lib/wireless/h3c/parsers/display_mac_authentication_connection.rb +4 -2
  19. data/lib/wireless/h3c/parsers/display_wlan_ap_all_verbose.rb +37 -11
  20. data/lib/wireless/h3c/parsers/display_wlan_ap_model_all.rb +5 -5
  21. data/lib/wireless/h3c/parsers/display_wlan_bss_all_verbose.rb +6 -6
  22. data/lib/wireless/h3c/parsers/display_wlan_client_security_block_mac.rb +2 -2
  23. data/lib/wireless/h3c/parsers/display_wlan_client_verbose.rb +14 -8
  24. data/lib/wireless/h3c/parsers/display_wlan_statistics_client_ip_conflict.rb +2 -2
  25. data/lib/wireless/h3c/profile.rb +6 -3
  26. data/lib/wireless/h3c/record_parser.rb +138 -0
  27. data/lib/wireless/huawei/parser.rb +86 -0
  28. data/lib/wireless/huawei/parsers/display_ap_all.rb +14 -0
  29. data/lib/wireless/huawei/parsers/display_station_all.rb +14 -0
  30. data/lib/wireless/huawei/profile.rb +22 -0
  31. data/lib/wireless/observation.rb +2 -0
  32. data/lib/wireless/parser_registry.rb +2 -1
  33. data/lib/wireless/projection.rb +4 -0
  34. data/lib/wireless/runtime_parser.rb +16 -11
  35. data/lib/wireless/snapshot.rb +2 -1
  36. data/lib/wireless/terminal.rb +32 -0
  37. data/lib/wireless/version.rb +1 -1
  38. data/lib/wireless.rb +0 -2
  39. metadata +9 -20
  40. data/lib/wireless/h3c/session_parser.rb +0 -58
  41. data/lib/wireless/h3c/verbose_parser.rb +0 -82
  42. data/lib/wireless/h3c_runtime.rb +0 -18
  43. data/lib/wireless/huawei_runtime.rb +0 -65
@@ -1,82 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "parser"
4
-
5
- module Wireless
6
- module H3c
7
- # 为 H3C 详细命令回显共享词元切分与类型化字段处理。
8
- class VerboseParser < Parser
9
- private
10
-
11
- # 切分含引号的命令值,不将其作为 Ruby 代码解释。
12
- def tokens(text, issues)
13
- text.lines.each_with_index.each_with_object([]) do |(line, index), fields|
14
- row = line.strip
15
- next if row.empty? || /\A[-=]+\z/.match?(row)
16
- if (match = /\A([^:]+?)\s*:\s*(.*)\z/.match(row))
17
- label = match[1].downcase.gsub(/\s+/, " ")
18
- next if /\A(?:total|number of aps|connected|remaining|maximum|current number|(?:local|server|sync) ap licenses|(?:current|max|bound) bss number)\b/.match?(label)
19
- fields << [ label, Fields.value(match[2]), index + 1 ]
20
- elsif (match = /\A:\s*(\S.*)\z/.match(row)) && fields.last&.first == "poe status"
21
- fields.last[1] = [ fields.last[1], match[1] ].compact.join("\n")
22
- elsif /\A(?:NSS\d+\s+[\d, ]+|TID \d+\s+(?:In|Out|Both)|[\d., ]+(?:Mbps)?)\z/.match?(row)
23
- next
24
- else
25
- issues << { code: :unrecognized_line, line: index + 1 }
26
- end
27
- end
28
- end
29
-
30
- # 更新当前记录前,先应用字段专用转换。
31
- def assign_field(record, mapping, label, raw, issues, line, details:)
32
- if record && (field = mapping[label])
33
- safely(issues, line) do
34
- # 优先使用运行带宽;80+80MHz 等歧义值保持原义,不截断为单个数值。
35
- if field == :channel_width
36
- (record[:details] ||= {})[label.tr(" ", "_").to_sym] = raw
37
- return if label == "channel bandwidth" && record[:details].key?(:operating_bandwidth)
38
- end
39
- record[field] = convert(field, raw)
40
- end
41
- elsif details
42
- (details[:details] ||= {})[label.tr(" -", "__").to_sym] = label.end_with?("url") ? !raw.nil? && !raw.strip.empty? : raw
43
- else
44
- issues << { code: :unrecognized_field, line: line }
45
- end
46
- end
47
-
48
- # 按声明的归一化规则转换已知字段。
49
- def convert(field, raw)
50
- case field
51
- when :mac_address, :client_mac, :bssid then Fields.mac(raw)
52
- when :management_ip, :client_ip, :client_ipv6, :ip_address, :ipv6_address then Fields.ip(raw)
53
- when :ap_id, :radio_id then Fields.integer(raw)&.to_s
54
- when :client_count, :online_seconds, :uptime_seconds
55
- %i[online_seconds uptime_seconds].include?(field) ? Fields.duration(raw) : Fields.integer(raw)
56
- when :vlan, :initial_vlan_id, :authorized_vlan_id then Fields.integer(raw, max: 4094)
57
- when :channel then Fields.channel(raw)
58
- when :channel_width then Fields.width(raw)
59
- when :band then Fields.band(raw)
60
- when :noise_dbm then Fields.number(raw, unit: "dBm")&.then { |number| number if number.negative? }
61
- when :utilization
62
- number = Fields.number(raw, unit: "%")
63
- raise ArgumentError, "Invalid wireless utilization" if number && !(0..100).cover?(number)
64
- number&.round
65
- else raw
66
- end
67
- end
68
-
69
- # 解析非负计数,同时保留未知值。
70
- def count(text, noun)
71
- /(?:Total(?: number of)?\s+(?:#{noun})|Total|Current BSS number)\s*:\s*(\d+)\s*$/i.match(text)&.[](1)&.to_i
72
- end
73
-
74
- # 隔离单个格式错误字段,同时保留无关记录数据。
75
- def safely(issues, line)
76
- yield
77
- rescue ArgumentError, IPAddr::InvalidAddressError
78
- issues << { code: :invalid_field, line: line }
79
- end
80
- end
81
- end
82
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "runtime_parser"
4
-
5
- module Wireless
6
- # 保留 H3C 公共入口,具体 CLI 语法由独立命令类负责。
7
- class H3cRuntime
8
- # 绑定 H3C 运行解析器,并保留既有公共入口。
9
- def initialize(model: nil)
10
- @parser = RuntimeParser.new(model: model)
11
- end
12
-
13
- # 将单个 H3C 运行维度委派给共享无线解析入口。
14
- def parse(name, text, complete:)
15
- @parser.parse(name, text, platform: :h3c, complete: complete)
16
- end
17
- end
18
- end
@@ -1,65 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "fields"
4
- require_relative "observation"
5
-
6
- module Wireless
7
- # 仅支持有证据的 Huawei 表格格式,区分不支持维度与空清单。
8
- class HuaweiRuntime
9
- # 解析支持的 Huawei AP 或客户端汇总,其余维度标记为不支持。
10
- def parse(name, text, complete:)
11
- unless %i[access_points clients].include?(name)
12
- return Observation.new(name: name, status: :unsupported, issues: [ { code: :unsupported_platform_dimension } ])
13
- end
14
- records, issues = [], []
15
- header = false
16
- total = nil
17
- text.lines.each_with_index do |line, index|
18
- row = line.strip
19
- next if row.empty? || /\A[-=]+\z/.match?(row)
20
- if (match = /\ATotal\s*:\s*(\d+)\z/i.match(row))
21
- total = match[1].to_i
22
- elsif name == :access_points ? /\AID\s+MAC\s+Name\s+Group\s+IP\s+Type\s+State\s+STA\s+Uptime\b/i.match?(row) : /\ASTA MAC\s+AP ID\s+Ap name\s+Rf\/WLAN\b/i.match?(row)
23
- header = true
24
- elsif /\ATotal AP information:|\A(?:nor|fault|idle|stdby)\s*:/i.match?(row)
25
- next
26
- elsif !header
27
- issues << { code: :missing_header, line: index + 1 }
28
- else
29
- begin
30
- records << (name == :access_points ? ap(row.split) : client(row.split))
31
- rescue ArgumentError, IPAddr::InvalidAddressError
32
- issues << { code: :invalid_row, line: index + 1 }
33
- end
34
- end
35
- end
36
- issues << { code: :missing_header } unless header
37
- result = Fields.result(records, issues: issues, complete: complete, total: total, identity: [ name == :access_points ? :name : :client_mac ])
38
- Observation.new(name: name, **result.to_h)
39
- end
40
-
41
- private
42
-
43
- # 归一化控制器报告的单条 AP 记录。
44
- def ap(columns)
45
- raise ArgumentError, "Invalid AP row" unless columns.size == 9
46
- id, mac, name, group, ip, model, state, clients, uptime = columns
47
- { ap_id: Fields.integer(id).to_s, mac_address: Fields.mac(mac), name: name, group_name: group,
48
- management_ip: Fields.ip(Fields.value(ip)), model: model, operational_status: Fields.online_status(state),
49
- client_count: Fields.integer(clients), uptime_seconds: Fields.duration(Fields.value(uptime)) }
50
- end
51
-
52
- # 归一化控制器报告的单条无线客户端记录。
53
- def client(columns)
54
- raise ArgumentError, "Invalid station row" unless columns.size == 15
55
- mac, ap_id, ap_name, radio_wlan, band, protocol, rates, rssi, vlan, ip, ssid, state, ipv6, _ac_id, uptime = columns
56
- raise ArgumentError, "Invalid station identity" unless /\A\d+\/\d+\z/.match?(radio_wlan)
57
- rx, tx = Fields.rates(rates)
58
- signal = Fields.number(Fields.value(rssi), unit: "dBm")
59
- { client_mac: Fields.mac(mac), ap_id: Fields.integer(ap_id).to_s, ap_name: ap_name, radio_id: radio_wlan.split("/").first,
60
- band: Fields.band(band), protocol: protocol, rx_rate_mbps: rx, tx_rate_mbps: tx, signal_dbm: signal == 0 ? nil : signal,
61
- vlan: Fields.integer(vlan, max: 4094), client_ip: Fields.ip(Fields.value(ip)), ssid: ssid, operational_status: state,
62
- client_ipv6: Fields.ip(Fields.value(ipv6)), uptime_seconds: Fields.duration(Fields.value(uptime)) }
63
- end
64
- end
65
- end