root/lib/cyborghood/cyborg/botnet/interface.rb @ afdc8d97
d1e614b5 | Marc Dequènes (Duck) | #--
|
|
# CyborgHood, a distributed system management software.
|
|||
# Copyright (c) 2009-2010 Marc Dequènes (Duck) <Duck@DuckCorp.org>
|
|||
#
|
|||
# This program is free software: you can redistribute it and/or modify
|
|||
# it under the terms of the GNU General Public License as published by
|
|||
# the Free Software Foundation, either version 3 of the License, or
|
|||
# (at your option) any later version.
|
|||
#
|
|||
# This program is distributed in the hope that it will be useful,
|
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
# GNU General Public License for more details.
|
|||
#
|
|||
# You should have received a copy of the GNU General Public License
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#++
|
|||
require 'singleton'
|
|||
7466fc08 | Marc Dequènes (Duck) | require 'ostruct'
|
|
d1e614b5 | Marc Dequènes (Duck) | ||
module CyborgHood
|
|||
7466fc08 | Marc Dequènes (Duck) | module DSL
|
|
class ServerApiNode < BaseDSL
|
|||
afdc8d97 | Marc Dequènes (Duck) | attr_reader :bot, :node_name
|
|
8fcaacd6 | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | # needed for testing node existence
|
|
reveal :nil?
|
|||
476368e8 | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | def initialize(bot, parent_node = nil, &block)
|
|
@bot = bot
|
|||
@parent_node = parent_node
|
|||
# don't call super because we need defered loading
|
|||
@blocks = [block]
|
|||
a3483167 | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | cleanup
|
|
a3483167 | Marc Dequènes (Duck) | end
|
|
8fcaacd6 | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | def add_behavior(&block)
|
|
@blocks << block
|
|||
8fcaacd6 | Marc Dequènes (Duck) | end
|
|
7466fc08 | Marc Dequènes (Duck) | # string, array (useful for aliases), or regex
|
|
# TODO: name validation
|
|||
def node(match, &block)
|
|||
child_node = self.class.new(@bot, self, &block)
|
|||
if match.is_a? Array
|
|||
match.each{|n| @nodes[n] = child_node}
|
|||
else
|
|||
@nodes[match] = child_node
|
|||
end
|
|||
8fcaacd6 | Marc Dequènes (Duck) | end
|
|
69a12fdb | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | def on_request(&cb)
|
|
@request_cb = cb
|
|||
69a12fdb | Marc Dequènes (Duck) | end
|
|
d1e614b5 | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | def _is_node?(session, node_path)
|
|
node = __send__(:find_node, session, node_path)
|
|||
not node.nil?
|
|||
end
|
|||
69a12fdb | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | def _call(session, node_path, args = nil)
|
|
args ||= []
|
|||
raise CyberError.new(:unrecoverable, 'api/cyborghood', "wrong format for arguments") unless args.is_a? Array
|
|||
d1e614b5 | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | node = find_node(session, node_path)
|
|
raise CyberError.new(:unrecoverable, 'api/cyborghood', "unknown node") if node.nil?
|
|||
d1e614b5 | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | logger.debug "[Server API] Node '#{node_path}' found"
|
|
afdc8d97 | Marc Dequènes (Duck) | node.__send__(:request, session, args)
|
|
7466fc08 | Marc Dequènes (Duck) | end
|
|
23b2305f | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | protected
|
|
23b2305f | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | def root?
|
|
@parent_node.nil?
|
|||
end
|
|||
23b2305f | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | def load(node_element = '')
|
|
cleanup
|
|||
@node_name = node_element
|
|||
@blocks.each do |bl|
|
|||
instance_eval &bl
|
|||
end
|
|||
end
|
|||
1c89625f | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | def find_node(session, node_path)
|
|
# it is a string argument when interface root is called, but a list of node elemnts later
|
|||
if root?
|
|||
logger.debug "[Server API] Looking for node '#{node_path}'"
|
|||
node_path = node_path.split("/")
|
|||
# remove empty string before first "/"
|
|||
node_path.shift
|
|||
# initial load
|
|||
load
|
|||
end
|
|||
41802ec1 | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | node_element = node_path.shift
|
|
logger.debug "[Server API] Looking for node element '#{node_element}'"
|
|||
if node_element.nil?
|
|||
return self
|
|||
41802ec1 | Marc Dequènes (Duck) | else
|
|
7466fc08 | Marc Dequènes (Duck) | next_node = find_child_node(node_element)
|
|
if next_node
|
|||
next_node.__send__(:load, node_element)
|
|||
return next_node.__send__(:find_node, session, node_path)
|
|||
else
|
|||
return
|
|||
end
|
|||
41802ec1 | Marc Dequènes (Duck) | end
|
|
end
|
|||
7466fc08 | Marc Dequènes (Duck) | def find_child_node(child_node)
|
|
return @nodes[child_node] if @nodes.has_key? child_node
|
|||
@nodes.each_pair do |match, node|
|
|||
found = if match.is_a? String
|
|||
child_node == match
|
|||
elsif match.is_a? Regexp
|
|||
child_node =~ Regexp.new(match)
|
|||
elsif match.is_a? Proc
|
|||
match.call.include? child_node
|
|||
end
|
|||
return node if found
|
|||
end
|
|||
f94d64b1 | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | nil
|
|
d1e614b5 | Marc Dequènes (Duck) | end
|
|
7466fc08 | Marc Dequènes (Duck) | class Request
|
|
attr_reader :session, :args, :reply
|
|||
b7f7d214 | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | def initialize(session, args)
|
|
@session = session
|
|||
@args = args
|
|||
b7f7d214 | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | @reply = {
|
|
:results => {},
|
|||
:infos => [],
|
|||
:warnings => [],
|
|||
:errors => []
|
|||
}.to_ostruct
|
|||
b7f7d214 | Marc Dequènes (Duck) | end
|
|
end
|
|||
7466fc08 | Marc Dequènes (Duck) | def request(session, args)
|
|
if @request_cb
|
|||
request = Request.new(session, args)
|
|||
begin
|
|||
@request_cb.call(request)
|
|||
# TODO: full reply needed
|
|||
request.reply.results
|
|||
rescue
|
|||
logger.debug "node request error message: " + $!
|
|||
logger.debug "node request error backtrace: " + $!.backtrace.join("\n")
|
|||
raise CyberError.new(:unrecoverable, 'api/cyborghood', "method call failed: " + $!)
|
|||
b7f7d214 | Marc Dequènes (Duck) | end
|
|
7466fc08 | Marc Dequènes (Duck) | else
|
|
@nodes.keys.collect do |match|
|
|||
if match.is_a? String
|
|||
match
|
|||
elsif match.is_a? Regexp
|
|||
'/' + match.to_s + '/'
|
|||
elsif match.is_a? Proc
|
|||
match.call
|
|||
end
|
|||
end.compact.flatten
|
|||
b7f7d214 | Marc Dequènes (Duck) | end
|
|
end
|
|||
d1e614b5 | Marc Dequènes (Duck) | ||
7466fc08 | Marc Dequènes (Duck) | def cleanup
|
|
@nodes = {}
|
|||
@request_cb = nil
|
|||
a3483167 | Marc Dequènes (Duck) | end
|
|
end
|
|||
d1e614b5 | Marc Dequènes (Duck) | end
|
|
end
|