Algumas vezes me perguntei como fazer algumas coisas mais complexas em AIR de uma maneira rapida e segura, como por exemplo pegar informaçoes do usuario, conectar com um banco de dados (sem ser o nativo do AIR) como oracle,mssql… executar linha de comando, e outras coisas que só seriam possiveis utilizando alguma outra linguagem mais poderosa. Levando em conta que isto realmente era necessario para aumentar o “poder” do AIR e que o AMF fazia algo parecido, só que para a internet, resolvi criar uma classe em AS e uma função em Python que facilita a comunicação entre os dois (deixe o servidor python rodando de fundo e chame as funçoes dele
)
Primeiro a classe Python.as que pode ser baixada aqui :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | package { import com.adobe.serialization.json.JSON; import flash.net.Socket; /** * Classe para conexao com python utilizando socket * @author Armando Leopoldo Keller - (http://alkeller.wordpress.com) - alkeller@live.de */ public class Python extends Socket { // TODO: Implementar um metodo de retorno, verificando o tipo do retorno, e passando como parametro na funcao associada /** * Cria um novo Socket * @param host Host onde esta o socket * @param port Porta que esta o socket * @see flash.net.Socket * @usage var p:Python = new Python("10.1.1.23",2727); */ public function Python(host:String=null, port:uint=0) { super(host, port); host = null; port = 0; } /** * Chama uma funcao do python se o socket estiver conectado * @param func Nome da funcao a ser chamada no python * @param args Argumentos a serem chamados no python * @usage p.call("teste",{um:1,dois:2,tres:3}); * @usage p.call("teste"); */ public function call(func:String,args:Object=null):void { if(this.connected) { this.flush(); var obj:Object = new Object(); obj["funcao"] = func; for(var i:* in args) { if(args[i] is String) args[i] = "'"+args[i]+"'"; obj[i]=args[i]; } this.writeUTFBytes(JSON.encode(obj)); obj = null; } else throw new Error("Voce deve estar conectado ao socket.") this.flush(); } } } |
Depois é necessario a função em python que vai reconhecer o que está sendo chamado pelo flash, o arquivo pode ser baixado aqui :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import json; def executar(objeto): __arr__ = []; __str__ = ""; obj = json.loads(objeto); __str__ = str(obj["funcao"])+"("; obj.pop("funcao"); if len(obj.keys()) >;= 1: for k in obj: __arr__.append(str(k)+"="+str(obj[k])); for x in xrange(len(__arr__)-1): __str__ = __str__+__arr__[x]+","; __str__ = __str__ +__arr__[len(__arr__)-1]+")"; else: __str__ = __str__+")"; return __str__; |
Agora precisamos de um “servidor socket” rodando de fundo com as funçoes a serem chamadas, que pode ser baixado aqui :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | import socket import threading import json from JMF import executar class ClientThread ( threading.Thread ): def __init__ ( self, channel, details ): self.channel = channel self.details = details threading.Thread.__init__ ( self ); def run ( self ): print 'Conexao recebida: ', self.details [ 0 ] self.channel.send ( "resposta vinda do python" ) for x in xrange ( 10 ): string = self.channel.recv ( 1024 ) self.interpretaComando(string) self.channel.close(); print 'Conexao fechada: ', self.details [ 0 ] def interpretaComando(self,string): eval("self."+executar(str(string))); def testar(self,arg1,arg2): print "Chamou testar: "+str(arg1)+","+str(arg2); self.channel.send("Chamou testar: "+str(arg1)+","+str(arg2)); def pegaVariaveis(self): print "chamou pegaVariaveis" self.channel.send("chamou pegaVariaveis"); def pegarArray(self): print "Chamou pegar Array"; arr = ['a','b','c',1,2,3]; txt = json.dumps(arr); self.channel.send(txt); def pegarObj(self): print "Chamou pegar Objeto"; teste = {} teste["item1"] = "Primeiro item"; teste["item2"] = "Segundo item"; teste["numero"] = 2; self.channel.send(json.dumps(teste)); # Inicia o servidor server = socket.socket ( socket.AF_INET, socket.SOCK_STREAM ) server.bind ( ( socket.gethostbyname(socket.gethostname()), 2727 ) ) server.listen ( 5 ) print "Iniciando servidor..." while True: channel, details = server.accept() ClientThread ( channel, details).start() |
Pronto, agora só falta uma aplicação de exemplo chamando estas funçoes, que pode ser baixada aqui :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | <?xml version="1.0" encoding="utf-8"?>; <mx:WindowedApplication applicationComplete="iniciar()" xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:Script> <![CDATA[ import com.adobe.serialization.json.JSON; private var py:Python [Bindable] public var texto:String = "" public function iniciar():void { py = new Python(); py.addEventListener(ProgressEvent.SOCKET_DATA,onRecebe); py.addEventListener(Event.CONNECT,onConecta); py.addEventListener(IOErrorEvent.IO_ERROR,onErroIO); py.connect("10.1.1.3",2727); } public function onRecebe(e:ProgressEvent):void { var str:String = py.readUTFBytes(py.bytesAvailable); texto = str; py.flush(); } public function onConecta(e:Event):void { trace("Conectou") } private function chamarTeste():void { if(py.connected) py.call("testar",{arg1:"Argumento 1",arg2:"Argumento 2"}) else texto = "O socket esta desconectado"; } private function chamarPegaVariaveis():void { if(py.connected) py.call("pegaVariaveis") else texto = "O socket esta desconectado" } private function pegarArray():void { if(py.connected) py.call("pegarArray"); else texto = "O socket esta desconectado"; } private function pegarObj():void { if(py.connected) py.call("pegarObj"); else texto = "O socket esta desconectado"; } private function matarServer():void { py.close(); texto = "Desconectado" } public function onErroIO(e:IOErrorEvent):void { trace("Erro ao conectar com o socket"); } ]]> </mx:Script> <mx:VBox> <mx:HBox> <mx:Button label = "Testar" click = "chamarTeste()" /> <mx:Button label = "PegaVar" click = "chamarPegaVariaveis()" /> <mx:Button label = "pegarArray" click = "pegarArray()" /> <mx:Button label = "pegarObj" click = "pegarObj()" /> <mx:Button label = "Kill Server" click = "matarServer()" /> </mx:HBox> <mx:Text text="{texto}" width="100%" height="115"/> </mx:VBox> </mx:WindowedApplication> |
Claro que esta aplicação ainda está bastante simples, mas o objetivo é demonstrar como pode ser facil conectar o AS3 com Python utilizando socket, para quem não conhece python, vale a pena dar uma estudada, é uma linguagem muito util, poderosa, e simples, que é utilizada em diversos lugares, alguns exemplos bons são nasa e google (precisa mais ? ), agora mistura isso com AS3 (tem algo MUITO funcional e bonito).
Explicação rapida
A sintaxe é muito parecida com a Tweener (classe de tween) que ja é bastante conhecida, então creio que não deve ter muita dificuldade para utilizar esta classe. Sendo que para chamar uma função do python é só chamar instancia.call(“nome_da_funcao”,{nome_do_argumento:valor_do_argumento…….});
Se alguem tiver alguma duvida, ou sugestão para esta classe ou para futuras classes, deixe um comentario ou envie por email mesmo.
A formatação dos codigos ainda não está boa, mas esta melhorando (plugin do Windows Live Writer) se alguem conhecer algum plugin para formatar codigos que tenha suporte a AS, Python, PHP,e C me avisa.
Tags: Actionscript 3, AS 3.0, conexao, python, Socket
Como você já deve saber: não use eval. Use:
func = getattr(self, nomedafuncao)
func(*args, **kw)
Sim, esta parte do python foi feita somente para demonstração da funcionalidade do AS tanto que pode ser otimizado (e não seria utilizado deste modo em alguma aplicação real).
Mas de qualquer modo é bom que tenha comentado, assim isto fica mais claro.
14. Hello, i think that i saw you visited my web site so i came to “return the favor”.I am attempting to find things to improve my website!I suppose its ok to use a few of your ideas!!