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.