knot-ruby 0.1.2 → 0.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d24b7dfed91ed556ec5c2ee1b6c765eb96879e2d7d5fdd4dfaf060e474f4c91
4
- data.tar.gz: 66c899d76cbd7ff9ea68d7f3f0fad98dc8bf21a1e136d156379f25ee42046ad1
3
+ metadata.gz: 431bf7db78b2a1b8e1698f53eec8ae8726ef3aca3a9c3b38c77f06ef592fd9c9
4
+ data.tar.gz: 8dcf78f6703e9c1c00149f629684b1cda175f20f2148c9780cd4eead1a9e78fb
5
5
  SHA512:
6
- metadata.gz: 5763ee24991d9d75ef48da2bb203acba69dc89dc4d982d35abd23980792f0649062ef4e58b8a9f5982a341cda9c20ac810873de1476d057c69cc733105fa5ecc
7
- data.tar.gz: b932a258e7340a0e3baa7a0a833868b6a5a9ae8eb6f5d1149601193238c1279abe3710d3dda9e1e5cc193ba74baa3fad61411ad34820b60fdffca52d6a7035f5
6
+ metadata.gz: 68642c8b64d37524a7ee4b53187e444dfe003fc5e47ee6208954b078c9849fabbfcd5080472a7bd42f2fa9721cac6060a04ff26233ba3ee891698cd4227ff919
7
+ data.tar.gz: 7bcbe887741d86b4fdc09212ae92a8ffc08e824aaaf9ec82fa225e4faf3a5db9434ab99bfff14cc0e918f24f9df6ea792b074f66c1a58ba7a25f8b12d32c1dfd
data/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
1
  source "https://rubygems.org"
2
+ ruby '>=2.7'
2
3
 
3
4
  # Specify your gem's dependencies in knot.gemspec
4
5
  gemspec
data/knot-ruby.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.summary = %q{Provides interface to knot-server.}
11
11
  spec.description = %q{Implements knot-protocol to provide an interface to knot-DNS-server}
12
12
  spec.homepage = 'https://git.denkn.at/deac/knot'
13
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
14
14
 
15
15
  #spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
16
16
 
@@ -69,7 +69,7 @@ class Knot::Zone
69
69
 
70
70
  def read() @protocol.call command: 'zone-read', zone: @zone end
71
71
  def diff() @protocol.call command: 'zone-diff', zone: @zone end
72
-
72
+
73
73
  # setting record
74
74
  # if data is nil, it will be unset.
75
75
  def set owner, ttl = nil, type, data
@@ -127,59 +127,64 @@ class Knot::Conf
127
127
  self.commit
128
128
  end
129
129
 
130
- def parse_item k
131
- case k
130
+ def parse_item kv
131
+ case kv
132
132
  when Hash
133
- case k.keys.sort
134
- when %w[section], %w[id section], %w[item section], %w[id item section]
135
- k
133
+ r = {}
134
+ kv.each {|k,v| r[k.to_s.to_sym] = v }
135
+ case r.keys.sort
136
+ when %i[section], %i[id section], %i[item section], %i[id item section]
137
+ r
136
138
  else
137
- raise ArgumentError, "Invalid Item-format"
139
+ raise ArgumentError, "Invalid Item-format: #{k}"
138
140
  end
139
141
 
140
142
  when Array
141
- case k.length
142
- when 1 then {section: k[0]}
143
- when 2 then {section: k[0], item: k[1]}
144
- when 3 then {section: k[0], id: k[1], item: k[2]}
145
- else raise ArgumentError, "Invalid Item-format"
143
+ case kv.length
144
+ when 1 then {section: kv[0]}
145
+ when 2 then {section: kv[0], item: kv[1]}
146
+ when 3 then {section: kv[0], id: kv[1], item: kv[2]}
147
+ else raise ArgumentError, "Invalid Item-format: #{kv}"
146
148
  end
147
149
 
148
150
  when /\A
149
- (?<section> [a-z0-9_-]+ )
150
- (?: \[ (?<id> [a-z0-9_.-]+) \] )?
151
- (?: \. (?<item>[a-z0-9_-]+) )?
151
+ (?<section> [a-z0-9_-]+ )
152
+ (?: \[ (?<id> [a-z0-9_.-]+) \] )?
153
+ (?: \. (?<item>[a-z0-9_-]+) )?
152
154
  \z/xi
153
155
 
154
- $~.named_captures.delete_if {|_,v| v.nil? }
156
+ $~.named_captures.delete_if {|_,v| v.nil? }
157
+
158
+ when nil
159
+ {}
155
160
 
156
161
  else
157
- raise ArgumentError, "Invalid Item-format"
162
+ raise ArgumentError, "Invalid Item-format: #{kv}"
158
163
  end
159
164
  end
160
165
 
161
166
  def get item = nil
162
- @protocol.call (item ? parse_item( item) : {}).update( command: 'conf-get')
167
+ @protocol.call **parse_item( item).update( command: 'conf-get')
163
168
  end
164
169
 
165
170
  # Sets or adds a new value to item.
166
171
  # knot knows single-value items like `server.rundir` and multi-value items like `server.listen`.
167
172
  # If you set a single-value, it will replace the old value. On a multi-value, it will add it.
168
173
  def set item, value
169
- @protocol.call parse_item( item).update( command: 'conf-set', data: value)
174
+ @protocol.call **parse_item( item).update( command: 'conf-set', data: value)
170
175
  end
171
176
 
172
177
  # Removes value from item. If you provide a value, this value will be removed.
173
178
  def unset item, value = nil
174
- @protocol.call parse_item( item).update( command: 'conf-unset', data: value)
179
+ @protocol.call **parse_item( item).update( command: 'conf-unset', data: value)
175
180
  end
176
181
  alias delete unset
177
182
 
178
183
  def list item = nil
179
- @protocol.call (item ? parse_item( item) : {}).update( command: 'conf-list')
184
+ @protocol.call **parse_item( item).update( command: 'conf-list')
180
185
  end
181
186
 
182
187
  def read item = nil
183
- @protocol.call (item ? parse_item( item) : {}).update( command: 'conf-read')
188
+ @protocol.call **parse_item( item).update( command: 'conf-read')
184
189
  end
185
190
  end
data/lib/knot/protocol.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'iounpack'
2
+ require 'stringio'
2
3
  require_relative 'errors'
3
4
 
4
5
  module Knot
@@ -51,44 +52,98 @@ module Knot::Protocol::Type
51
52
  end
52
53
  end
53
54
 
55
+ #class Knot::KnotC
56
+ # attr_accessor :binary
57
+ #
58
+ # def initialize path = nil, binary: nil
59
+ # @path = path
60
+ # @binary = binary || 'knotc'
61
+ # @conf = Knot::Conf.new self
62
+ # @zones = Hash.new {|h, zone| h[zone] = Knot::Zone.new zone, self }
63
+ # end
64
+ #
65
+ # def call command:, flags: nil, section: nil, item: nil, id: nil, zone: nil, owner: nil, ttl: nil, type: nil, data: nil, filter: nil
66
+ # cs =
67
+ # case command.to_s
68
+ # when 'conf-begin', 'conf-commit', 'conf-abort', 'status', 'stop', 'reload'
69
+ # [@binary, command, ]
70
+ # else raise ArgumentError, "Unknown Command: #{command}"
71
+ # end
72
+ # end
73
+ #end
74
+
54
75
  module Knot::Protocol::Idx
76
+ class Id
77
+ include Comparable
78
+ attr_reader :name, :code, :cname, :description
79
+
80
+ def initialize name, code, cname, description
81
+ raise ArgumentError, "Expecting Symbol for #{self.class.name} instead of: #{name.inspect}" unless Symbol === name
82
+ raise ArgumentError, "Expecting Integer for #{self.class.name} instead of: #{code.inspect}" unless Integer === code
83
+ @name, @code, @cname, @description = name, code, cname, description
84
+ freeze
85
+ end
86
+
87
+ def === x
88
+ case x
89
+ when self.class then self == x
90
+ when Symbol then @name == x
91
+ when String then @name == x.to_sym
92
+ when Integer then @code == x
93
+ else nil
94
+ end
95
+ end
96
+
97
+ def <=>( x) @id <=> x.id end
98
+ def to_s() @name.to_s end
99
+ def to_sym() @name end
100
+ def to_i() @code end
101
+ end
102
+
55
103
  Idx = [
56
- :command, # 10, :CMD, # Control command name.
57
- :flags, # 11, :FLAGS, # Control command flags.
58
- :error, # 12, :ERROR, # Error message.
59
- :section, # 13, :SECTION, # Configuration section name.
60
- :item, # 14, :ITEM, # Configuration item name.
61
- :id, # 15, :ID, # Congiguration item identifier.
62
- :zone, # 16, :ZONE, # Zone name.
63
- :owner, # 17, :OWNER, # Zone record owner
64
- :ttl, # 18, :TTL, # Zone record TTL.
65
- :type, # 19, :TYPE, # Zone record type name.
66
- :data, # 1a, :DATA, # Configuration item/zone record data.
67
- :filter, # 1b, :FILTER, # An option or a filter for output data processing.
104
+ Id.new( :command, 0x10, :CMD, 'Control command name.'),
105
+ Id.new( :flags, 0x11, :FLAGS, 'Control command flags.'),
106
+ Id.new( :error, 0x12, :ERROR, 'Error message.'),
107
+ Id.new( :section, 0x13, :SECTION, 'Configuration section name.'),
108
+ Id.new( :item, 0x14, :ITEM, 'Configuration item name.'),
109
+ Id.new( :id, 0x15, :ID, 'Congiguration item identifier.'),
110
+ Id.new( :zone, 0x16, :ZONE, 'Zone name.'),
111
+ Id.new( :owner, 0x17, :OWNER, 'Zone record owner'),
112
+ Id.new( :ttl, 0x18, :TTL, 'Zone record TTL.'),
113
+ Id.new( :type, 0x19, :TYPE, 'Zone record type name.'),
114
+ Id.new( :data, 0x1a, :DATA, 'Configuration item/zone record data.'),
115
+ Id.new( :filter, 0x1b, :FILTER, 'An option or a filter for output data processing.'),
68
116
  ]
69
117
  Name = {}
70
118
  Code = {}
71
- Idx.each_with_index do |v, i|
72
- Code[0x10+i] = v
73
- Name[v] = i
119
+
120
+ Idx.each do |id|
121
+ Code[id.to_i] = id
122
+ Name[id.to_sym] = id
74
123
  end
75
- def self.[] k
76
- case k
77
- when Symbol
78
- Name[k] or raise Knot::Errors::EINVAL, "Unknown Idx: #{k}"
79
- when Integer
80
- Idx[k] or raise Knot::Errors::EINVAL, "Unknown Idx: #{k}"
81
- else
82
- raise ArgumentError, "Unknown Idx-Type: #{k}"
124
+
125
+ class <<self
126
+ def [] k
127
+ case k
128
+ when Symbol
129
+ Name[k] or raise Knot::Errors::EINVAL, "Unknown Idx: #{k}"
130
+ when Integer
131
+ Code[k] or raise Knot::Errors::EINVAL, "Unknown Idx: #{k}"
132
+ else
133
+ raise ArgumentError, "Unknown Idx-Type: #{k}"
134
+ end
135
+ end
136
+
137
+ def each &exe
138
+ block_given? ? Idx.each( &exe) : Idx.to_enum( :each)
83
139
  end
84
140
  end
85
141
  end
86
142
 
87
143
  class Knot::Protocol
88
- attr_reader :sock, :conf, :zones
89
- attr_accessor :debug
144
+ attr_reader :sock, :conf, :zones, :logger
90
145
 
91
- def initialize path_or_sock = nil
146
+ def initialize path_or_sock = nil, logger: nil
92
147
  case path_or_sock
93
148
  when String, Pathname
94
149
  @sock = UNIXSocket.new path_or_sock.to_s
@@ -97,54 +152,62 @@ class Knot::Protocol
97
152
  when nil
98
153
  @sock = UNIXSocket.new '/run/knot/knot.sock'
99
154
  end
100
- @debug = false
155
+ @logger = logger || Logger.new(STDERR)
101
156
  @conf = Knot::Conf.new self
102
157
  @zones = Hash.new {|h, zone| h[zone] = Knot::Zone.new zone, self }
103
158
  end
104
159
 
105
160
  def snd sock: nil, **data
106
161
  rsock = sock || @sock
107
- s = ''
108
- sock = StringIO.new s
109
- sock.write [1].pack( 'c')
162
+ #s = ''.b
163
+ #sock = StringIO.new s
164
+ #sock.write [1].pack( 'c')
110
165
  data[:flags] ||= ''
111
- Idx::Idx.each_with_index do |n, i|
112
- v = data[n]&.to_s
113
- sock.write [0x10+i, v.size, v].pack( 'c na*') if v
166
+ ds =
167
+ Idx::Idx.
168
+ select {|n| data[n.to_sym] }.
169
+ map {|n| v = data[n.to_sym].to_s.b; [n.to_i, v.size, v ] }
170
+ s = (ds.flatten+[3]).pack( ('c na*'*ds.length)+'c').b
171
+ #Idx::Idx.each do |n|
172
+ # v = data[n.to_sym]&.to_s&.b
173
+ # sock.write [n.to_i, v.size, v].pack( 'c na*') if v
174
+ #end
175
+ #sock.write [3].pack( 'c')
176
+ #sock.flush
177
+ if 0 >= @logger.sev_threshold
178
+ @logger.debug "send data #{data.inspect}"
179
+ @logger.debug "send raw #{s.inspect}"
114
180
  end
115
- sock.write [3].pack( 'c')
116
- sock.flush
117
- STDERR.puts( {data: data, _: s}.inspect) if @debug
118
181
  rsock.write s
119
182
  rsock.flush
120
- end
183
+ end
121
184
 
122
185
  class RecordIO
123
186
  attr_reader :str
124
187
 
125
188
  def initialize sock, str = nil
126
- @str, @sock = str || '', sock
189
+ @str, @sock = str || ''.b, sock
127
190
  end
128
191
 
129
192
  def unpack pattern
130
- IOUnpack.new(pattern).unpack self
193
+ IOUnpack.new( pattern).unpack self
131
194
  end
132
195
 
133
196
  def unpack1 pattern
134
- IOUnpack.new(pattern).unpack1 self
197
+ IOUnpack.new( pattern).unpack1 self
135
198
  end
136
199
 
137
200
  def read n
138
201
  s = @sock.read n
139
- @str.insert -1, s
140
- s
202
+ @str.insert -1, s unless s.nil?
203
+ s || ''
141
204
  end
142
205
  end
143
206
 
144
207
  def rcv sock: nil
145
208
  ret, r = [], nil
146
209
  sock = sock || @sock
147
- sock = RecordIO.new sock if @debug
210
+ sock = RecordIO.new sock if 0 >= @logger.sev_threshold
148
211
  loop do
149
212
  t = sock.unpack1 'c'
150
213
  case t
@@ -153,7 +216,7 @@ class Knot::Protocol
153
216
  when 1, 2
154
217
  type = t
155
218
  ret.push( r = {})
156
- else
219
+ else
157
220
  raise Knot::Errors::EINVAL, "Missing Type before: #{t}" if ret.empty?
158
221
  i = Idx::Idx[t - 0x10] or raise Knot::Errors::EINVAL, "Unknown index: #{t-0x10}"
159
222
  l = sock.unpack1 'n'
@@ -161,13 +224,16 @@ class Knot::Protocol
161
224
  end
162
225
  end
163
226
  ensure
164
- STDERR.puts( {rcvd: ret, read: sock.str}.inspect) if @debug
227
+ if RecordIO === sock
228
+ @logger.debug "rcvd raw #{sock.str.inspect}"
229
+ @logger.debug "rcvd data #{ret.inspect}"
230
+ end
165
231
  ret
166
232
  end
167
233
 
168
234
  def call sock: nil, **data
169
235
  snd sock: sock, **data
170
- rcv( sock: sock).each do |r|
236
+ rcv( sock: sock).each do |r|
171
237
  if r[:error]
172
238
  if e = Knot::Errors.err2exc[r[:error]]
173
239
  raise e, r[:error]
@@ -179,10 +245,10 @@ class Knot::Protocol
179
245
 
180
246
  def zone( zone) @zones[zone.to_s.to_sym] end
181
247
 
182
- def conf_set( **opts) call **opts.update( command: 'conf-set') end
183
- def conf_unset( **opts) call **opts.update( command: 'conf-set') end
248
+ def conf_set( **opts) call **opts.update( command: 'conf-set') end
249
+ def conf_unset( **opts) call **opts.update( command: 'conf-unset') end
184
250
 
185
- def zone_set( **opts) call **opts.update( command: 'zone-set') end
251
+ def zone_set( **opts) call **opts.update( command: 'zone-set') end
186
252
  def zone_unset( **opts) call **opts.update( command: 'zone-unset') end
187
- def zone_get( **opts) call **opts.update( command: 'zone-get') end
253
+ def zone_get( **opts) call **opts.update( command: 'zone-get') end
188
254
  end
data/lib/knot/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Knot
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.1"
3
3
  end
data/lib/knot.rb CHANGED
@@ -2,3 +2,13 @@ require 'knot/version'
2
2
  require 'knot/errors'
3
3
  require 'knot/protocol'
4
4
  require 'knot/interface'
5
+
6
+ module Knot
7
+ class <<self
8
+ def new *as, **os
9
+ Protocol.new *as, **os
10
+ end
11
+ alias connect new
12
+ alias open new
13
+ end
14
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knot-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Knauf
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-09-26 00:00:00.000000000 Z
11
+ date: 2022-12-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: iounpack
@@ -57,15 +57,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - ">="
59
59
  - !ruby/object:Gem::Version
60
- version: 2.3.0
60
+ version: 2.7.0
61
61
  required_rubygems_version: !ruby/object:Gem::Requirement
62
62
  requirements:
63
63
  - - ">="
64
64
  - !ruby/object:Gem::Version
65
65
  version: '0'
66
66
  requirements: []
67
- rubyforge_project:
68
- rubygems_version: 2.7.6.2
67
+ rubygems_version: 3.2.5
69
68
  signing_key:
70
69
  specification_version: 4
71
70
  summary: Provides interface to knot-server.