From df197dab408e09910a6cb2aa09fe92990c7d6d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20P=C3=A5lsson?= Date: Mon, 14 Feb 2011 17:45:56 +0100 Subject: [PATCH 1/5] Switched over to new protocol module --- src/ggs_protocol.erl | 16 +++++++++++++--- src/ggs_server.erl | 40 ++++++++++++++++------------------------ 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/ggs_protocol.erl b/src/ggs_protocol.erl index 46c1ba1..35da585 100644 --- a/src/ggs_protocol.erl +++ b/src/ggs_protocol.erl @@ -1,10 +1,20 @@ -module(ggs_protocol). --export([parse/1]). +-export([parse/1, getToken/1]). +%% API Functions parse(Data) -> Parsed = do_parse(Data, []), prettify(Parsed). +getToken(Parsed) -> + case lists:keyfind(token, 1, Parsed) of + {_, Value} -> + Value; + false -> + false + end. + +%% Internal helpers do_parse(Data, ParsedMessage) -> NewLinePos = string:chr(Data, $\n), Line = string:substr(Data, 1, NewLinePos-1), @@ -15,7 +25,8 @@ do_parse(Data, ParsedMessage) -> {separator, data_next} -> {_, Value} = lists:keyfind(content_len, 1, ParsedMessage), {ContentLength, []} = string:to_integer(Value), - {ParsedMessage, handle_data(string:substr(Data, NewLinePos+1), ContentLength)} + {data, ArgumentData} = handle_data(string:substr(Data, NewLinePos+1), ContentLength), + {ParsedMessage, ArgumentData} end. handle([[]]) -> @@ -33,7 +44,6 @@ handle_data(Data, Length) -> {data, string:substr(Data,1,Length)}. -%% Helpers prettify({Args, Data}) -> case lists:keyfind(srv_cmd, 1, Args) of {_, Value} -> diff --git a/src/ggs_server.erl b/src/ggs_server.erl index 4a116fa..f8eae1e 100644 --- a/src/ggs_server.erl +++ b/src/ggs_server.erl @@ -1,10 +1,3 @@ -%%%---------------------------------------------------- -%%% @author Jonatan Pålsson -%%% @copyright 2010 Jonatan Pålsson -%%% @doc RPC over TCP server -%%% @end -%%%---------------------------------------------------- - -module(ggs_server). -behaviour(gen_server). @@ -95,37 +88,36 @@ handle_cast(stop, State) -> {stop, normal, State}; % Handle javascript defines -handle_cast({srv_cmd, "define", Args, Data}, State) -> - %JSVM = getJSVM(Token, State), - %js_runner:define(JSVM, Payload), +handle_cast({srv_cmd, "define", Headers, Data}, State) -> + Token = ggs_protocol:getToken(Headers), + JSVM = getJSVM(Token, State), + js_runner:define(JSVM, Data), send(State#state.lsock, "Token", "Okay, defined that for you!"), {noreply, State}; % Handle javascript calls -handle_cast({srv_cmd, "call", Args, Data}, State) -> - %io:format("Got call request: ~p~n", [Payload]), - %JSVM = getJSVM(Token, State), - %erlang:display(erlang:port_info(JSVM)), - %{ok, Ret} = js_runner:call(JSVM, Payload, []),%Payload, []), - %send(State#state.lsock, Token, "JS says:", binary_to_list(Ret)), +handle_cast({srv_cmd, "call", Headers, Data}, State) -> + Token = ggs_protocol:getToken(Headers), + io:format("Got call request: ~p~n", [Data]), + JSVM = getJSVM(Token, State), + erlang:display(erlang:port_info(JSVM)), + {ok, Ret} = js_runner:call(JSVM, Data, []),%Payload, []), + send(State#state.lsock, Token, "JS says:", binary_to_list(Ret)), {noreply, State}; % Set the new state to the reference generated, and JSVM associated handle_cast({srv_cmd, "hello", Headers, Data}, State) -> - %JSVM = js_runner:boot(), + JSVM = js_runner:boot(), Client = getRef(), send(State#state.lsock, Client, "This is your refID"), - %OldMap = State#state.client_vm_map, - %NewState = State#state{client_vm_map = OldMap ++ [{Client, JSVM}]}, - %gen_server:cast(ggs_backup, {set_backup, NewState}), - {noreply, State}. %NewState + OldMap = State#state.client_vm_map, + NewState = State#state{client_vm_map = OldMap ++ [{Client, JSVM}]}, + gen_server:cast(ggs_backup, {set_backup, NewState}), + {noreply, NewState}. %%----------------------------------------------------- %% Helpers %%----------------------------------------------------- getRef() -> - %{A1,A2,A3} = now(), - %#random:seed(A1, A2, A3), - %random:uniform(1000). string:strip(os:cmd("uuidgen"), right, $\n ). getJSVM(RefID, State) -> From bf98e1fee2c9338466ea58b2d08c9a277cf370ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20P=C3=A5lsson?= Date: Mon, 14 Feb 2011 19:32:46 +0100 Subject: [PATCH 2/5] Fixed ggs_vm_runner --- src/ggs_server.erl | 4 ++-- src/ggs_vm_runner.erl | 40 ++++++++++++++++++++++++++++------------ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/ggs_server.erl b/src/ggs_server.erl index 34d297f..c695fd6 100644 --- a/src/ggs_server.erl +++ b/src/ggs_server.erl @@ -104,8 +104,8 @@ handle_cast({define, Token, SourceCode}, State) -> % Handle javascript calls handle_cast({call, Token, Command}, State) -> GameVM = getJSVM(Token, State), - ggs_vm_runner:user_command(GameVM, "User", Command, []), - %send(State#state.lsock, Token, "JS says:", binary_to_list(Ret)), Unessecary + Ret = ggs_vm_runner:user_command(GameVM, "User", Command, []), + send(State#state.lsock, Token, "JS says:", binary_to_list(Ret)), {noreply, State}; % Set the new state to the reference generated, and JSVM associated diff --git a/src/ggs_vm_runner.erl b/src/ggs_vm_runner.erl index cf633f0..6c66378 100644 --- a/src/ggs_vm_runner.erl +++ b/src/ggs_vm_runner.erl @@ -4,25 +4,41 @@ %Mattias start_link() -> erlang_js:start(), - {ok, Port} = js_driver:new(), - js:define(Port, <<"function userCommand(user, command, args){}">>), - PortPid = spawn_link(fun() -> loop(Port) end ), + PortPid = spawn_link( fun() -> + process_flag(trap_exit, true), + {ok, Port} = js_driver:new(), + js:define(Port, <<"function userCommand(user, command, args){return 'Hello world';}">>), + loop(Port) + end ), PortPid. loop(Port) -> -receive - {define, SourceCode} -> - ok = js:define(Port, list_to_binary(SourceCode)), - loop(Port); - {user_command, User, Command, Args} -> - {ok, Ret} = js:call(Port, <<"userCommand">>, list_to_binary([User,Command,Args])), - loop(Port) -end. + io:format("I am PID"), + erlang:display(self()), + receive + {define, SourceCode} -> + ok = js:define(Port, list_to_binary(SourceCode)), + loop(Port); + {user_command, User, Command, Args, From, Ref} -> + {ok, Ret} = js:call(Port, <<"userCommand">>, + [ list_to_binary(User), + list_to_binary(Command), + list_to_binary(Args) + ]), + From ! {Ref, Ret}, + loop(Port) + end. define(GameVM, SourceCode) -> GameVM ! {define,SourceCode}. user_command(GameVM, User, Command, Args) -> - GameVM ! {user_command, User, Command, Args}. + Ref = make_ref(), + GameVM ! {user_command, User, Command, Args, self(), Ref}, + receive + {Ref, RetVal} -> + RetVal; + Other -> Other + end. From 67567fe2636189c49a635661d9abf8502264d3e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20P=C3=A5lsson?= Date: Sun, 20 Feb 2011 01:41:40 +0100 Subject: [PATCH 3/5] Added some more ggsvm_e functionality and also a chat client --- .gitignore | 2 +- games/GGSCalc/calc.glade | 317 ++++++++++++++++++++++++++++++++++++ games/GGSCalc/calc.py | 101 ++++++++++++ games/GGSChat/calc.glade | 317 ++++++++++++++++++++++++++++++++++++ games/GGSChat/chat.py | 85 ++++++++++ games/GGSChat/ggschat.glade | 92 +++++++++++ mnesia/.gamedb.erl.swp | Bin 12288 -> 0 bytes python_client | 64 ++++---- src/.ggs_connection.erl.swp | Bin 12288 -> 0 bytes src/.ggs_server.erl.swo | Bin 12288 -> 0 bytes src/ggs_coordinator.erl | 8 +- src/ggs_gamevm_e.erl | 21 ++- src/ggs_player.erl | 23 ++- src/ggs_protocol.erl | 61 +++++++ src/ggs_table.erl | 12 +- 15 files changed, 1058 insertions(+), 45 deletions(-) create mode 100644 games/GGSCalc/calc.glade create mode 100644 games/GGSCalc/calc.py create mode 100644 games/GGSChat/calc.glade create mode 100644 games/GGSChat/chat.py create mode 100644 games/GGSChat/ggschat.glade delete mode 100644 mnesia/.gamedb.erl.swp delete mode 100644 src/.ggs_connection.erl.swp delete mode 100644 src/.ggs_server.erl.swo create mode 100644 src/ggs_protocol.erl diff --git a/.gitignore b/.gitignore index d176978..d6f2bf3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -*.swp +*.sw* *.dump *.beam Mnesia.* diff --git a/games/GGSCalc/calc.glade b/games/GGSCalc/calc.glade new file mode 100644 index 0000000..720b7b4 --- /dev/null +++ b/games/GGSCalc/calc.glade @@ -0,0 +1,317 @@ + + + + + + + + True + + + True + True + + + + False + 0 + + + + + True + 5 + 4 + + + True + True + True + + + + + / + True + True + True + + + + 1 + 2 + + + + + * + True + True + True + + + + 2 + 3 + + + + + - + True + True + True + + + + 3 + 4 + + + + + 7 + True + True + True + + + + 1 + 2 + + + + + 8 + True + True + True + + + + 1 + 2 + 1 + 2 + + + + + 9 + True + True + True + + + + 2 + 3 + 1 + 2 + + + + + + + True + True + True + + + + 3 + 4 + 1 + 2 + + + + + 4 + True + True + True + + + + 2 + 3 + + + + + 5 + True + True + True + + + + 1 + 2 + 2 + 3 + + + + + 6 + True + True + True + + + + 2 + 3 + 2 + 3 + + + + + + True + True + True + + + + 3 + 4 + 2 + 3 + + + + + 1 + True + True + True + + + + 3 + 4 + + + + + 2 + True + True + True + + + + 1 + 2 + 3 + 4 + + + + + 3 + True + True + True + + + + 2 + 3 + 3 + 4 + + + + + = + True + True + True + + + + 3 + 4 + 3 + 4 + + + + + 0 + True + True + True + + + + 4 + 5 + + + + + True + True + True + + + 1 + 2 + 4 + 5 + + + + + True + True + True + + + 2 + 3 + 4 + 5 + + + + + + True + True + True + + + + 3 + 4 + 4 + 5 + + + + + 1 + + + + + True + 2 + + + False + 2 + + + + + + diff --git a/games/GGSCalc/calc.py b/games/GGSCalc/calc.py new file mode 100644 index 0000000..8468ceb --- /dev/null +++ b/games/GGSCalc/calc.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python + +import sys, socket +try: + import pygtk + pygtk.require("2.16") +except: + pass +try: + import gtk + import gtk.glade +except: + sys.exit(1) + +class GGSCalc: + + def __init__(self): + #Set the Glade file + self.gladefile = "calc.glade" + self.wTree = gtk.glade.XML(self.gladefile, "window1") + + #Create our dictionay and connect it + dic = {"on_mainWindow_destroy" : gtk.main_quit + , "on_btn0_clicked" : lambda x: self.OnBtnClick(0) + , "on_btn1_clicked" : lambda x: self.OnBtnClick(1) + , "on_btn2_clicked" : lambda x: self.OnBtnClick(2) + , "on_btn3_clicked" : lambda x: self.OnBtnClick(3) + , "on_btn4_clicked" : lambda x: self.OnBtnClick(4) + , "on_btn5_clicked" : lambda x: self.OnBtnClick(5) + , "on_btn6_clicked" : lambda x: self.OnBtnClick(6) + , "on_btn7_clicked" : lambda x: self.OnBtnClick(7) + , "on_btn8_clicked" : lambda x: self.OnBtnClick(8) + , "on_btn9_clicked" : lambda x: self.OnBtnClick(9) + , "on_btnDiv_clicked" : lambda x: self.OnBtnClick("/") + , "on_btnMul_clicked" : lambda x: self.OnBtnClick("*") + , "on_btnMin_clicked" : lambda x: self.OnBtnClick("-") + , "on_btnPlus_clicked" : lambda x: self.OnBtnClick("+") + , "on_btnEq_clicked" : lambda x: self.calc() + , "on_btnDel_clicked" : lambda x: self.OnBtnClick("Del") + , "on_btnConnect_clicked" : lambda x: self.connect() + } + + for i in range(0,9): + dic + self.wTree.signal_autoconnect(dic) + + self.wTree.get_widget("window1").show() + self.setStatus("Not connected") + + def setStatus(self, msg): + self.wTree.get_widget("statusbar").push(0, msg) + + def calc(self): + exp = self.wTree.get_widget("txtCalc").get_text() + self.s.send("Server-Command: call\n"+ + "Token: %s\n" % self.token + + "Content-Type: text\n"+ + "Content-Length: %s\n" % len(exp)+ + "\n"+ + exp) + fs = self.s.makefile() + self.wTree.get_widget("txtCalc").set_text(fs.readline().split(" ")[1]) + + + def connect(self): + print "Connecting" + self.setStatus("Connecting") + HOST = 'localhost' # The remote host + PORT = 9000 # The same port as used by the server + self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.s.connect((HOST, PORT)) + self.s.send("Server-Command: hello\n"+ + "Content-Type: text\n"+ + "Content-Length: 0\n"+ + "\n") + fs = self.s.makefile() + self.token = fs.readline().split(" ")[0] + self.setStatus("Connected!") + + def OnBtnClick(self, btn): + calcTxt = self.wTree.get_widget("txtCalc") + t = calcTxt.get_text() + if btn == "+": + t += "+" + elif btn == "-": + t += "-" + elif btn == "/": + t += "/" + elif btn == "=": + t += "=" + elif btn == "*": + t += "*" + elif btn == "Del": + t = t[:-1] + else: + t += str("\""+str(btn)+"\"") + calcTxt.set_text(t) + +if __name__ == "__main__": + calc = GGSCalc() + gtk.main() diff --git a/games/GGSChat/calc.glade b/games/GGSChat/calc.glade new file mode 100644 index 0000000..720b7b4 --- /dev/null +++ b/games/GGSChat/calc.glade @@ -0,0 +1,317 @@ + + + + + + + + True + + + True + True + + + + False + 0 + + + + + True + 5 + 4 + + + True + True + True + + + + + / + True + True + True + + + + 1 + 2 + + + + + * + True + True + True + + + + 2 + 3 + + + + + - + True + True + True + + + + 3 + 4 + + + + + 7 + True + True + True + + + + 1 + 2 + + + + + 8 + True + True + True + + + + 1 + 2 + 1 + 2 + + + + + 9 + True + True + True + + + + 2 + 3 + 1 + 2 + + + + + + + True + True + True + + + + 3 + 4 + 1 + 2 + + + + + 4 + True + True + True + + + + 2 + 3 + + + + + 5 + True + True + True + + + + 1 + 2 + 2 + 3 + + + + + 6 + True + True + True + + + + 2 + 3 + 2 + 3 + + + + + + True + True + True + + + + 3 + 4 + 2 + 3 + + + + + 1 + True + True + True + + + + 3 + 4 + + + + + 2 + True + True + True + + + + 1 + 2 + 3 + 4 + + + + + 3 + True + True + True + + + + 2 + 3 + 3 + 4 + + + + + = + True + True + True + + + + 3 + 4 + 3 + 4 + + + + + 0 + True + True + True + + + + 4 + 5 + + + + + True + True + True + + + 1 + 2 + 4 + 5 + + + + + True + True + True + + + 2 + 3 + 4 + 5 + + + + + + True + True + True + + + + 3 + 4 + 4 + 5 + + + + + 1 + + + + + True + 2 + + + False + 2 + + + + + + diff --git a/games/GGSChat/chat.py b/games/GGSChat/chat.py new file mode 100644 index 0000000..c10ca8f --- /dev/null +++ b/games/GGSChat/chat.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python + +import sys, socket, thread, gobject, getpass +try: + import pygtk + pygtk.require("2.16") +except: + pass +try: + import gtk + import gtk.glade +except: + sys.exit(1) + +class GGSChat: + + def __init__(self,host, port): + #Set the Glade file + self.gladefile = "ggschat.glade" + self.wTree = gtk.glade.XML(self.gladefile, "window1") + + self.setStatus("Not connected") + self.connect(host, port) + thread.start_new_thread(self.listenChat, ()) + #Create our dictionay and connect it + dic = {"on_window1_destroy_event" : gtk.main_quit + , "on_sendButton_clicked" : lambda x: self.chat() + , "on_entry_activate" : lambda x : self.chat() + , "on_chatBox_focus" : lambda x, y: self.wTree.get_widget("entry").grab_focus() + } + + for i in range(0,9): + dic + self.wTree.signal_autoconnect(dic) + + self.wTree.get_widget("nickBox").set_text(getpass.getuser()) + self.wTree.get_widget("window1").show() + self.wTree.get_widget("entry").grab_focus() + + def setStatus(self, msg): + self.wTree.get_widget("statusbar").push(0, msg) + + def chat(self): + exp = self.wTree.get_widget("entry").get_text() + nick = self.wTree.get_widget("nickBox").get_text() + exp = "<%s> %s" % (nick, exp) + self.s.send("Game-Command: chat\n"+ + "Token: %s\n" % self.token + + "Content-Type: text\n"+ + "Content-Length: %s\n" % (len(exp))+ + "\n"+ + exp+"\n") + self.wTree.get_widget("entry").set_text("") + #self.listenChat() + + + def connect(self, host,port): + print "Connecting" + self.setStatus("Connecting") + HOST = host # The remote host + PORT = port # The same port as used by the server + self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.s.connect((HOST, PORT)) + self.token = self.s.recv(1024) + self.setStatus("Connected!") + + def listenChat(self): + print "listening" + fs = self.s.makefile() + while True: + line = fs.readline() + print "Received: ", line + gobject.idle_add(self.updateChatText, line) + + def updateChatText(self, text): + self.wTree.get_widget("chatBox").get_buffer().insert_at_cursor(text) +if __name__ == "__main__": + host = "localhost" + port = 9000 + if len(sys.argv) >= 2: + host = sys.argv[1] + port = int(sys.argv[2]) + chat = GGSChat(host, port) + gobject.threads_init() + gtk.main() diff --git a/games/GGSChat/ggschat.glade b/games/GGSChat/ggschat.glade new file mode 100644 index 0000000..ac4e9cb --- /dev/null +++ b/games/GGSChat/ggschat.glade @@ -0,0 +1,92 @@ + + + + + + 500 + 500 + + + + True + + + True + + + True + True + False + + + + 0 + + + + + 0 + + + + + True + + + True + True + + 10 + Anonymous + + + False + 0 + + + + + True + True + + + + + 1 + + + + + Chat! + True + True + True + + + + False + False + 2 + + + + + False + False + 1 + + + + + True + 2 + + + False + 2 + + + + + + diff --git a/mnesia/.gamedb.erl.swp b/mnesia/.gamedb.erl.swp deleted file mode 100644 index 469b1f85b2ecf7663f6f99f957c41243aa53c9d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2zfTlF6vqcEQBk9XjV9wE^c~uUwxG9A3wj3SpnmAjS;oFXpP_fq7W5WsLG#cJs2}=` z*tenA&^%Ow94N`@1lEK?CIUo&2oM1xKm>@u|3rXec*zmXaifJFiH1>upT8UXg)*~~ z>5#r#WV<)}R~3ve1=%yL;PBeT2;Jn`8LfGIzc+H@1JWO|Mq+22omqCbw2|9xebwV&MdL9H&}jaz%JyTka;4q><#@S!BC3>)Gzy4_c#PjEwfs92d$g zeDw@9$s((11KAk4Xhgj&_xgNpO&Ft9Jx0hyu4N<8?xOOSg8Y(_Z5Pkd9xtpfAbI60 zlk|Vj0invbZ5$|a&pud5`Hgn$%6u+6_TAF$9KtKfl`zmIKWF2tIK{3yRjS4AN?}1q zeKFlpwTffYEh!vShrbk{ec%Od40`En@qpXv@LICLF(fp^C$W{KAKaj^+l+SvsEbH) z>}FiYzERkptP}oRXk`n+an@anrYxtnjUZgrs@XD}k2uvTuc1mxM0`dXBXtxd^zbqf jn-*N!@$V9T6Fa9h3+=0-$)+b%yW9vo`z7sdlVX1X$Qr-k diff --git a/python_client b/python_client index e265120..10feefd 100755 --- a/python_client +++ b/python_client @@ -7,50 +7,56 @@ PORT = int(sys.argv[1]) # The same port as used by the server s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) -# Say hello +# Define ourselves a function! +token = s.recv(1024) -print "Saying hello to server" +#print "Defining a function called myFun" +#s.send( +#"Token: %s\n\ +#Server-Command: define\n\ +#Content-Type: text\n\ +#Content-Length: 49\n\ +#\n\ +#function myFun() {return 'Hello World!' ;}" % token) +#fs = s.makefile() +#data = fs.readline() +#print "Token:", token +#print "Data: ", ' '.join(data.split(" ")[1:]) + +# Call that function! +fs = s.makefile() +print "Token: ", token s.send( -"Server-Command: hello\n\ +"Token: %s\n\ +Game-Command: greet\n\ Content-Type: text\n\ Content-Length: 0\n\ \n\ -") -fs = s.makefile() -data = fs.readline() -token = data.split(" ")[0] -print "Token:", token -print "Data: ", ' '.join(data.split(" ")[1:]) +" % token) +time.sleep(1) -# Define ourselves a function! - -print "Defining a function called myFun" s.send( "Token: %s\n\ -Server-Command: define\n\ +Game-Command: uname\n\ Content-Type: text\n\ -Content-Length: 49\n\ +Content-Length: 0\n\ \n\ -function myFun() {return 'Hello World!' ;}" % token) -fs = s.makefile() -data = fs.readline() -print "Token:", token -print "Data: ", ' '.join(data.split(" ")[1:]) +" % token) +time.sleep(1) -# Call that function! - -print "Calling myFun" s.send( "Token: %s\n\ -Server-Command: call\n\ +Game-Command: chat\n\ Content-Type: text\n\ -Content-Length: 6\n\ +Content-Length: 23\n\ \n\ -myFun" % token) -fs = s.makefile() -data = fs.readline() -print "Token:", token -print "Data: ", ' '.join(data.split(" ")[1:]) +Hello guys, what's up?\n" % token) +time.sleep(1) + + +while True: + data = fs.readline() + print "Data: ", data s.close() diff --git a/src/.ggs_connection.erl.swp b/src/.ggs_connection.erl.swp deleted file mode 100644 index 0c009f8287377d2e3763a3fb7610231c3237d3fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2O>Z1E7{^^+M0qKoqMo?8TdkN?XJ3-EAceGwl!%h3+pLndm(^7W&e$W5 zH=){YkdU|{!I^9M0Eiwz;sQv$@CmqagL`?A;O}|aYywf~wg)QN%3m`c+m9drp2wC} z@pkLxTARMpSRg2`6LRL$wf0X-7s$022}!jSJV-*tG&jx1l^q@@QXbcO@O^*UU^7v2 zpjaG-V$kF&Vt8D+veitL-y955&zC}QUx!jO(0X9RzF7j6z#|igm=49FN1 zorLbcO2}R4b0~m(Xd7xnSD`;o5%LH0JMre&y z^<_eSfqsPUL0>^0^cM8jON4v_-GN5XD)c7wJoFs&EOa0D7QTi)hWbziItx9(`pg>d znswS@30MM_fF)oFSOWih0yHZFE521sA2M4uN3~j?rI2cs zUSH|Z6&6J)MQs)%b%ft6aU`VTNp#y_!hO$iBmXLIxzsbX$Mn(!1M_{JXy>Z=UUSI~ z6G6niQ1qpv!-Ta5CfkPGeY#$L=44BCi-HeSx3 zr`>COFEh~_kKfH)4CP{9s+eh~f^HN87EKbA{Y)i~N^ZoRwDjOQ7G4@JT+2OZ9P%LV zS6YNWf%Mk54E9MPZnC{qrddI+=F;l*jn$1qXhz6hv=^CM3>cRqkZZ;nT1^;k#d6J6 zN_}Z=$I`x%amGI7YL}}bUbsvPbBJ2ZqJy9nvG7@{oxI0U;6;>2CbC)Ezpc1*3u!R1 zh}90b#>L#BKzzOT;MJ7#Gp8St`28$_R64T_V#sAHDiSD>N+V7kJY0G>2VL4KlG_Y= zSQ#lkOgRez)c+ z8=X?jj*O5x|G;o^y2h_24#=rcH|M9Ssh+BuZEmXO1Z^%9&kH@AsiYpuU>I@7+}}3) zo@?_JF3xl^nQ?R(v*a&<^vhu7dx++>|;O?y@+$5Y|N|GrN0mvvzuVYG#`0>1wNM zU}2o~fQcOR;J={Zju(~aNfTmXVvHeC4|?;UCW?f_tKaJG`2{LumV+eK$%mfmu6p(A z`(C~74PDNz9zQ{!OHUIVdkNWgb@s%Su?yshR|q-9eaY1I+Z?a5K=Rx4QMWfEgPD02 zHY5)+d0t_eW5-IFP&k=dEwn-=PBW2a!n*@wx{FpoD{$uuv}85){2p>}dMc|19T?wF zAA5A=&d2MXS^=$qRzNGD70?Q31+)TM0jsbJEl&t$KgIFiH1lr&ncn##iOW<*E;{ighfD7PlPykPXePA!RzLSt&!7t!* z@FBPaHb5CX4JN_E;5WqJYw!V3@i-4w!9MWU{r6yUX_vJE|1$+>|2QIQVVbCRn>S3V znjJc$+W&F~A0}CWEkc%y{UHeSjyX;*YhnhOjEOjOiZLk zIWUeM$9H7Hw>?^I`HpnCAC7E|C>0~2OVXCClO_&6BeR^k?bn!Lo%AZJp>NXYrb(@Z z4Jqu&$bU7EH_}8!&Gj+Xu!_tMIeJ@B_kOpw&jky-vxyx{q6SB^S}JHNO}de^9S5Jk z8B6Lq6oelYk6Er?<%V>djJFV-1EKP@?S<%rp;2FDqN#N-WKt88IFWW zvx6b-g{K>0&kZH>lbyEKwvoc8nMtK+v5wj`uJ1}?O<7)#71_d8QFF%MK~e|%uxvYx zEpC>+#atAJ!=;7d>O#?^Dj+B?>SRQIZ^7+3)HAiy=fZ$FYP0mLV$Vf4Dm=Q5oaaGE zWu4LFbI+}nf}zzRCwi;vB?p$+`+e8eN#pG|LtT`%8WYB(TI88J6KqI^;hEzS5)JJP ziE@-lr_N$o{8qEf1m#tlY}=4F?FyrkLp3){WZRl*s7FHLq2o7$TZNOw z8fW>~8cVDr#Kxq)_{l4ix#!G>TdGsi+zQkJQXT6~PqSP)-?Zs?=qs z%G{3VS9SKdq8p-ON;%doJ}8 z5{{{vRV+xV% ggs_logger:not_implemented(). %% @doc Removes a player from coordinator. -remove_player(_From, _Player) -> +remove_player(_From, Player) -> + %gen_server:cast(ggs_coordinator, {remove_player, Player}). ggs_logger:not_implemented(). %% gen_server callbacks @@ -87,6 +88,11 @@ handle_call(_Message, _From, State) -> handle_cast({stop, Reason}, State) -> {stop, normal, state}; +%% @TODO: Implement me +%handle_cast({remove_player, Player}) -> +% {noreply, State#co_state{ + + handle_cast(_Message, State) -> {noreply, State}. diff --git a/src/ggs_gamevm_e.erl b/src/ggs_gamevm_e.erl index 76b9350..4575ef1 100644 --- a/src/ggs_gamevm_e.erl +++ b/src/ggs_gamevm_e.erl @@ -33,9 +33,24 @@ user_command(GameVM, Player, Command, Args) -> loop(Table) -> receive {define, SourceCode} -> + io:format("GameVM_e can't define functions, sorry!~n"), loop(Table); - {user_command, _User, Command, _Args, _From, _Ref} -> - io:format("GameVM received a message~n"), - ggs_table:notify_all_players(Table, Command), + {user_command, Player, Command, Args, From, _Ref} -> + erlang:display(Player), + do_stuff(Command, Args, Player, Table), loop(Table) end. + +do_stuff(Command, Args, Player, Table) -> + case Command of + "greet" -> + ggs_player:notify(Player, server, "Hello there!\n"); + "chat" -> + ggs_table:notify_all_players(Table, Args ++ "\n"); + "uname" -> + Uname = os:cmd("uname -a"), + ggs_player:notify(Player, server, Uname); + + Other -> + ggs_player:notify(Player, server, "I don't know that command..\n") + end. diff --git a/src/ggs_player.erl b/src/ggs_player.erl index af92ad9..bd3b198 100644 --- a/src/ggs_player.erl +++ b/src/ggs_player.erl @@ -26,10 +26,12 @@ start_link(Socket) -> TableStatus = ggs_coordinator:join_table(1337), case TableStatus of {ok, Table} -> + notify(self(), self(), Token), loop(#pl_state{socket = Socket, token = Token, table = Table}); {error, no_such_table} -> ggs_coordinator:create_table({force, 1337}), {ok, Table} = ggs_coordinator:join_table(1337), + notify(self(), self(), Token), loop(#pl_state{socket = Socket, token = Token, table = Table}) end. @@ -57,10 +59,25 @@ stop(_Player,_Table) -> loop(#pl_state{token = Token, socket = Socket, table = Table} = State) -> receive {tcp, Socket, Data} -> % Just echo for now.. - io:format("Notifying table..~n"), - ggs_table:notify_game(Table, Token, Data), + io:format("Parsing via protocol module..~n"), + Parsed = ggs_protocol:parse(Data), + self() ! Parsed, loop(State); {notify, From, Message} -> gen_tcp:send(Socket, Message), - loop(State) + loop(State); + % Below are messages generated by the parser + {game_cmd,Cmd, Headers, Data} -> + ggs_table:notify(Table, self(), {game, Cmd, Data}), + loop(State); + {srv_cmd,"define", Headers, Data} -> + ggs_table:notify(Table, self(), {server, define, Data}), + loop(State); + {tcp_closed, _Socket} -> + io:format("Client disconnected, but THIS IS NOT SUPPORTED YET!~n"), + loop(State); + Other -> + io:format("Got UNKNOWN message: "), + erlang:display(Other), + io:format("~n") end. diff --git a/src/ggs_protocol.erl b/src/ggs_protocol.erl new file mode 100644 index 0000000..3dc88f9 --- /dev/null +++ b/src/ggs_protocol.erl @@ -0,0 +1,61 @@ +-module(ggs_protocol). +-export([parse/1, getToken/1]). + +%% API Functions +parse(Data) -> + Parsed = do_parse(Data, []), + prettify(Parsed). + +getToken(Parsed) -> + case lists:keyfind(token, 1, Parsed) of + {_, Value} -> + Value; + false -> + false + end. + +%% Internal helpers +do_parse(Data, ParsedMessage) -> + NewLinePos = string:chr(Data, $\n), + Line = string:substr(Data, 1, NewLinePos-1), + Tokens = re:split(Line, ": ", [{return, list}]), + case handle(Tokens) of + {Command, more} -> + do_parse(string:substr(Data, NewLinePos+1), ParsedMessage ++ [Command]); + {separator, data_next} -> + {_, Value} = lists:keyfind(content_len, 1, ParsedMessage), + {ContentLength, []} = string:to_integer(Value), + {data, ArgumentData} = handle_data(string:substr(Data, NewLinePos+1), ContentLength), + {ParsedMessage, ArgumentData} + end. + +handle([[]]) -> + {separator, data_next}; +handle(["Server-Command", Param]) -> + {{srv_cmd, Param}, more}; +handle(["Game-Command", Param]) -> + {{game_cmd, Param}, more}; +handle(["Content-Length", Param]) -> + {{content_len, Param}, more}; +handle(["Token", Param]) -> + {{token, Param}, more}; +handle(["Content-Type", Param]) -> + {{content_type, Param}, more}. + +handle_data(Data, Length) -> + {data, string:substr(Data,1,Length)}. + + +prettify({Args, Data}) -> + case lists:keyfind(srv_cmd, 1, Args) of + {_, Value} -> + {srv_cmd, Value, Args, Data}; + _Other -> + case lists:keyfind(game_cmd, 1, Args) of + {_, Value} -> + {game_cmd, Value, Args, Data}; + _ -> + ok + end + end. + diff --git a/src/ggs_table.erl b/src/ggs_table.erl index 53c27e9..118ae0d 100644 --- a/src/ggs_table.erl +++ b/src/ggs_table.erl @@ -51,7 +51,6 @@ notify_all_players(Table, Message) -> gen_server:cast(Table, {notify_all_players, Message}). notify_game(Table, From, Message) -> - io:format("Notify game called on"), erlang:display(Table), io:format("~n"), gen_server:cast(Table, {notify_game, Message, From}). @@ -82,22 +81,19 @@ handle_call(Msg, _From, State) -> %% @private handle_cast({notify, Player, Message}, #state { game_vm = GameVM } = State) -> case Message of - {server, define, Args} -> - ggs_gamevm_e:define(GameVM, Args); - {game, Command, Args} -> - ggs_gamevm_e:user_command(GameVM, Player, Command, Args) + {server, define, Args} -> + ggs_gamevm_e:define(GameVM, Args); + {game, Command, Args} -> + ggs_gamevm_e:user_command(GameVM, Player, Command, Args) end, {noreply, State}; handle_cast({notify_game, Message, From}, #state { game_vm = GameVM } = State) -> - io:format("notify_game message received~n"), ggs_gamevm_e:user_command(GameVM, From, Message, ""), {noreply, State}; handle_cast({notify_all_players, Message}, #state{players = Players} = State) -> - io:format("Notifying all players... ~p~n", [Players]), lists:foreach(fun(P) -> - io:format("Notifying ~p~n", [P]), ggs_player:notify(P, "Server", Message) end, Players), {noreply, State}; From 507081c234f70d0c734059e2dea7c3d1a31c52e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20P=C3=A5lsson?= Date: Sun, 20 Feb 2011 01:58:48 +0100 Subject: [PATCH 4/5] Now we have a /lusers command in chat ;) --- games/GGSChat/chat.py | 13 +++++++++---- src/ggs_gamevm_e.erl | 4 +++- src/ggs_table.erl | 6 +++++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/games/GGSChat/chat.py b/games/GGSChat/chat.py index c10ca8f..9c94728 100644 --- a/games/GGSChat/chat.py +++ b/games/GGSChat/chat.py @@ -29,8 +29,6 @@ class GGSChat: , "on_chatBox_focus" : lambda x, y: self.wTree.get_widget("entry").grab_focus() } - for i in range(0,9): - dic self.wTree.signal_autoconnect(dic) self.wTree.get_widget("nickBox").set_text(getpass.getuser()) @@ -43,8 +41,15 @@ class GGSChat: def chat(self): exp = self.wTree.get_widget("entry").get_text() nick = self.wTree.get_widget("nickBox").get_text() - exp = "<%s> %s" % (nick, exp) - self.s.send("Game-Command: chat\n"+ + if exp[0] == "/": + self.s.send("Game-Command: %s\n" % exp[1:] + + "Token: %s\n" % self.token + + "Content-Type: text\n" + + "Content-Length: 0\n"+ + "\n") + else: + exp = "<%s> %s" % (nick, exp) + self.s.send("Game-Command: chat\n"+ "Token: %s\n" % self.token + "Content-Type: text\n"+ "Content-Length: %s\n" % (len(exp))+ diff --git a/src/ggs_gamevm_e.erl b/src/ggs_gamevm_e.erl index 4575ef1..ad2527b 100644 --- a/src/ggs_gamevm_e.erl +++ b/src/ggs_gamevm_e.erl @@ -50,7 +50,9 @@ do_stuff(Command, Args, Player, Table) -> "uname" -> Uname = os:cmd("uname -a"), ggs_player:notify(Player, server, Uname); - + "lusers" -> + {ok, Players} = ggs_table:get_player_list(Table), + ggs_player:notify(Player, server,io_lib:format("~p\n",[Players])); Other -> ggs_player:notify(Player, server, "I don't know that command..\n") end. diff --git a/src/ggs_table.erl b/src/ggs_table.erl index 118ae0d..93b79fd 100644 --- a/src/ggs_table.erl +++ b/src/ggs_table.erl @@ -6,7 +6,7 @@ %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, notify_all_players/2, notify_game/3, - add_player/2]). + add_player/2, get_player_list/1]). -record(state, { token, players, socket, game_vm } ). @@ -39,6 +39,10 @@ add_player(Table, Player) -> remove_player(Table, Player) -> call(Table, {remove_player, Player}). +%% @doc Get a list of all player processes attached to this table +get_player_list(Table) -> + gen_server:call(Table, get_player_list). + % @doc stops the table process stop(Table) -> gen_server:cast(Table, stop). From 7412087d4a93663a6194197e6d5ec21bf1b9642a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20P=C3=A5lsson?= Date: Mon, 21 Feb 2011 15:11:28 +0100 Subject: [PATCH 5/5] worked more on chat --- games/GGSChat/chat.py | 8 ++++++-- src/ggs_coordinator.erl | 8 ++++---- src/ggs_dispatcher.erl | 2 +- src/ggs_gamevm.erl | 5 +++-- src/ggs_gamevm_e.erl | 10 ++++++---- src/ggs_player.erl | 8 ++++---- src/ggs_table.erl | 2 +- 7 files changed, 25 insertions(+), 18 deletions(-) diff --git a/games/GGSChat/chat.py b/games/GGSChat/chat.py index 9c94728..17c30ea 100644 --- a/games/GGSChat/chat.py +++ b/games/GGSChat/chat.py @@ -42,11 +42,15 @@ class GGSChat: exp = self.wTree.get_widget("entry").get_text() nick = self.wTree.get_widget("nickBox").get_text() if exp[0] == "/": + cmdStr = exp[1:].split(" ") + cmd = cmdStr[0] + params = ' '.join(cmdStr[1:]) self.s.send("Game-Command: %s\n" % exp[1:] + "Token: %s\n" % self.token + "Content-Type: text\n" + - "Content-Length: 0\n"+ - "\n") + "Content-Length: %s\n" % len(params)+ + "\n"+ + params) else: exp = "<%s> %s" % (nick, exp) self.s.send("Game-Command: chat\n"+ diff --git a/src/ggs_coordinator.erl b/src/ggs_coordinator.erl index a7f0ab8..f1e7caa 100644 --- a/src/ggs_coordinator.erl +++ b/src/ggs_coordinator.erl @@ -49,7 +49,7 @@ respawn_table(_Token) -> ggs_logger:not_implemented(). %% @doc Removes a player from coordinator. -remove_player(_From, Player) -> +remove_player(_From, _Player) -> %gen_server:cast(ggs_coordinator, {remove_player, Player}). ggs_logger:not_implemented(). @@ -66,7 +66,7 @@ handle_call({join_table, Table}, From, State) -> {FromPlayer, _Ref} = From, Tables = State#co_state.tables, case lists:keyfind(Table, 1, Tables) of - {TableID, TablePID} -> + {_TableID, TablePID} -> ggs_table:add_player(TablePID, FromPlayer), {reply, {ok, TablePID}, State}; false -> @@ -85,8 +85,8 @@ handle_call({create_table, {force, TableID}}, From, State) -> handle_call(_Message, _From, State) -> {noreply, State}. -handle_cast({stop, Reason}, State) -> - {stop, normal, state}; +handle_cast({stop, _Reason}, State) -> + {stop, normal, State}; %% @TODO: Implement me %handle_cast({remove_player, Player}) -> diff --git a/src/ggs_dispatcher.erl b/src/ggs_dispatcher.erl index 49dcf4b..11dd729 100644 --- a/src/ggs_dispatcher.erl +++ b/src/ggs_dispatcher.erl @@ -45,7 +45,7 @@ handle_call(_Message, _From, State) -> handle_cast(_Message, State) -> {noreply, State}. -handle_info({tcp, _Socket, RawData}, State) -> +handle_info({tcp, _Socket, _RawData}, State) -> io:format("Got connect request!~n"), {noreply, State}; diff --git a/src/ggs_gamevm.erl b/src/ggs_gamevm.erl index 1a8f547..a16e6a6 100644 --- a/src/ggs_gamevm.erl +++ b/src/ggs_gamevm.erl @@ -6,7 +6,6 @@ %% @doc Create a new VM process. The process ID is returned and can be used %% with for example the define method of this module. start_link() -> - erlang_js:start(), %% @TODO: should only be done once PortPid = spawn_link( fun() -> process_flag(trap_exit, true), {ok, Port} = js_driver:new(), @@ -46,5 +45,7 @@ loop(Port) -> list_to_binary(Args) ]), From ! {Ref, Ret}, - loop(Port) + loop(Port); + {eval, JS} -> + end. diff --git a/src/ggs_gamevm_e.erl b/src/ggs_gamevm_e.erl index ad2527b..3cc6b17 100644 --- a/src/ggs_gamevm_e.erl +++ b/src/ggs_gamevm_e.erl @@ -32,11 +32,11 @@ user_command(GameVM, Player, Command, Args) -> loop(Table) -> receive - {define, SourceCode} -> + {define, _SourceCode} -> io:format("GameVM_e can't define functions, sorry!~n"), loop(Table); - {user_command, Player, Command, Args, From, _Ref} -> - erlang:display(Player), + {user_command, Player, Command, Args, _From, _Ref} -> + erlang:display(Command), do_stuff(Command, Args, Player, Table), loop(Table) end. @@ -53,6 +53,8 @@ do_stuff(Command, Args, Player, Table) -> "lusers" -> {ok, Players} = ggs_table:get_player_list(Table), ggs_player:notify(Player, server,io_lib:format("~p\n",[Players])); - Other -> + "nick" -> + io:format("Changing nickname of ~p to ~p.", [Player, Args]); + _Other -> ggs_player:notify(Player, server, "I don't know that command..\n") end. diff --git a/src/ggs_player.erl b/src/ggs_player.erl index bd3b198..0211f3f 100644 --- a/src/ggs_player.erl +++ b/src/ggs_player.erl @@ -56,21 +56,21 @@ stop(_Player,_Table) -> %% Internals -loop(#pl_state{token = Token, socket = Socket, table = Table} = State) -> +loop(#pl_state{token = _Token, socket = Socket, table = Table} = State) -> receive {tcp, Socket, Data} -> % Just echo for now.. io:format("Parsing via protocol module..~n"), Parsed = ggs_protocol:parse(Data), self() ! Parsed, loop(State); - {notify, From, Message} -> + {notify, _From, Message} -> gen_tcp:send(Socket, Message), loop(State); % Below are messages generated by the parser - {game_cmd,Cmd, Headers, Data} -> + {game_cmd,Cmd, _Headers, Data} -> ggs_table:notify(Table, self(), {game, Cmd, Data}), loop(State); - {srv_cmd,"define", Headers, Data} -> + {srv_cmd,"define", _Headers, Data} -> ggs_table:notify(Table, self(), {server, define, Data}), loop(State); {tcp_closed, _Socket} -> diff --git a/src/ggs_table.erl b/src/ggs_table.erl index 93b79fd..cf77f30 100644 --- a/src/ggs_table.erl +++ b/src/ggs_table.erl @@ -6,7 +6,7 @@ %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, notify_all_players/2, notify_game/3, - add_player/2, get_player_list/1]). + get_player_list/1]). -record(state, { token, players, socket, game_vm } ).