require 'whiteboard.rb' class RemoteSimpleAPI class CallingTransaction def initialize(app,txid) @app=app @txid=txid end def sendResult(r) @app.sendResult(@txid,r) end end class SentTransaction TIMEOUT=10 # def initialize(app,txid,from) @app=app @from=from @txid=txid end # waits for the return value def wait(timeout=nil) timeout||=TIMEOUT @app.getFromWhiteboard(@txid,@from,timeout) end def valueAvailable? raise :NotImplementedYet # FIXME end end class Service # this function should not be called except through RewmoteSimpleAPI::hook(.) def initialize(app,sname,pblock) @app=app @sname=sname @block=pblock end # call service with *args and don't return anything - you won't get any info, if this succeeded def sendAsync(node,*args) @app.sendAsync(node,@sname,*data) end # sends *data to *node* and returns a SentTransaction value def send(node,*data) @app.send(node,@sname,*data) end # closes the service def close @app.closeService(self) end def name @sname end def block @block end end def initialize(node) @node=node @txCount=0 @txMutex=Mutex.new @services=[] @node.addReceiver(self) {|from,args| receive(from,args) } @whiteboard=Whiteboard.new end def me @node.me end # close the api-object - api won't listen anymore def close @node.removeReceiver(self) end # hook up a new service with the given name and block - returns # a Service object for simple handling of this service def hook(serviceName,&block) service=Service.new(self,serviceName,block) @services << service service end # send data to all hooks with name "serviceName" on node *node* def send(node,serviceName,*data) txid=nil txid=getTxCount sdata=Secure::Marshal::dump([false,serviceName,txid,*data]) @node.sendMessage(sdata,node) SentTransaction.new(self,txid,node) end def sendAsync(node,serviceName,*data) txid=nil data=Secure::Marshal::dump([false,serviceName,txid,*data]) @node.sendMessage(data,node) nil end def closeService(service) @services.delete(service) end def getFromWhiteboard(tx,from,timeout) log "getFromWhiteboard #{tx} #{from}" @whiteboard.get([tx,from],timeout) end def stop end private def getTxCount id=nil @txMutex.synchronize { id=@txCount+=1 } id end def receive(from,args) args=Secure::Marshal.load(args) #log "API RECEIVED",args.inspect #log "FROM #{from}" assert{args.is_a?(Array)} if args[0]==false call(from,args[1..-1]) else pushReturn(from,args[1..-1]) end end def log(*x) @node.log(*x) end # call local function of service def call(from,args) serviceName,tx,*args=args @services.each{|service| if service.name==serviceName result=service.block.call(*args) if tx sendReturn(from,tx,result) end end } end # put return value into whiteboard for retrieval def pushReturn(from,args) name,tx,value=args @whiteboard.put([tx,from],value) end # send return value back to calling node def sendReturn(from,tx,result) data=Secure::Marshal::dump([true,nil,tx,result]) @node.sendMessage(data,from) end end