Project

General

Profile

Download (5.06 KB) Statistics
| Branch: | Tag: | Revision:
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'


module CyborgHood
bc473567 Marc Dequènes (Duck)
module CyborgServerInterface
def self.included(base)
8fcaacd6 Marc Dequènes (Duck)
base.class_eval("include CyborgServerInterfaceBase")
bc473567 Marc Dequènes (Duck)
base.class_eval("include Singleton")
8fcaacd6 Marc Dequènes (Duck)
end
end

module CyborgServerEmbededInterface
def self.included(base)
base.class_eval("include CyborgServerInterfaceBase")
base.export_parent_methods
end
end

module CyborgServerInterfaceBase
NODE_PATTERN = "([a-zA-Z0-9._]+(?:\/[a-zA-Z0-9._]+)*[?=]?)"

def self.included(base)
bc473567 Marc Dequènes (Duck)
base.extend(ClassMethods)
end
d1e614b5 Marc Dequènes (Duck)
1c89625f Marc Dequènes (Duck)
module ClassMethods
a3483167 Marc Dequènes (Duck)
attr_accessor :exported_methods
attr_accessor :auto_export_public_instance_methods

def export_method(syms)
syms = [syms] unless syms.is_a? Array
self.exported_methods ||= []
self.exported_methods += syms.collect{|m| m.to_s }
end
8fcaacd6 Marc Dequènes (Duck)
def unexport_method(syms)
syms = [syms] unless syms.is_a? Array
self.exported_methods ||= []
self.exported_methods -= syms.collect{|m| m.to_s }
end

def export_parent_methods
self.export_method self.superclass.public_instance_methods(false)
end
ce98dac2 Marc Dequènes (Duck)
end

8fcaacd6 Marc Dequènes (Duck)
def initialize(*args)
super(*args)

d1e614b5 Marc Dequènes (Duck)
@config = Config.instance
a3483167 Marc Dequènes (Duck)
self.class.exported_methods ||= []
self.class.auto_export_public_instance_methods = true
d1e614b5 Marc Dequènes (Duck)
end

1c89625f Marc Dequènes (Duck)
def api_klasses
list = self.class.constants.collect do |c|
d1e614b5 Marc Dequènes (Duck)
cc = self.class.const_get(c)
8fcaacd6 Marc Dequènes (Duck)
(cc.class == Class and cc.ancestors.include? CyborgHood::CyborgServerInterfaceBase) ? [c, cc] : nil
1c89625f Marc Dequènes (Duck)
end.compact
Hash[list]
d1e614b5 Marc Dequènes (Duck)
end

def api_methods
a3483167 Marc Dequènes (Duck)
methods = self.class.exported_methods
methods += self.class.public_instance_methods(false) if self.class.auto_export_public_instance_methods
methods & self.methods
d1e614b5 Marc Dequènes (Duck)
end

1c89625f Marc Dequènes (Duck)
def api_nodes
(api_klasses.keys + api_methods).sort
end

41802ec1 Marc Dequènes (Duck)
def find_node_action(node_name)
8fcaacd6 Marc Dequènes (Duck)
next_node_name, other_nodes_names = node_name.split('/', 2)
41802ec1 Marc Dequènes (Duck)
next_node_klass = api_klasses[next_node_name]
8fcaacd6 Marc Dequènes (Duck)
# inner class or method ?
41802ec1 Marc Dequènes (Duck)
if next_node_klass.nil?
8fcaacd6 Marc Dequènes (Duck)
# method is declared ?
41802ec1 Marc Dequènes (Duck)
if api_methods.include? next_node_name
8fcaacd6 Marc Dequènes (Duck)
# final node ?
if other_nodes_names.nil?
# cannot use method(), as this method may not exist at all (but still
# be usuable through metaprogramming
return lambda do |*args|
r = self.send(next_node_name, *args)
# dynamic tree construction: method may return a node
if r.class.ancestors.include? CyborgHood::CyborgServerInterfaceBase
r.api_nodes
else
r
end
end
end
next_node = self.send(next_node_name)
41802ec1 Marc Dequènes (Duck)
else
8fcaacd6 Marc Dequènes (Duck)
# unknown method
41802ec1 Marc Dequènes (Duck)
return
end
else
next_node = next_node_klass.instance
8fcaacd6 Marc Dequènes (Duck)
# final node ?
41802ec1 Marc Dequènes (Duck)
return next_node.method('api_nodes') if other_nodes_names.nil?
end

8fcaacd6 Marc Dequènes (Duck)
# search deeper
if next_node.class.ancestors.include? CyborgHood::CyborgServerInterfaceBase
next_node.find_node_action(other_nodes_names)
else
# it is not a node, so there are no children
return
end
41802ec1 Marc Dequènes (Duck)
end

def has_node?(cmd)
not find_node_action(cmd).nil?
end

d1e614b5 Marc Dequènes (Duck)
# preliminary incoming message handling
f94d64b1 Marc Dequènes (Duck)
def call(cmd, data)
1c89625f Marc Dequènes (Duck)
action = find_node_action(cmd)
return "551 unknown node" if action.nil?
d1e614b5 Marc Dequènes (Duck)
a3483167 Marc Dequènes (Duck)
if data.nil?
formated_data = []
else
begin
formated_data = YAML.load(data) unless data.nil?
rescue
1c89625f Marc Dequènes (Duck)
return "552 unreadable YAML data for arguments"
a3483167 Marc Dequènes (Duck)
end
ce98dac2 Marc Dequènes (Duck)
a3483167 Marc Dequènes (Duck)
return "552 wrong format for arguments" unless formated_data.is_a? Array
end
f94d64b1 Marc Dequènes (Duck)
d1e614b5 Marc Dequènes (Duck)
begin
# preliminary outgoing message handling
1c89625f Marc Dequènes (Duck)
action.call(*formated_data).to_yaml
d1e614b5 Marc Dequènes (Duck)
rescue
1c89625f Marc Dequènes (Duck)
return "550 method call failed: " + $!
d1e614b5 Marc Dequènes (Duck)
end
end
end

bc473567 Marc Dequènes (Duck)
module CyborgServerDefaultInterface
ce98dac2 Marc Dequènes (Duck)
PROTOCOL_VERSION = "0.1~"
d1e614b5 Marc Dequènes (Duck)
a3483167 Marc Dequènes (Duck)
def self.included(base)
list = self.public_instance_methods(false)
base.class_eval do
export_method list
end
end

def product_name
d1e614b5 Marc Dequènes (Duck)
PRODUCT
end

a3483167 Marc Dequènes (Duck)
def product_version
d1e614b5 Marc Dequènes (Duck)
VERSION
end

a3483167 Marc Dequènes (Duck)
def protocol_version
ce98dac2 Marc Dequènes (Duck)
PROTOCOL_VERSION
d1e614b5 Marc Dequènes (Duck)
end

a3483167 Marc Dequènes (Duck)
def bot_name
d1e614b5 Marc Dequènes (Duck)
@config.bot_name
end
end
end