Revision 258a439a
Added by Marc Dequènes almost 14 years ago
- ID 258a439a59e2be7ce7dcb2e68acf3b744e01f91f
bin/test_client | ||
---|---|---|
#ask "MapMaker", :search_slave, "/Zones/?", {:is_master => false}
|
||
#know? "MapMaker", :k1, "/Zones"
|
||
#know? "MapMaker", :k2, "/prout"
|
||
set_user "duck"
|
||
set_user "guihome"
|
||
ask "Clerk", :dns_info, "/Commands/DNS/INFO"
|
||
on_error do
|
||
puts "PLOUF"
|
lib/cyborghood-librarian/interface/0_base.rb | ||
---|---|---|
children.collect!{|i| i.camelize }
|
||
|
||
node children do
|
||
object_list = Proc.new do |*args|
|
||
object_list = Proc.new do |session, env, *args|
|
||
obj_name, options = args
|
||
options ||= {}
|
||
|
||
... | ... | |
end
|
||
|
||
on_request do |request|
|
||
request.reply.results = object_list.call
|
||
request.reply.results = object_list.call(request.session, request.env)
|
||
request.send_reply
|
||
end
|
||
|
||
attr_search_node do |criterias|
|
||
attr_search_node do |session, env, criterias|
|
||
{
|
||
:post_filter => false,
|
||
:list => object_list.call(:search, :criterias => criterias, :format => :data_hash)
|
||
:list => object_list.call(session, env, :search,
|
||
:criterias => criterias,
|
||
:format => :data_hash)
|
||
}
|
||
end
|
||
|
||
node object_list do
|
||
on_request do |request|
|
||
request.reply.results = object_list.call(node_name, :format => :data_hash)
|
||
request.reply.results = object_list.call(request.session, request.env,
|
||
node_name,
|
||
:format => :data_hash)
|
||
request.send_reply
|
||
end
|
||
end
|
lib/cyborghood-mapmaker/interface/0_base.rb | ||
---|---|---|
node 'Services', :dir => 'services'
|
||
|
||
node 'Zones' do
|
||
zone_list = Proc.new do
|
||
zone_list = Proc.new do |session, env|
|
||
store.dns.flush_cache
|
||
store.dns.zones
|
||
end
|
lib/cyborghood/cyborg/botnet/conversation.rb | ||
---|---|---|
require 'cyborghood/cyborg/botnet/session'
|
||
require 'cyborghood/cyborg/botnet/protocol'
|
||
require 'set'
|
||
require 'thread'
|
||
|
||
|
||
module CyborgHood
|
||
... | ... | |
end
|
||
|
||
# convenience method
|
||
def call(*args, &callback)
|
||
@conversation.protocol.send_request_call(self, *args, &callback)
|
||
def call(env, node, *args, &callback)
|
||
@conversation.protocol.send_request_call(self, env, node, *args, &callback)
|
||
end
|
||
|
||
# convenience method
|
||
def exists?(node, &callback)
|
||
@conversation.protocol.send_request_exists(self, node, &callback)
|
||
def exists?(env, node, &callback)
|
||
@conversation.protocol.send_request_exists(self, env, node, &callback)
|
||
end
|
||
|
||
# convenience method
|
lib/cyborghood/cyborg/botnet/dsl.rb | ||
---|---|---|
def ask(peer, key, cmd, *args)
|
||
action_name = ['ask', cmd, *args].hash
|
||
|
||
_add_subtask_using_peer(action_name, peer) do |subtask, conv_thread|
|
||
conv_thread.call(cmd, *args) do |reply|
|
||
_add_subtask_using_peer(action_name, peer) do |subtask, conv_thread, env|
|
||
cmd = cmd.call if cmd.is_a? Proc
|
||
args.collect!{|a| a.is_a?(Proc) ? a.call : a }
|
||
|
||
conv_thread.call(env, cmd, *args) do |reply|
|
||
case reply[:status]
|
||
when :ok
|
||
subtask.results = {key => reply[:result]}
|
||
... | ... | |
def know?(peer, key, cmd)
|
||
action_name = ['know', cmd].hash
|
||
|
||
_add_subtask_using_peer(action_name, peer) do |subtask, conv_thread|
|
||
conv_thread.exists?(cmd) do |reply|
|
||
_add_subtask_using_peer(action_name, peer) do |subtask, conv_thread, env|
|
||
cmd = cmd.call if cmd.is_a? Proc
|
||
|
||
conv_thread.exists?(env, cmd) do |reply|
|
||
case reply[:status]
|
||
when :ok
|
||
subtask.results = {key => reply[:result]}
|
||
... | ... | |
registered_resources[subtask_name] = defuse_peer_action_cb
|
||
end
|
||
|
||
# catch current environment to transmit it
|
||
env = {
|
||
:preferred_locales => @preferred_locales,
|
||
:user => @user
|
||
}
|
||
|
||
@bot.contact_peer(peer) do |conv|
|
||
if conv
|
||
logger.debug "Task '#{@name}': subtask '#{subtask.name}': peer '#{peer}' contacted, starting conversation"
|
||
... | ... | |
# don't use the block call to leave the conversation thread open
|
||
conv_thread = conv.thread(@notification_name)
|
||
|
||
yield(subtask, conv_thread)
|
||
yield(subtask, conv_thread, env)
|
||
else
|
||
logger.debug "Task '#{@name}': Could not contact peer '#{peer}'"
|
||
subtask.errors << CyberError.new(:unrecoverable, "botnet/client/dsl", "Task '#{@name}': could not contact peer '#{peer}'")
|
lib/cyborghood/cyborg/botnet/interface.rb | ||
---|---|---|
node '?', :hidden => true do
|
||
on_request do |request|
|
||
if request.args.empty?
|
||
request.reply.results = lookup_node.__send__(:visible_nodes_names)
|
||
request.reply.results = lookup_node.__send__(:visible_nodes_names, request)
|
||
else
|
||
request.reply.results = list.nil? ? search_among_children(request, lookup_node) :
|
||
search_in_list(request, lookup_node, list)
|
||
... | ... | |
@request_cb = cb
|
||
end
|
||
|
||
def _is_node?(session, node_path)
|
||
node = __send__(:find_node, session, node_path)
|
||
def _is_node?(session, env, node_path)
|
||
node = __send__(:find_node, session, env, node_path)
|
||
not node.nil?
|
||
end
|
||
|
||
def _call(session, node_path, args = nil, &send_result_cb)
|
||
def _call(session, env, node_path, args = nil, &send_result_cb)
|
||
args ||= []
|
||
raise CyberError.new(:unrecoverable, 'api/cyborghood', "wrong format for arguments when calling node '#{node_path}'") unless args.is_a? Array
|
||
|
||
node = find_node(session, node_path)
|
||
node = find_node(session, env, node_path)
|
||
raise CyberError.new(:unrecoverable, 'api/cyborghood', "unknown node '#{node_path}'") if node.nil?
|
||
|
||
logger.debug "[Server API] Node '#{node_path}' found"
|
||
node.__send__(:request, session, args, &send_result_cb)
|
||
|
||
# TODO: validate environment and setup things (choosen locale for example)
|
||
|
||
node.__send__(:request, session, env, args, &send_result_cb)
|
||
end
|
||
|
||
protected
|
||
... | ... | |
end
|
||
end
|
||
|
||
def find_node(session, node_path)
|
||
def find_node(session, env, node_path)
|
||
# node_path is a string argument when interface root node is called, but is a list of node elements later on
|
||
if root?
|
||
logger.debug "[Server API] Looking for node '#{node_path}'"
|
||
... | ... | |
if node_element.nil?
|
||
return self
|
||
else
|
||
next_node = find_child_node(node_element)
|
||
next_node = find_child_node(session, env, node_element)
|
||
if next_node
|
||
next_node.__send__(:load, node_element)
|
||
return next_node.__send__(:find_node, session, node_path)
|
||
return next_node.__send__(:find_node, session, env, node_path)
|
||
else
|
||
return
|
||
end
|
||
end
|
||
end
|
||
|
||
def find_child_node(child_node)
|
||
def find_child_node(session, env, child_node)
|
||
return @nodes[child_node] if @nodes.has_key? child_node
|
||
|
||
@nodes.each_pair do |match, node|
|
||
... | ... | |
elsif match.is_a? Regexp
|
||
child_node =~ Regexp.new(match)
|
||
elsif match.is_a? Proc
|
||
match.call.include? child_node
|
||
match.call(session, env).include? child_node
|
||
end
|
||
return node if found
|
||
end
|
||
... | ... | |
end
|
||
|
||
class Request
|
||
attr_reader :session, :args, :reply
|
||
attr_reader :session, :env, :args, :reply
|
||
|
||
def initialize(session, args = [], &send_result_cb)
|
||
def initialize(session, env, args = [], &send_result_cb)
|
||
@session = session
|
||
@env = env.to_ostruct
|
||
@args = args
|
||
@send_result_cb = send_result_cb
|
||
|
||
... | ... | |
end
|
||
end
|
||
|
||
def request(session, args = [], &send_result_cb)
|
||
request = Request.new(session, args, &send_result_cb)
|
||
def request(session, env, args = [], &send_result_cb)
|
||
request = Request.new(session, env, args, &send_result_cb)
|
||
|
||
if @request_cb
|
||
begin
|
||
... | ... | |
raise CyberError.new(:unrecoverable, 'api/cyborghood', "call failed on node '#{node_path}': " + $!)
|
||
end
|
||
else
|
||
request.reply.results = visible_nodes_names
|
||
request.reply.results = visible_nodes_names(request)
|
||
request.send_reply
|
||
end
|
||
end
|
||
... | ... | |
Hash[@nodes.select{|match, node| not node.hidden? }]
|
||
end
|
||
|
||
def node_match_to_name(match)
|
||
def node_match_to_name(request, match)
|
||
if match.is_a? String
|
||
match
|
||
elsif match.is_a? Regexp
|
||
'/' + match.to_s + '/'
|
||
elsif match.is_a? Proc
|
||
match.call
|
||
match.call(request.session, request.env)
|
||
end
|
||
end
|
||
|
||
def visible_nodes_names
|
||
def visible_nodes_names(request)
|
||
visible_nodes.keys.collect do |match|
|
||
node_match_to_name(match)
|
||
node_match_to_name(request, match)
|
||
end.compact.flatten
|
||
end
|
||
|
||
... | ... | |
if match.is_a? String
|
||
match_list = [match]
|
||
elsif match.is_a? Proc
|
||
match_list = match.call
|
||
match_list = match.call(request.session, request.env)
|
||
else
|
||
next
|
||
end
|
||
|
||
# TODO: filter by auth token
|
||
match_list.each do |child_node_name|
|
||
node.__send__(:load, child_node_name)
|
||
result = node.__send__(:request, request.session)
|
||
result = node.__send__(:request, request.session, request.env)
|
||
next unless result.respond_to? :to_hash
|
||
|
||
child_node_attrs = result.to_hash
|
||
... | ... | |
return {} unless criterias.is_a? Hash
|
||
|
||
if list.is_a? Proc
|
||
data = list.call(criterias)
|
||
data = list.call(request.session, request.env, criterias)
|
||
|
||
return data[:list] unless data[:post_filter]
|
||
end
|
lib/cyborghood/cyborg/botnet/protocol.rb | ||
---|---|---|
@conversation.bot.schedule_task do
|
||
begin
|
||
@conversation.bot.interface._call(message.conv_thread.session,
|
||
message.action_parameters[:node],
|
||
message.action_parameters[:parameters],
|
||
&process_result_cb)
|
||
message.action_parameters[:environment],
|
||
message.action_parameters[:node],
|
||
message.action_parameters[:parameters],
|
||
&process_result_cb)
|
||
rescue CyberError => e
|
||
process_result_cb.call(:errors => [{
|
||
:category => e.category,
|
||
... | ... | |
:message => "missing parameters"
|
||
})
|
||
end
|
||
|
||
send_reply_ack(message)
|
||
|
||
@conversation.bot.schedule_task(@@request_callback) do
|
||
{
|
||
:reply_message => message,
|
||
:results => @conversation.bot.interface._is_node?(message.conv_thread.session, message.action_parameters[:node])
|
||
:results => @conversation.bot.interface._is_node?(message.conv_thread.session,
|
||
message.action_parameters[:environment],
|
||
message.action_parameters[:node])
|
||
}
|
||
end
|
||
end
|
||
... | ... | |
@conversation.thread('system').new_message("REQUEST EXISTS", { :node => node }).send
|
||
end
|
||
|
||
def send_request_call(conv_thread, node, *parameters, &callback)
|
||
message = conv_thread.new_message("REQUEST CALL", { :node => node, :parameters => parameters }).send
|
||
def send_request_call(conv_thread, env, node, *parameters, &callback)
|
||
message = conv_thread.new_message("REQUEST CALL", {
|
||
:node => node,
|
||
:parameters => parameters,
|
||
:environment => env
|
||
}).send
|
||
message.register_callback(callback)
|
||
end
|
||
|
||
def send_request_exists(conv_thread, node, &callback)
|
||
message = conv_thread.new_message("REQUEST EXISTS", { :node => node }).send
|
||
def send_request_exists(conv_thread, env, node, &callback)
|
||
message = conv_thread.new_message("REQUEST EXISTS", {
|
||
:node => node,
|
||
:environment => env
|
||
}).send
|
||
message.register_callback(callback)
|
||
end
|
||
|
||
def send_request_describe(conv_thread, node)
|
||
message = conv_thread.new_message("REQUEST DESCRIBE", { :node => node }).send
|
||
def send_request_describe(conv_thread, env, node)
|
||
message = conv_thread.new_message("REQUEST DESCRIBE", {
|
||
:node => node,
|
||
:environment => env
|
||
}).send
|
||
message.register_callback(callback)
|
||
end
|
||
|
lib/cyborghood/cyborg/botnet/session.rb | ||
---|---|---|
end
|
||
obj
|
||
end
|
||
|
||
def to_hash
|
||
Hash[self]
|
||
end
|
||
end
|
||
end
|
||
end
|
Also available in: Unified diff
[evol] Botnet: propagate API calls environment (user token and language prefs at the moment), propagate session a bit further too in order to implement a more dynamic API tree