PageRenderTime 31ms CodeModel.GetById 17ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/mod_base/resources/resource_websocket.erl

https://code.google.com/p/zotonic/
Erlang | 111 lines | 67 code | 18 blank | 26 comment | 0 complexity | 3ffe8c2e3660e3a4e1af444d7373bcdd MD5 | raw file
  1%% @author Marc Worrell <marc@worrell.nl>
  2%% @copyright 2010 Marc Worrell
  3%% @doc WebSocket connections
  4
  5%% Copyright 2010 Marc Worrell
  6%%
  7%% Licensed under the Apache License, Version 2.0 (the "License");
  8%% you may not use this file except in compliance with the License.
  9%% You may obtain a copy of the License at
 10%% 
 11%%     http://www.apache.org/licenses/LICENSE-2.0
 12%% 
 13%% Unless required by applicable law or agreed to in writing, software
 14%% distributed under the License is distributed on an "AS IS" BASIS,
 15%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16%% See the License for the specific language governing permissions and
 17%% limitations under the License.
 18
 19-module(resource_websocket).
 20-author("Marc Worrell <marc@worrell.nl>").
 21
 22-export([
 23    init/1, 
 24    forbidden/2,
 25    upgrades_provided/2,
 26    charsets_provided/2,
 27    content_types_provided/2,
 28    provide_content/2,
 29    websocket_start/2,
 30    
 31    handle_message/2
 32]).
 33
 34-include_lib("webmachine_resource.hrl").
 35-include_lib("include/zotonic.hrl").
 36
 37init(_Args) -> {ok, []}.
 38
 39
 40%% @doc The request must have a valid session cookie.
 41forbidden(ReqData, _State) ->
 42    Context = z_context:new(ReqData),
 43    Context1 = z_context:continue_session(Context),
 44    ?WM_REPLY(not z_context:has_session(Context1), Context1).
 45
 46%% @doc Possible connection upgrades
 47upgrades_provided(ReqData, Context) ->
 48    {[
 49        {"WebSocket", websocket_start}
 50    ], ReqData, Context}.
 51
 52charsets_provided(ReqData, Context) ->
 53    {[{"utf-8", fun(X) -> X end}], ReqData, Context}.
 54
 55content_types_provided(ReqData, Context) ->
 56    {[{"text/html", provide_content}], ReqData, Context}.
 57
 58provide_content(ReqData, Context) ->
 59    Context1 = ?WM_REQ(ReqData, Context),
 60    Context2 = z_context:ensure_qs(Context1),
 61    Context3 = z_context:set_resp_header("X-Robots-Tag", "noindex", Context2),
 62    Rendered = z_template:render("error_websocket.tpl", z_context:get_all(Context), Context3),
 63    {Output, OutputContext} = z_context:output(Rendered, Context3),
 64    ?WM_REPLY(Output, OutputContext).
 65
 66%% @doc Initiate the websocket connection upgrade
 67websocket_start(ReqData, Context) ->
 68    ContextReq = ?WM_REQ(ReqData, Context),
 69    Context1 = z_context:ensure_all(ContextReq),
 70    case z_context:get_req_header("sec-websocket-version", Context1) of
 71        undefined ->
 72            case z_context:get_req_header("sec-websocket-key1", Context1) of
 73                undefined ->
 74                    z_websocket_hixie75:start(ReqData, Context1);
 75                WsKey1 ->
 76                    z_websocket_hybi00:start(WsKey1, ReqData, Context1)
 77            end;
 78        % https://github.com/ostinelli/misultin/commit/23b21e0c8d1d9aa4bc0ce60d527a8716d76e025c
 79        "7" ->
 80            % http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07
 81            todo; % hybi07(WsKey1, Context1);
 82        "8" ->
 83            % http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10
 84            todo % hybi10(WsKey1, Context1)
 85    end.
 86
 87
 88
 89%% Handle a message from the browser, should contain an url encoded request. Sends result script back to browser.
 90handle_message(Msg, Context) ->
 91    Qs = mochiweb_util:parse_qs(Msg),
 92    Context1 = z_context:set('q', Qs, Context),
 93
 94    {ResultScript, ResultContext} = try
 95        % Enable caching lookup values, essential for fast data handling
 96        z_depcache:in_process(true),
 97        resource_postback:process_postback(Context1)
 98    catch
 99        Error:X ->
100            ?zWarning(io_lib:format("~p:~p~n~p", [Error, X, erlang:get_stacktrace()]), Context1),
101            {case z_context:get_q("z_trigger_id", Context1) of 
102                undefined -> [];
103                ZTrigger -> [" z_unmask_error('",z_utils:js_escape(ZTrigger),"');"]
104             end, 
105             Context1}
106    end,
107    % Cleanup process dict, so our process heap is smaller between calls
108    % z_depcache:flush_process_dict(),
109    z_session_page:add_script(ResultScript, ResultContext),
110    erlang:erase().
111