Project

General

Profile

« Previous | Next » 

Revision 258a439a

Added by Marc Dequènes over 13 years ago

  • ID 258a439a59e2be7ce7dcb2e68acf3b744e01f91f

[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

View differences:

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