Project

General

Profile

Download (4.93 KB) Statistics
| Branch: | Tag: | Revision:
#--
# 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'
require 'ostruct'


module CyborgHood
module DSL
class ServerApiNode < BaseDSL
attr_reader :bot, :node_name

# needed for testing node existence
reveal :nil?

def initialize(bot, parent_node = nil, &block)
@bot = bot
@parent_node = parent_node
# don't call super because we need defered loading
@blocks = [block]

cleanup
end

def add_behavior(&block)
@blocks << block
end

# 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
end

def on_request(&cb)
@request_cb = cb
end

def _is_node?(session, node_path)
node = __send__(:find_node, session, node_path)
not node.nil?
end

def _call(session, node_path, args = nil)
args ||= []
raise CyberError.new(:unrecoverable, 'api/cyborghood', "wrong format for arguments") unless args.is_a? Array

node = find_node(session, node_path)
raise CyberError.new(:unrecoverable, 'api/cyborghood', "unknown node") if node.nil?

logger.debug "[Server API] Node '#{node_path}' found"
node.__send__(:request, session, args)
end

protected

def root?
@parent_node.nil?
end

def load(node_element = '')
cleanup
@node_name = node_element
@blocks.each do |bl|
instance_eval &bl
end
end

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

node_element = node_path.shift
logger.debug "[Server API] Looking for node element '#{node_element}'"
if node_element.nil?
return self
else
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
end
end

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

nil
end

class Request
attr_reader :session, :args, :reply

def initialize(session, args)
@session = session
@args = args

@reply = {
:results => {},
:infos => [],
:warnings => [],
:errors => []
}.to_ostruct
end
end

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: " + $!)
end
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
end
end

def cleanup
@nodes = {}
@request_cb = nil
end
end
end
end
(3-3/5)