【问题标题】:About a client for pusher written in Erlang关于一个用 Erlang 编写的 pusher 客户端
【发布时间】:2015-08-14 18:29:37
【问题描述】:

我想编写一个模块,该模块需要能够在 Erlang 中将消息推送到推送器。我找到了这个 repo https://github.com/bradfordw/pusherl,它不再维护,但我认为我可以适应使其工作。我按照自述文件,成功运行了所有 Rebar 命令。然后我通过命令打开钢筋控制台

./rel/pusherl/bin/pusherl console

所以服务器应该启动。但是当我尝试打电话时

gen_server:call(pusherl_server, {push, {"ChannelName", "EventName", "Payload"}}).

然后它会抛出错误:

exception exit: {noproc,{gen_server,call,
                                   [pusherl_server,
                                    {push, 

    {"ChannelName","EventName","Payload"}}]}}
     in function  gen_server:call/2 (gen_server.erl, line 182)

我对 Erlang 和 OTP 还很陌生,我花了半天时间让它工作但没有成功。请帮我解决这个问题。我真的很感激。

顺便说一下,如果你认识其他的推送客户端,请推荐我。非常感谢。

这里是 gen_server 回调的代码:

-module(pusherl_server).
-behaviour(gen_server).
-define(SERVER, ?MODULE).
-define(JP, fun(K,V) -> string:join([K,V],"=") end).

-record(state,{app_id, key, secret}).

-export([start_link/0]).

-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

start_link() ->
  gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

init(_) ->
  {ok, PusherAppId} = application:get_env(pusher_app_id),
  {ok, PusherKey} = application:get_env(pusher_key),
  {ok, PusherSecret} = application:get_env(pusher_secret),
  {ok, #state{app_id=PusherAppId, key=PusherKey, secret=PusherSecret}}.

handle_call({push, {ChannelName, EventName, Payload}}, _From, State) ->
  case http_request(ChannelName, EventName, Payload, State) of
    {ok, _} -> {reply, ok, State};
    {error, _} -> {reply, error, State}
  end;
handle_call(_Request, _From, State) ->
  {noreply, ok, State}.

handle_cast({push, {ChannelName, EventName, Payload}}, State) ->
  case http_request(ChannelName, EventName, Payload, State) of
    {ok, _} -> {noreply, ok, State};
    {error, _} -> {noreply, error, State}
  end;
handle_cast(_Msg, State) ->
  {noreply, State}.

handle_info(_Info, State) ->
  {noreply, State}.

terminate(_Reason, _State) ->
  ok.

code_change(_OldVsn, State, _Extra) ->
  {ok, State}.

http_request(ChannelName, EventName, Payload, Config) when is_list(ChannelName), is_record(Config, state) ->
  {ok, ReqProps} = http_request_props(Payload, EventName, ChannelName, Config),
    httpc:request(post, ReqProps, [], []).

http_request_props(Payload, EventName, ChannelName, #state{app_id=AppId, key=AppKey, secret=AppSecret}) ->
    Md5String = lists:flatten([io_lib:format("~2.16.0b",[N]) || <<N>> <= crypto:md5(Payload)]),
  ToSign = ["POST",
                lists:flatten(["/apps/", AppId, "/channels/", ChannelName, "/events"]),
                string:join([?JP("auth_key", AppKey),
        ?JP("auth_timestamp", get_time_as_string()),
        ?JP("auth_version", "1.0"),
        ?JP("body_md5", Md5String),
                ?JP("name", EventName)
                ],"&")
  ],
    AuthSignature = signed_params(ToSign, AppSecret),
    QueryParams = [
        ?JP("auth_key", AppKey),
      ?JP("auth_timestamp", get_time_as_string()),
      ?JP("auth_version","1.0"),
      ?JP("body_md5", Md5String),
        ?JP("auth_signature", AuthSignature),
        ?JP("name", EventName)
    ],
  Url = http_api_url(AppId, ChannelName, QueryParams),
  {ok, {Url, [], "application/x-www-form-urlencoded", Payload}}.

http_api_url(AppId, ChannelName, QueryParams) ->
  QueryString = string:join(QueryParams,"&"),
  lists:flatten(["http://api.pusherapp.com/apps/",AppId,"/channels/",ChannelName,"/events?", QueryString]).

get_time_as_string() ->
  {M, S, _} = now(),
  integer_to_list(((M * 1000000) + S)).

signed_params(Params, Secret) ->
    lists:flatten([io_lib:format("~2.16.0b",[N]) || <<N:8>> <= sha2:hmac_sha256(Secret, string:join(Params,"\n"))]).

【问题讨论】:

  • 我还是遇到了我提到的问题。请任何人帮我解决这个问题。谢谢

标签: erlang erlang-otp


【解决方案1】:

noproc 表示您尝试调用的进程没有运行。你需要从以下开始:

pusherl_server:start_link().

请注意,这会将pusherl_server 进程链接到调用进程。如果你在 shell 中运行它,然后做了一些导致错误的事情,错误将通过链接传播到 pusherl_server 进程并杀死它,所以你必须重新启动它。

为避免这种情况,您可以在启动进程后取消链接:

{ok, Pid} = pusherl_server:start_link().
unlink(Pid).

或在模块中添加一个start 函数,其作用与start_link 相同,只是它调用gen_server:start 而不是gen_server:start_link

【讨论】:

  • 另一种选择是在 shell 中执行 catch_exception(true). 来告诉它捕获异常而不是让它们自己杀死。
  • 另外,一旦他解决了noproc 的问题,他就会遇到pusherl_server:init 需要设置一些应用程序环境变量的问题。
  • 其实我是通过rebar./rel/pusherl/bin/pusherl console的命令运行的。所以我认为服务器已经启动了。让我试试 erl 控制台。
  • 很抱歉让您感到困惑。我编辑了我的问题以使其更清楚。谢谢
猜你喜欢
  • 2011-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-06
  • 2020-04-03
  • 2017-06-08
  • 2012-06-01
相关资源
最近更新 更多