merge
This commit is contained in:
commit
0718031e22
10 changed files with 3251 additions and 4 deletions
|
@ -1 +1 @@
|
|||
Subproject commit aad268d03a3c23de917cfecf767d583d3cb32633
|
||||
Subproject commit 00312859714bef6e9a4fdb9931a41fef56eeb89a
|
7
games/Pong/Pong.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
games/Pong/Pong.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:Pong.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
2937
games/Pong/Pong.xcodeproj/project.xcworkspace/xcuserdata/jeena.xcuserdatad/UserInterfaceState.xcuserstate
generated
Normal file
2937
games/Pong/Pong.xcodeproj/project.xcworkspace/xcuserdata/jeena.xcuserdatad/UserInterfaceState.xcuserstate
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,76 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1D6058900D05DD3D006BFB54"
|
||||
BuildableName = "Pong.app"
|
||||
BlueprintName = "Pong"
|
||||
ReferencedContainer = "container:Pong.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
|
||||
displayScaleIsEnabled = "NO"
|
||||
displayScale = "1.00"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug">
|
||||
<BuildableProductRunnable>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1D6058900D05DD3D006BFB54"
|
||||
BuildableName = "Pong.app"
|
||||
BlueprintName = "Pong"
|
||||
ReferencedContainer = "container:Pong.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
displayScaleIsEnabled = "NO"
|
||||
displayScale = "1.00"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release">
|
||||
<BuildableProductRunnable>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "1D6058900D05DD3D006BFB54"
|
||||
BuildableName = "Pong.app"
|
||||
BlueprintName = "Pong"
|
||||
ReferencedContainer = "container:Pong.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>Pong.xcscheme</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>1D6058900D05DD3D006BFB54</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
|
@ -60,7 +60,8 @@ while True:
|
|||
|
||||
s.close()
|
||||
|
||||
"""
|
||||
time.sleep(2)
|
||||
|
||||
HOST = 'localhost' # The remote host
|
||||
PORT = int(sys.argv[1]) # The same port as used by the server
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
@ -81,4 +82,3 @@ print "Token:", token
|
|||
print "Data: ", ' '.join(data.split(" ")[1:])
|
||||
|
||||
s.close()
|
||||
"""
|
||||
|
|
23
python_client_reconnect
Executable file
23
python_client_reconnect
Executable file
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys, time, socket
|
||||
|
||||
HOST = 'localhost' # The remote host
|
||||
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))
|
||||
# Call that function!
|
||||
|
||||
print "Calling myFun"
|
||||
s.send(
|
||||
"Token: %s\n\
|
||||
Server-Command: call\n\
|
||||
Content-Type: text\n\
|
||||
Content-Length: 6\n\
|
||||
\n\
|
||||
myFun" % raw_input("Token >> "))
|
||||
fs = s.makefile()
|
||||
data = fs.readline()
|
||||
print "Data: ", ' '.join(data.split(" ")[1:])
|
||||
|
||||
s.close()
|
|
@ -25,7 +25,6 @@ create_message(Cmd, Enc, Acc, Data) ->
|
|||
Data,
|
||||
Msg.
|
||||
|
||||
|
||||
%% Internal helpers
|
||||
do_parse(Data, ParsedMessage) ->
|
||||
NewLinePos = string:chr(Data, $\n),
|
||||
|
|
141
src/ggs_server.erl
Normal file
141
src/ggs_server.erl
Normal file
|
@ -0,0 +1,141 @@
|
|||
-module(ggs_server).
|
||||
-behaviour(gen_server).
|
||||
|
||||
%% API
|
||||
-export([start_link/1,
|
||||
start_link/0,
|
||||
stop/0
|
||||
]).
|
||||
|
||||
%% gen_server callbacks
|
||||
-export([init/1, handle_call/3, handle_cast/2,
|
||||
handle_info/2, terminate/2, code_change/3]).
|
||||
|
||||
|
||||
-define(SERVER, ?MODULE).
|
||||
-define(DEFAULT_PORT, 1055).
|
||||
|
||||
-record(state, {port, lsock, client_vm_map = []}).
|
||||
|
||||
%%%====================================================
|
||||
%%% API
|
||||
%%%====================================================
|
||||
|
||||
%%-----------------------------------------------------
|
||||
%% @doc Starts the server
|
||||
%% @end
|
||||
%%-----------------------------------------------------
|
||||
start_link(Port) ->
|
||||
gen_server:start_link({local, ?SERVER}, ?MODULE, [Port], []).
|
||||
|
||||
start_link() ->
|
||||
start_link(?DEFAULT_PORT).
|
||||
|
||||
%%-----------------------------------------------------
|
||||
%% @doc Stops the server.
|
||||
%% @spec stop() -> ok
|
||||
%% @end
|
||||
%%-----------------------------------------------------
|
||||
stop() ->
|
||||
gen_server:cast(?SERVER, stop).
|
||||
|
||||
%%-----------------------------------------------------
|
||||
%% gen_server callbacks
|
||||
%%-----------------------------------------------------
|
||||
|
||||
init([Port]) ->
|
||||
case gen_server:call(ggs_backup, get_backup) of
|
||||
{backup_state, not_initialized} ->
|
||||
{ok, LSock} = gen_tcp:listen(Port, [{active, true},
|
||||
{reuseaddr, true}]),
|
||||
{ok, #state{port = Port, lsock = LSock}, 0};
|
||||
{backup_state, State} ->
|
||||
{ok, LSock} = gen_tcp:listen(Port, [{active, true},
|
||||
{reuseaddr, true}]),
|
||||
{ok, State#state{lsock = LSock}, 0}
|
||||
end.
|
||||
|
||||
handle_call({backup_state, OldState}, _From, State) ->
|
||||
io:format("Received old state from backup~n"),
|
||||
{noreply, OldState}.
|
||||
|
||||
|
||||
handle_info({tcp, Socket, RawData}, State) ->
|
||||
ggs_protocol:parse(RawData),
|
||||
{noreply, State#state{lsock = Socket}};
|
||||
|
||||
handle_info({tcp_closed, Socket}, State) ->
|
||||
gen_tcp:close(Socket),
|
||||
{stop, "Client closed socket", State};
|
||||
|
||||
handle_info(timeout, #state{lsock = LSock} = State) ->
|
||||
{ok, _Sock} = gen_tcp:accept(LSock),
|
||||
{noreply, State};
|
||||
|
||||
handle_info(Other, State) ->
|
||||
erlang:display(Other).
|
||||
|
||||
terminate(_Reason, _State) ->
|
||||
ok.
|
||||
|
||||
code_change(_OldVsn, State, _Extra) ->
|
||||
{ok, State}.
|
||||
|
||||
%%-----------------------------------------------------
|
||||
%% Internal functions
|
||||
%%-----------------------------------------------------
|
||||
handle_cast(stop, State) ->
|
||||
{stop, normal, State};
|
||||
|
||||
% Handle javascript defines
|
||||
handle_cast({srv_cmd, "define", Headers, Data}, State) ->
|
||||
Token = ggs_protocol:getToken(Headers),
|
||||
GameVM = getJSVM(Token, State),
|
||||
ggs_vm_runner:define(GameVM, Data),
|
||||
send(State#state.lsock, "Token", "Okay, defined that for you!"),
|
||||
{noreply, State};
|
||||
|
||||
% Handle javascript calls
|
||||
handle_cast({srv_cmd, "call", Headers, Data}, State) ->
|
||||
Token = ggs_protocol:getToken(Headers),
|
||||
io:format("Got call request: ~p~n", [Data]),
|
||||
GameVM = getJSVM(Token, State),
|
||||
Ret = ggs_vm_runner:user_command(GameVM, "User", Data, []),
|
||||
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({server, hello, Headers}, State) ->
|
||||
handle_cast({srv_cmd, "hello", Headers, Data}, State) ->
|
||||
GameToken = case proplist:get_value(game_token, Headers) of ->
|
||||
undefined -> getNewToken();
|
||||
GT -> GT;
|
||||
end,
|
||||
ClientToken = getNewToken(),
|
||||
OldMap = State#state.client_vm_map,
|
||||
NewState = State#state{client_vm_map = OldMap ++ [{ClientToken, GameVM, GameToken}]},
|
||||
gen_server:cast(ggs_backup, {set_backup, NewState}),
|
||||
{noreply, NewState}.
|
||||
|
||||
|
||||
%%-----------------------------------------------------
|
||||
%% Helpers
|
||||
%%-----------------------------------------------------
|
||||
getNewToken() ->
|
||||
string:strip(os:cmd("uuidgen"), right, $\n ).
|
||||
|
||||
getJSVM(ClientToken, State) ->
|
||||
VMs = State#state.client_vm_map,
|
||||
{value, {_,VM}} = lists:keysearch(ClientToken, 1, VMs),
|
||||
VM.
|
||||
|
||||
getGameVMByGameToken(GameToken, State) ->
|
||||
VMs = State#state.client_vm_map,
|
||||
{value, {_,VM}} = lists:keysearch(GameToken, 3, VMs),
|
||||
VM.
|
||||
|
||||
send(Socket, RefID, String) ->
|
||||
gen_tcp:send(Socket, string:join([RefID,String,"\n"], " ")).
|
||||
|
||||
send(Socket, RefID, String1, String2) ->
|
||||
gen_tcp:send(Socket, string:join([RefID,String1, String2,"\n"], " ")).
|
42
src/ggs_vm_runner.erl
Normal file
42
src/ggs_vm_runner.erl
Normal file
|
@ -0,0 +1,42 @@
|
|||
-module(ggs_vm_runner).
|
||||
-export([start_link/0, define/2, user_command/4]).
|
||||
|
||||
%Mattias
|
||||
start_link() ->
|
||||
erlang_js:start(),
|
||||
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, 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) ->
|
||||
Ref = make_ref(),
|
||||
GameVM ! {user_command, User, Command, Args, self(), Ref},
|
||||
receive
|
||||
{Ref, RetVal} ->
|
||||
RetVal;
|
||||
Other -> Other
|
||||
end.
|
Reference in a new issue