keenetic 0.2.0 → 1.0.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.
- checksums.yaml +4 -4
- data/README.md +25 -51
- data/lib/keenetic/client.rb +82 -1
- data/lib/keenetic/resources/base.rb +4 -0
- data/lib/keenetic/resources/components.rb +88 -0
- data/lib/keenetic/resources/config.rb +37 -1
- data/lib/keenetic/resources/diagnostics.rb +102 -0
- data/lib/keenetic/resources/dns.rb +95 -0
- data/lib/keenetic/resources/dyndns.rb +71 -0
- data/lib/keenetic/resources/firewall.rb +103 -0
- data/lib/keenetic/resources/ipv6.rb +74 -0
- data/lib/keenetic/resources/mesh.rb +84 -0
- data/lib/keenetic/resources/nat.rb +202 -0
- data/lib/keenetic/resources/qos.rb +89 -0
- data/lib/keenetic/resources/schedule.rb +87 -0
- data/lib/keenetic/resources/system.rb +134 -0
- data/lib/keenetic/resources/usb.rb +135 -0
- data/lib/keenetic/resources/users.rb +92 -0
- data/lib/keenetic/resources/vpn.rb +153 -0
- data/lib/keenetic/version.rb +1 -1
- data/lib/keenetic.rb +13 -0
- metadata +14 -1
|
@@ -138,8 +138,142 @@ module Keenetic
|
|
|
138
138
|
normalize_license(response)
|
|
139
139
|
end
|
|
140
140
|
|
|
141
|
+
# Reboot the router.
|
|
142
|
+
#
|
|
143
|
+
# == Keenetic API Request
|
|
144
|
+
# POST /rci/system/reboot
|
|
145
|
+
# Body: {}
|
|
146
|
+
#
|
|
147
|
+
# == Warning
|
|
148
|
+
# This will immediately restart the router. All active connections
|
|
149
|
+
# will be dropped and the router will be unavailable for 1-2 minutes.
|
|
150
|
+
#
|
|
151
|
+
# @return [Hash, nil] API response
|
|
152
|
+
# @example
|
|
153
|
+
# client.system.reboot
|
|
154
|
+
#
|
|
155
|
+
def reboot
|
|
156
|
+
post('/rci/system/reboot', {})
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Factory reset the router.
|
|
160
|
+
#
|
|
161
|
+
# == Keenetic API Request
|
|
162
|
+
# POST /rci/system/default
|
|
163
|
+
# Body: {}
|
|
164
|
+
#
|
|
165
|
+
# == Warning
|
|
166
|
+
# This will erase ALL configuration and restore factory defaults.
|
|
167
|
+
# The router will reboot and you will lose access until you
|
|
168
|
+
# reconfigure it. Use with extreme caution!
|
|
169
|
+
#
|
|
170
|
+
# @return [Hash, nil] API response
|
|
171
|
+
# @example
|
|
172
|
+
# client.system.factory_reset
|
|
173
|
+
#
|
|
174
|
+
def factory_reset
|
|
175
|
+
post('/rci/system/default', {})
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Check for available firmware updates.
|
|
179
|
+
#
|
|
180
|
+
# == Keenetic API Request
|
|
181
|
+
# GET /rci/show/system/update
|
|
182
|
+
#
|
|
183
|
+
# == Response Fields
|
|
184
|
+
# - available: Whether an update is available
|
|
185
|
+
# - version: Available firmware version
|
|
186
|
+
# - current: Current firmware version
|
|
187
|
+
# - channel: Update channel (stable, preview)
|
|
188
|
+
#
|
|
189
|
+
# @return [Hash] Update availability information
|
|
190
|
+
# @example
|
|
191
|
+
# update_info = client.system.check_updates
|
|
192
|
+
# # => { available: true, version: "4.2.0", current: "4.1.0", ... }
|
|
193
|
+
#
|
|
194
|
+
def check_updates
|
|
195
|
+
response = get('/rci/show/system/update')
|
|
196
|
+
normalize_update_info(response)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Apply available firmware update.
|
|
200
|
+
#
|
|
201
|
+
# == Keenetic API Request
|
|
202
|
+
# POST /rci/system/update
|
|
203
|
+
# Body: {}
|
|
204
|
+
#
|
|
205
|
+
# == Warning
|
|
206
|
+
# This will download and install the latest firmware update.
|
|
207
|
+
# The router will reboot automatically after the update is applied.
|
|
208
|
+
# Do not power off the router during the update process!
|
|
209
|
+
#
|
|
210
|
+
# @return [Hash, nil] API response
|
|
211
|
+
# @example
|
|
212
|
+
# client.system.apply_update
|
|
213
|
+
#
|
|
214
|
+
def apply_update
|
|
215
|
+
post('/rci/system/update', {})
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Control LED mode on the router.
|
|
219
|
+
#
|
|
220
|
+
# == Keenetic API Request
|
|
221
|
+
# POST /rci/system/led
|
|
222
|
+
# Body: { "mode": "on" | "off" | "auto" }
|
|
223
|
+
#
|
|
224
|
+
# @param mode [String] LED mode: "on", "off", or "auto"
|
|
225
|
+
# @return [Hash, nil] API response
|
|
226
|
+
# @raise [ArgumentError] if mode is invalid
|
|
227
|
+
#
|
|
228
|
+
# @example Turn off LEDs
|
|
229
|
+
# client.system.set_led_mode('off')
|
|
230
|
+
#
|
|
231
|
+
# @example Set to automatic
|
|
232
|
+
# client.system.set_led_mode('auto')
|
|
233
|
+
#
|
|
234
|
+
def set_led_mode(mode)
|
|
235
|
+
valid_modes = %w[on off auto]
|
|
236
|
+
unless valid_modes.include?(mode)
|
|
237
|
+
raise ArgumentError, "Invalid LED mode: #{mode}. Valid modes: #{valid_modes.join(', ')}"
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
post('/rci/system/led', { 'mode' => mode })
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Get button configuration.
|
|
244
|
+
#
|
|
245
|
+
# == Keenetic API Request
|
|
246
|
+
# GET /rci/show/button
|
|
247
|
+
#
|
|
248
|
+
# Returns information about physical buttons on the router
|
|
249
|
+
# and their configured actions.
|
|
250
|
+
#
|
|
251
|
+
# @return [Hash] Button configuration
|
|
252
|
+
# @example
|
|
253
|
+
# buttons = client.system.button_config
|
|
254
|
+
# # => { wifi: { action: "toggle" }, fn: { action: "wps" } }
|
|
255
|
+
#
|
|
256
|
+
def button_config
|
|
257
|
+
response = get('/rci/show/button')
|
|
258
|
+
normalize_button_config(response)
|
|
259
|
+
end
|
|
260
|
+
|
|
141
261
|
private
|
|
142
262
|
|
|
263
|
+
def normalize_update_info(response)
|
|
264
|
+
return {} unless response.is_a?(Hash)
|
|
265
|
+
|
|
266
|
+
result = deep_normalize_keys(response)
|
|
267
|
+
normalize_booleans(result, %i[available downloading])
|
|
268
|
+
result
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def normalize_button_config(response)
|
|
272
|
+
return {} unless response.is_a?(Hash)
|
|
273
|
+
|
|
274
|
+
deep_normalize_keys(response)
|
|
275
|
+
end
|
|
276
|
+
|
|
143
277
|
def normalize_resources(response)
|
|
144
278
|
return {} unless response.is_a?(Hash)
|
|
145
279
|
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
module Keenetic
|
|
2
|
+
module Resources
|
|
3
|
+
# USB resource for managing USB devices and storage.
|
|
4
|
+
#
|
|
5
|
+
# == API Endpoints Used
|
|
6
|
+
#
|
|
7
|
+
# === Reading USB Devices
|
|
8
|
+
# GET /rci/show/usb
|
|
9
|
+
# Returns: Connected USB devices
|
|
10
|
+
#
|
|
11
|
+
# === Reading Storage/Media
|
|
12
|
+
# GET /rci/show/media
|
|
13
|
+
# Returns: Mounted storage partitions
|
|
14
|
+
#
|
|
15
|
+
# === Safely Eject USB
|
|
16
|
+
# POST /rci/usb/eject
|
|
17
|
+
# Body: { port }
|
|
18
|
+
#
|
|
19
|
+
class Usb < Base
|
|
20
|
+
# Get connected USB devices.
|
|
21
|
+
#
|
|
22
|
+
# == Keenetic API Request
|
|
23
|
+
# GET /rci/show/usb
|
|
24
|
+
#
|
|
25
|
+
# == Response Fields (per device)
|
|
26
|
+
# - port: USB port number
|
|
27
|
+
# - manufacturer: Device manufacturer
|
|
28
|
+
# - product: Product name
|
|
29
|
+
# - serial: Serial number
|
|
30
|
+
# - class: USB device class
|
|
31
|
+
# - speed: USB speed
|
|
32
|
+
# - connected: Currently connected
|
|
33
|
+
#
|
|
34
|
+
# @return [Array<Hash>] List of USB devices
|
|
35
|
+
# @example
|
|
36
|
+
# devices = client.usb.devices
|
|
37
|
+
# # => [{ port: 1, manufacturer: "SanDisk", product: "USB Flash", ... }]
|
|
38
|
+
#
|
|
39
|
+
def devices
|
|
40
|
+
response = get('/rci/show/usb')
|
|
41
|
+
normalize_devices(response)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Get mounted storage partitions.
|
|
45
|
+
#
|
|
46
|
+
# == Keenetic API Request
|
|
47
|
+
# GET /rci/show/media
|
|
48
|
+
#
|
|
49
|
+
# == Response Fields (per partition)
|
|
50
|
+
# - name: Device name
|
|
51
|
+
# - label: Volume label
|
|
52
|
+
# - uuid: Volume UUID
|
|
53
|
+
# - fs: Filesystem type
|
|
54
|
+
# - mountpoint: Mount path
|
|
55
|
+
# - total: Total bytes
|
|
56
|
+
# - used: Used bytes
|
|
57
|
+
# - free: Free bytes
|
|
58
|
+
#
|
|
59
|
+
# @return [Array<Hash>] List of storage partitions
|
|
60
|
+
# @example
|
|
61
|
+
# media = client.usb.media
|
|
62
|
+
# # => [{ name: "sda1", label: "USB_DRIVE", fs: "ext4", total: 32000000000, ... }]
|
|
63
|
+
#
|
|
64
|
+
def media
|
|
65
|
+
response = get('/rci/show/media')
|
|
66
|
+
normalize_media(response)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Alias for media
|
|
70
|
+
alias storage media
|
|
71
|
+
|
|
72
|
+
# Safely eject a USB device.
|
|
73
|
+
#
|
|
74
|
+
# == Keenetic API Request
|
|
75
|
+
# POST /rci/usb/eject
|
|
76
|
+
# Body: { "port": 1 }
|
|
77
|
+
#
|
|
78
|
+
# @param port [Integer] USB port number to eject
|
|
79
|
+
# @return [Hash, nil] API response
|
|
80
|
+
#
|
|
81
|
+
# @example
|
|
82
|
+
# client.usb.eject(port: 1)
|
|
83
|
+
#
|
|
84
|
+
def eject(port:)
|
|
85
|
+
post('/rci/usb/eject', { 'port' => port })
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def normalize_devices(response)
|
|
91
|
+
devices_data = case response
|
|
92
|
+
when Array
|
|
93
|
+
response
|
|
94
|
+
when Hash
|
|
95
|
+
response['device'] || response['devices'] || []
|
|
96
|
+
else
|
|
97
|
+
[]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
return [] unless devices_data.is_a?(Array)
|
|
101
|
+
|
|
102
|
+
devices_data.map { |device| normalize_device(device) }.compact
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def normalize_device(data)
|
|
106
|
+
return nil unless data.is_a?(Hash)
|
|
107
|
+
|
|
108
|
+
result = deep_normalize_keys(data)
|
|
109
|
+
normalize_booleans(result, %i[connected])
|
|
110
|
+
result
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def normalize_media(response)
|
|
114
|
+
media_data = case response
|
|
115
|
+
when Array
|
|
116
|
+
response
|
|
117
|
+
when Hash
|
|
118
|
+
response['media'] || response['partition'] || []
|
|
119
|
+
else
|
|
120
|
+
[]
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
return [] unless media_data.is_a?(Array)
|
|
124
|
+
|
|
125
|
+
media_data.map { |partition| normalize_partition(partition) }.compact
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def normalize_partition(data)
|
|
129
|
+
return nil unless data.is_a?(Hash)
|
|
130
|
+
|
|
131
|
+
deep_normalize_keys(data)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
module Keenetic
|
|
2
|
+
module Resources
|
|
3
|
+
# Users resource for managing router user accounts.
|
|
4
|
+
#
|
|
5
|
+
# == API Endpoints Used
|
|
6
|
+
#
|
|
7
|
+
# === List Users
|
|
8
|
+
# GET /rci/show/user
|
|
9
|
+
#
|
|
10
|
+
# === Create User
|
|
11
|
+
# POST /rci/user
|
|
12
|
+
#
|
|
13
|
+
# === Delete User
|
|
14
|
+
# POST /rci/user with { "name": "...", "no": true }
|
|
15
|
+
#
|
|
16
|
+
# == User Tags (permissions)
|
|
17
|
+
# - http: Web interface access
|
|
18
|
+
# - cli: CLI/Telnet access
|
|
19
|
+
# - cifs: File sharing access
|
|
20
|
+
# - ftp: FTP access
|
|
21
|
+
# - vpn: VPN access
|
|
22
|
+
#
|
|
23
|
+
class Users < Base
|
|
24
|
+
# List all users.
|
|
25
|
+
#
|
|
26
|
+
# @return [Array<Hash>] List of users
|
|
27
|
+
# @example
|
|
28
|
+
# users = client.users.all
|
|
29
|
+
#
|
|
30
|
+
def all
|
|
31
|
+
response = get('/rci/show/user')
|
|
32
|
+
normalize_users(response)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Find a user by name.
|
|
36
|
+
#
|
|
37
|
+
# @param name [String] User name
|
|
38
|
+
# @return [Hash, nil] User data or nil
|
|
39
|
+
#
|
|
40
|
+
def find(name)
|
|
41
|
+
all.find { |u| u[:name] == name }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Create a new user.
|
|
45
|
+
#
|
|
46
|
+
# @param name [String] User name
|
|
47
|
+
# @param password [String] User password
|
|
48
|
+
# @param tag [Array<String>] Permission tags (http, cli, cifs, ftp, vpn)
|
|
49
|
+
# @return [Hash, nil] API response
|
|
50
|
+
# @example
|
|
51
|
+
# client.users.create(name: 'guest', password: 'guestpass', tag: ['http', 'cifs'])
|
|
52
|
+
#
|
|
53
|
+
def create(name:, password:, tag: [])
|
|
54
|
+
params = { 'name' => name, 'password' => password }
|
|
55
|
+
params['tag'] = tag unless tag.empty?
|
|
56
|
+
post('/rci/user', params)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Delete a user.
|
|
60
|
+
#
|
|
61
|
+
# @param name [String] User name
|
|
62
|
+
# @return [Hash, nil] API response
|
|
63
|
+
#
|
|
64
|
+
def delete(name:)
|
|
65
|
+
post('/rci/user', { 'name' => name, 'no' => true })
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def normalize_users(response)
|
|
71
|
+
users_data = case response
|
|
72
|
+
when Array
|
|
73
|
+
response
|
|
74
|
+
when Hash
|
|
75
|
+
response['user'] || response['users'] || []
|
|
76
|
+
else
|
|
77
|
+
[]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
return [] unless users_data.is_a?(Array)
|
|
81
|
+
|
|
82
|
+
users_data.map { |user| normalize_user(user) }.compact
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def normalize_user(data)
|
|
86
|
+
return nil unless data.is_a?(Hash)
|
|
87
|
+
|
|
88
|
+
deep_normalize_keys(data)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
module Keenetic
|
|
2
|
+
module Resources
|
|
3
|
+
# VPN resource for managing VPN server and monitoring connections.
|
|
4
|
+
#
|
|
5
|
+
# == API Endpoints Used
|
|
6
|
+
#
|
|
7
|
+
# === Reading VPN Server Status
|
|
8
|
+
# GET /rci/show/vpn-server
|
|
9
|
+
# Returns: VPN server configuration and status
|
|
10
|
+
#
|
|
11
|
+
# === Reading VPN Clients
|
|
12
|
+
# GET /rci/show/vpn-server/clients
|
|
13
|
+
# Returns: Array of connected VPN clients
|
|
14
|
+
#
|
|
15
|
+
# === Reading IPsec Status
|
|
16
|
+
# GET /rci/show/crypto/ipsec/sa
|
|
17
|
+
# Returns: IPsec security associations
|
|
18
|
+
#
|
|
19
|
+
# === Configuring VPN Server
|
|
20
|
+
# POST /rci/vpn-server
|
|
21
|
+
# Body: { type, enabled, pool-start, pool-end, ... }
|
|
22
|
+
#
|
|
23
|
+
class Vpn < Base
|
|
24
|
+
# Get VPN server status and configuration.
|
|
25
|
+
#
|
|
26
|
+
# == Keenetic API Request
|
|
27
|
+
# GET /rci/show/vpn-server
|
|
28
|
+
#
|
|
29
|
+
# == Response Fields
|
|
30
|
+
# - type: VPN server type (pptp, l2tp, sstp, etc.)
|
|
31
|
+
# - enabled: Whether server is enabled
|
|
32
|
+
# - running: Whether server is currently running
|
|
33
|
+
# - pool_start: Start of IP pool for clients
|
|
34
|
+
# - pool_end: End of IP pool for clients
|
|
35
|
+
# - interface: VPN interface name
|
|
36
|
+
#
|
|
37
|
+
# @return [Hash] VPN server status
|
|
38
|
+
# @example
|
|
39
|
+
# status = client.vpn.status
|
|
40
|
+
# # => { type: "l2tp", enabled: true, running: true, ... }
|
|
41
|
+
#
|
|
42
|
+
def status
|
|
43
|
+
response = get('/rci/show/vpn-server')
|
|
44
|
+
normalize_status(response)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Get connected VPN clients.
|
|
48
|
+
#
|
|
49
|
+
# == Keenetic API Request
|
|
50
|
+
# GET /rci/show/vpn-server/clients
|
|
51
|
+
#
|
|
52
|
+
# == Response Fields (per client)
|
|
53
|
+
# - name: Client username
|
|
54
|
+
# - ip: Assigned IP address
|
|
55
|
+
# - uptime: Connection duration in seconds
|
|
56
|
+
# - rxbytes: Bytes received
|
|
57
|
+
# - txbytes: Bytes transmitted
|
|
58
|
+
#
|
|
59
|
+
# @return [Array<Hash>] List of connected VPN clients
|
|
60
|
+
# @example
|
|
61
|
+
# clients = client.vpn.clients
|
|
62
|
+
# # => [{ name: "user1", ip: "192.168.1.200", uptime: 3600, ... }]
|
|
63
|
+
#
|
|
64
|
+
def clients
|
|
65
|
+
response = get('/rci/show/vpn-server/clients')
|
|
66
|
+
normalize_clients(response)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Get IPsec security associations status.
|
|
70
|
+
#
|
|
71
|
+
# == Keenetic API Request
|
|
72
|
+
# GET /rci/show/crypto/ipsec/sa
|
|
73
|
+
#
|
|
74
|
+
# == Response Fields
|
|
75
|
+
# - established: Number of established SAs
|
|
76
|
+
# - sa: Array of security associations
|
|
77
|
+
#
|
|
78
|
+
# @return [Hash] IPsec status with security associations
|
|
79
|
+
# @example
|
|
80
|
+
# ipsec = client.vpn.ipsec_status
|
|
81
|
+
# # => { established: 2, sa: [...] }
|
|
82
|
+
#
|
|
83
|
+
def ipsec_status
|
|
84
|
+
response = get('/rci/show/crypto/ipsec/sa')
|
|
85
|
+
normalize_ipsec(response)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Configure VPN server.
|
|
89
|
+
#
|
|
90
|
+
# == Keenetic API Request
|
|
91
|
+
# POST /rci/vpn-server
|
|
92
|
+
# Body: { type, enabled, pool-start, pool-end, ... }
|
|
93
|
+
#
|
|
94
|
+
# @param type [String] VPN type: "pptp", "l2tp", "sstp"
|
|
95
|
+
# @param enabled [Boolean] Enable or disable the server
|
|
96
|
+
# @param pool_start [String, nil] Start of client IP pool
|
|
97
|
+
# @param pool_end [String, nil] End of client IP pool
|
|
98
|
+
# @param mppe [String, nil] MPPE encryption: "require", "prefer", "none"
|
|
99
|
+
# @return [Hash, Array, nil] API response
|
|
100
|
+
#
|
|
101
|
+
# @example Enable L2TP server
|
|
102
|
+
# client.vpn.configure(
|
|
103
|
+
# type: 'l2tp',
|
|
104
|
+
# enabled: true,
|
|
105
|
+
# pool_start: '192.168.1.200',
|
|
106
|
+
# pool_end: '192.168.1.210'
|
|
107
|
+
# )
|
|
108
|
+
#
|
|
109
|
+
# @example Disable VPN server
|
|
110
|
+
# client.vpn.configure(type: 'pptp', enabled: false)
|
|
111
|
+
#
|
|
112
|
+
def configure(type:, enabled:, pool_start: nil, pool_end: nil, mppe: nil)
|
|
113
|
+
params = {
|
|
114
|
+
'type' => type,
|
|
115
|
+
'enabled' => enabled
|
|
116
|
+
}
|
|
117
|
+
params['pool-start'] = pool_start if pool_start
|
|
118
|
+
params['pool-end'] = pool_end if pool_end
|
|
119
|
+
params['mppe'] = mppe if mppe
|
|
120
|
+
|
|
121
|
+
post('/rci/vpn-server', params)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
private
|
|
125
|
+
|
|
126
|
+
def normalize_status(response)
|
|
127
|
+
return {} unless response.is_a?(Hash)
|
|
128
|
+
|
|
129
|
+
result = deep_normalize_keys(response)
|
|
130
|
+
normalize_booleans(result, %i[enabled running])
|
|
131
|
+
result
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def normalize_clients(response)
|
|
135
|
+
return [] unless response.is_a?(Array)
|
|
136
|
+
|
|
137
|
+
response.map { |client_data| normalize_client(client_data) }.compact
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def normalize_client(data)
|
|
141
|
+
return nil unless data.is_a?(Hash)
|
|
142
|
+
|
|
143
|
+
deep_normalize_keys(data)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def normalize_ipsec(response)
|
|
147
|
+
return {} unless response.is_a?(Hash)
|
|
148
|
+
|
|
149
|
+
deep_normalize_keys(response)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
data/lib/keenetic/version.rb
CHANGED
data/lib/keenetic.rb
CHANGED
|
@@ -16,6 +16,19 @@ require_relative 'keenetic/resources/logs'
|
|
|
16
16
|
require_relative 'keenetic/resources/routes'
|
|
17
17
|
require_relative 'keenetic/resources/hotspot'
|
|
18
18
|
require_relative 'keenetic/resources/config'
|
|
19
|
+
require_relative 'keenetic/resources/nat'
|
|
20
|
+
require_relative 'keenetic/resources/vpn'
|
|
21
|
+
require_relative 'keenetic/resources/diagnostics'
|
|
22
|
+
require_relative 'keenetic/resources/firewall'
|
|
23
|
+
require_relative 'keenetic/resources/mesh'
|
|
24
|
+
require_relative 'keenetic/resources/usb'
|
|
25
|
+
require_relative 'keenetic/resources/dns'
|
|
26
|
+
require_relative 'keenetic/resources/dyndns'
|
|
27
|
+
require_relative 'keenetic/resources/schedule'
|
|
28
|
+
require_relative 'keenetic/resources/users'
|
|
29
|
+
require_relative 'keenetic/resources/components'
|
|
30
|
+
require_relative 'keenetic/resources/qos'
|
|
31
|
+
require_relative 'keenetic/resources/ipv6'
|
|
19
32
|
|
|
20
33
|
# Keenetic Router API Client
|
|
21
34
|
#
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: keenetic
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Anton Zaytsev
|
|
@@ -52,18 +52,31 @@ files:
|
|
|
52
52
|
- lib/keenetic/configuration.rb
|
|
53
53
|
- lib/keenetic/errors.rb
|
|
54
54
|
- lib/keenetic/resources/base.rb
|
|
55
|
+
- lib/keenetic/resources/components.rb
|
|
55
56
|
- lib/keenetic/resources/config.rb
|
|
56
57
|
- lib/keenetic/resources/devices.rb
|
|
57
58
|
- lib/keenetic/resources/dhcp.rb
|
|
59
|
+
- lib/keenetic/resources/diagnostics.rb
|
|
60
|
+
- lib/keenetic/resources/dns.rb
|
|
61
|
+
- lib/keenetic/resources/dyndns.rb
|
|
62
|
+
- lib/keenetic/resources/firewall.rb
|
|
58
63
|
- lib/keenetic/resources/hotspot.rb
|
|
59
64
|
- lib/keenetic/resources/internet.rb
|
|
65
|
+
- lib/keenetic/resources/ipv6.rb
|
|
60
66
|
- lib/keenetic/resources/logs.rb
|
|
67
|
+
- lib/keenetic/resources/mesh.rb
|
|
68
|
+
- lib/keenetic/resources/nat.rb
|
|
61
69
|
- lib/keenetic/resources/network.rb
|
|
62
70
|
- lib/keenetic/resources/policies.rb
|
|
63
71
|
- lib/keenetic/resources/ports.rb
|
|
72
|
+
- lib/keenetic/resources/qos.rb
|
|
64
73
|
- lib/keenetic/resources/routes.rb
|
|
65
74
|
- lib/keenetic/resources/routing.rb
|
|
75
|
+
- lib/keenetic/resources/schedule.rb
|
|
66
76
|
- lib/keenetic/resources/system.rb
|
|
77
|
+
- lib/keenetic/resources/usb.rb
|
|
78
|
+
- lib/keenetic/resources/users.rb
|
|
79
|
+
- lib/keenetic/resources/vpn.rb
|
|
67
80
|
- lib/keenetic/resources/wifi.rb
|
|
68
81
|
- lib/keenetic/version.rb
|
|
69
82
|
homepage: https://github.com/antonzaytsev/keenetic-ruby
|