knot-ruby 0.1.2 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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.