Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added units for reimplementing CWIGA along with the implementation code.

Also added helper method to help us determine our http responses
  • Loading branch information...
commit a4c1476c14cf1a412417efe73a685c0fceab2561 1 parent e3214bf
Yomi Colledge authored
16 lib/chatterl/ebin/chatterl.app
View
@@ -1,7 +1,7 @@
%% This is the application resource file (.app file) for the chatterl,
%% application.
{application, chatterl,
- [{description, "Erlang based chat system."},
+ [{description, "Erlang based chat system."},
{vsn, "0.1.1.8"},
{modules, [chatterl,
message_handler,
@@ -14,12 +14,14 @@
chatterl_sup,
server_sup,
cwiga_sup,
- test_helpers,
- test_chatterl_serv,
- test_chatterl_groups,
- test_chatterl_client,
- test_chatterl_mid_man,
- test_chatterl_store]},
+ cwiga,
+ test_helpers,
+ test_chatterl_serv,
+ test_chatterl_groups,
+ test_chatterl_client,
+ test_chatterl_mid_man,
+ test_chatterl_store,
+ test_cwiga]},
{registered,[chatterl_groups, chatterl_mid_man, chatterl,serv, chatterl_sup]},
{applications, [kernel, stdlib, crypto, inets, mochiweb]},
{mod, {chatterl,[{port,9000},{copy,ram_copies}]}},
153 lib/chatterl/src/cwiga.erl
View
@@ -0,0 +1,153 @@
+%%----------------------------------------------------------------
+%%% @author Yomi Colledge <yomi@boodah.net>
+%%% @doc Web interface for Chatterl
+%%%
+%%% Chatterl Web Gateway, allowing Web based clients to interact
+%%% with Chatterl over a RESTful API.
+%%%
+%%% Allows Chatterl to interface with any web-based interface
+%%% Using JSON and XML, sending the requests off to the chatterl_serv
+%%% module.
+%%%
+%%% All calls to CWIGA will only be allowed via a specified IP, which
+%%% will be defined with the configuration file.
+%%% @end
+%%% @copyright 2008-2009 Yomi Colledge
+%%%---------------------------------------------------------------
+-module(cwiga).
+
+-behaviour(gen_server).
+
+%% API
+-export([start_link/1,stop/0]).
+
+-define(APP, "CWIGA").
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-define(SERVER, ?MODULE).
+-record(state, {}).
+
+%%====================================================================
+%% API
+%%====================================================================
+%%--------------------------------------------------------------------
+%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
+%% Description: Starts the server
+%%--------------------------------------------------------------------
+start_link(Port) ->
+ gen_server:start_link({global, ?SERVER}, ?MODULE, [Port], []).
+
+stop() ->
+ gen_server:call({global, ?SERVER}, stop, infinity).
+
+dispatch_requests(Req) ->
+ %Path = Req:get(path),
+ [Path|Ext] = string:tokens(Req:get(path),"."),
+ Method = Req:get(method),
+ Post = Req:parse_post(),
+ io:format("~p request for ~p with post: ~p~n", [Method, Path, Post]),
+ Response = handle(Method, Path, get_content_type(Ext), Post),
+ Req:respond(Response).
+
+
+handle(_,Path,ContentType,_Post) ->
+ Response = message_handler:get_response_body(ContentType,
+ message_handler:build_carrier("error", "Unknown command: " ++Path)),
+ {404, [{"Content-Type", ContentType}], list_to_binary(Response)}.
+%%====================================================================
+%% gen_server callbacks
+%%====================================================================
+
+%%--------------------------------------------------------------------
+%% Function: init(Args) -> {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%% Description: Initiates the server
+%%--------------------------------------------------------------------
+init([Port]) ->
+ process_flag(trap_exit, true),
+ mochiweb_http:start([{port, Port}, {loop, fun dispatch_requests/1}]),
+ erlang:monitor(process,mochiweb_http),
+ {ok, #state{}}.
+
+%%--------------------------------------------------------------------
+%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} |
+%% {stop, Reason, State}
+%% Description: Handling call messages
+%%--------------------------------------------------------------------
+handle_call(stop, _From, State) ->
+ io:format("Processing shut down ~s~n", [?APP]),
+ {stop, normal, stopped, State};
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+%%--------------------------------------------------------------------
+%% Function: handle_cast(Msg, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% Description: Handling cast messages
+%%--------------------------------------------------------------------
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% Function: handle_info(Info, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% Description: Handling all non call/cast messages
+%%--------------------------------------------------------------------
+handle_info({'DOWN', _Ref, _Process, {mochiweb_http, Host}, Reason}, State) ->
+ io:format("Unable to start mochiweb on ~s:~nReason: ~s~n",[Host,Reason]),
+ {stop,normal,State};
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% Function: terminate(Reason, State) -> void()
+%% Description: This function is called by a gen_server when it is about to
+%% terminate. It should be the opposite of Module:init/1 and do any necessary
+%% cleaning up. When it returns, the gen_server terminates with Reason.
+%% The return value is ignored.
+%%--------------------------------------------------------------------
+terminate(_Reason, _State) ->
+ io:format("Shutting down ChatterlWeb on: ~s...~n",[node(self())]),
+ mochiweb_http:stop(),
+ ok.
+
+%%--------------------------------------------------------------------
+%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
+%% Description: Convert process state when code is changed
+%%--------------------------------------------------------------------
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%%
+%% Gets the content type, used to help CWIGA to determine what format
+%% to respond in.
+%% @spec get_content_type(Type) -> string()
+%%
+%% @end
+%%--------------------------------------------------------------------
+get_content_type(Type) ->
+ case Type of
+ ["json"] ->
+ ["text/json"];
+ ["xml"] ->
+ ["text/xml"];
+ _ -> ["text/json"]
+ end.
2  lib/chatterl/src/test_chatterl_mid_man.erl
View
@@ -219,7 +219,7 @@ group_test_() ->
check_json(mochijson2:decode(chatterl_mid_man:group_create(ContentType,{Room,Description})))),
?assertEqual(<<"Unable to create group: nu">>,
check_json(mochijson2:decode(chatterl_mid_man:group_create(ContentType,{Room,Description}))))
- end},
+ end}},
{"Groups can group destroyed",
fun() ->
% abit lazy but not sure how to check the creation date dynamically atm.
22 lib/chatterl/src/test_cwiga.erl
View
@@ -0,0 +1,22 @@
+-module(test_cwiga).
+
+-include_lib("eunit/include/eunit.hrl").
+-include_lib("chatterl.hrl").
+
+-import(test_helpers,[check_response/2,check_json/1]).
+handles_test_() ->
+ [{setup,
+ fun() ->
+ inets:start(),
+ cwiga:start_link(8080)
+ end,
+ fun(_) ->
+ cwiga:stop()
+ end,
+ [fun() ->
+ Response = http:request("http://127.0.0.1:8080/"),
+ ?assertEqual(404, check_response(code,Response)),
+ ?assertEqual("Object Not Found", check_response(status,Response)),
+ ?assertEqual({"content-type","text/json"}, check_response(content_type,Response)),
+ ?assertEqual(<<"Unknown command: /">>, check_json(mochijson2:decode(check_response(body,Response))))
+ end]}].
18 lib/chatterl/src/test_helpers.erl
View
@@ -1,6 +1,6 @@
-module(test_helpers).
--export([start_client/3,start_group/2,check_json/1]).
+-export([start_client/3,start_group/2,check_response/2,check_json/1]).
%% Helper functions.
start_client(Client,Group,Description) ->
@@ -11,6 +11,20 @@ start_group(Group,Description) ->
chatterl:start(),
chatterl_serv:create(Group,Description).
+check_response(Check,Response) ->
+ {ok,{{"HTTP/1.1",Code,Status},
+ [_Date,
+ _Server,
+ _ContentLength,
+ ContentType],
+ Body}} = Response,
+ case Check of
+ code -> Code;
+ status -> Status;
+ content_type -> ContentType;
+ body -> Body
+ end.
+
check_json(Json) ->
{struct,[{<<"chatterl">>,{struct,[{<<"response">>,{struct,[Response]}}]}}]} = Json,
case Response of
@@ -20,4 +34,4 @@ check_json(Json) ->
Result;
{<<"error">>,Result} ->
Result
- end.
+ end.
Please sign in to comment.
Something went wrong with that request. Please try again.