require_relative 'protocol' require_relative 'errors' module Knot end class Knot::Zone attr_reader :protocol, :zone def initialize zone, protocol = nil @protocol = protocol || Protocol.new @zone, @transaction_opened = zone, 0 end # If no transaction opened, yet, it opens a new transaction. # Counts calling begin. # Knot allowes only one global transaction, so if two clients tries to open a transaction, # the second will fail. But the second client can change items in the same # transaction like the first client. # The first client, which calls commit or abort, wins and the transaction will be closed. # So, the transaction-handling is only safe, if one client connects to knot. def begin @transaction_opened += 1 @protocol.call command: 'zone-begin', zone: @zone if 1 == @transaction_opened end # Decreases opened transactions. # If opened transactions is zero, it stores items and closes transaction successfully. def commit @protocol.call command: 'zone-commit', zone: @zone if 1 == @transaction_opened @transaction_opened -= 1 if 0 < @transaction_opened end # Closes transaction without saving immidiatly. # Counter of opened transaction will be reset to 0. def abort @protocol.call command: 'zone-abort', zone: @zone @transaction_opened = 0 end # Opens transaction, calls yielded Proc and closes transaction after return. # If exception was raised, the transaction will be aborted. def transaction # :yield: self.begin yield self rescue Object self.abort raise ensure self.commit unless $! end # zone operation def check() @protocol.call command: 'zone-check', zone: @zone end def reload() @protocol.call command: 'zone-reload', zone: @zone end def refresh() @protocol.call command: 'zone-refresh', zone: @zone end def notify() @protocol.call command: 'zone-notify', zone: @zone end def retransfer() @protocol.call command: 'zone-retransfer', zone: @zone end def sign() @protocol.call command: 'zone-sign', zone: @zone end def freeze() @protocol.call command: 'zone-freeze', zone: @zone end def thaw() @protocol.call command: 'zone-thaw', zone: @zone end def status( filter = nil) @protocol.call command: 'zone-status', zone: @zone, filter: filter end def stats( modul = nil, counter = nil) @protocol.call command: 'zone-stats', zone: @zone, module: modul, counter: counter end # zone manipulation def read() @protocol.call command: 'zone-read', zone: @zone end def diff() @protocol.call command: 'zone-diff', zone: @zone end # setting record # if data is nil, it will be unset. def set owner, ttl = nil, type, data @protocol.call command: data.nil? ? 'zone-unset' : 'zone-set', zone: @zone, owner: owner, ttl: ttl, type: type, data: data rescue Knot::Errors::EISRECORD, Knot::Errors::ENONODE, Knot::Errors::ENOENT end alias []= set def unset owner, type = nil, data = nil @protocol.call command: 'zone-unset', zone: @zone, owner: owner, type: type, data: data rescue Knot::Errors::ENONODE, Knot::Errors::ENOENT end alias delete unset alias del unset def get owner = nil, type = nil @protocol.call command: 'zone-get', zone: @zone, owner: owner, type: type rescue Knot::Errors::ENONODE, Knot::Errors::ENOENT nil end alias [] get end class Knot::Conf def initialize protocol = nil @protocol = protocol || Protocol.new @transaction_opened = 0 end def begin @transaction_opened += 1 @protocol.call command: 'conf-begin' if 1 == @transaction_opened end def commit @protocol.call command: 'conf-commit' if 1 == @transaction_opened @transaction_opened -= 1 if 0 < @transaction_opened end def abort @protocol.call command: 'conf-abort' @transaction_opened = 0 end def transaction self.begin yield self rescue Object self.abort raise ensure self.commit end def parse_item k case k when Hash case k.keys.sort when %w[section], %w[id section], %w[item section], %w[id item section] k else raise ArgumentError, "Invalid Item-format" end when Array case k.length when 1 then {section: k[0]} when 2 then {section: k[0], item: k[1]} when 3 then {section: k[0], id: k[1], item: k[2]} else raise ArgumentError, "Invalid Item-format" end when /\A (?
[a-z0-9_-]+ ) (?: \[ (? [a-z0-9_.-]+) \] )? (?: \. (?[a-z0-9_-]+) )? \z/xi $~.named_captures.delete_if {|_,v| v.nil? } else raise ArgumentError, "Invalid Item-format" end end def get item = nil @protocol.call (item ? parse_item( item) : {}).update( command: 'conf-get') end # Sets or adds a new value to item. # knot knows single-value items like `server.rundir` and multi-value items like `server.listen`. # If you set a single-value, it will replace the old value. On a multi-value, it will add it. def set item, value @protocol.call parse_item( item).update( command: 'conf-set', data: value) end # Removes value from item. If you provide a value, this value will be removed. def unset item, value = nil @protocol.call parse_item( item).update( command: 'conf-unset', data: value) end alias delete unset def list item = nil @protocol.call (item ? parse_item( item) : {}).update( command: 'conf-list') end def read item = nil @protocol.call (item ? parse_item( item) : {}).update( command: 'conf-read') end end