From c5ee4eec0a7f4ee6d564b919d135d3b73c696f32 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Thu, 3 Apr 2025 15:33:48 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=84=E8=8C=83=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/dimension_apn/src/dimension_apn.app.src | 1 + .../src/dimension_apn_pusher.erl | 106 +++++++++++------- apps/dimension_apn/src/dimension_apn_sup.erl | 17 ++- config/sys.config | 26 +++++ 4 files changed, 98 insertions(+), 52 deletions(-) diff --git a/apps/dimension_apn/src/dimension_apn.app.src b/apps/dimension_apn/src/dimension_apn.app.src index e12a4f4..55bf54a 100644 --- a/apps/dimension_apn/src/dimension_apn.app.src +++ b/apps/dimension_apn/src/dimension_apn.app.src @@ -5,6 +5,7 @@ {mod, {dimension_apn_app, []}}, {applications, [ + poolboy, ranch, cowboy, lager, diff --git a/apps/dimension_apn/src/dimension_apn_pusher.erl b/apps/dimension_apn/src/dimension_apn_pusher.erl index 9783703..12cc33a 100644 --- a/apps/dimension_apn/src/dimension_apn_pusher.erl +++ b/apps/dimension_apn/src/dimension_apn_pusher.erl @@ -12,7 +12,7 @@ -behaviour(gen_server). %% API --export([start_link/0]). +-export([start_link/1]). -export([push/4]). -export([test/1]). @@ -22,7 +22,8 @@ -define(SERVER, ?MODULE). -record(state, { - apns_pid :: pid() + apns_pid :: pid(), + headers :: map() }). %%%=================================================================== @@ -39,10 +40,10 @@ push(Pid, DeviceToken, Title, Body) when is_pid(Pid), is_binary(DeviceToken), is gen_server:cast(Pid, {push, DeviceToken, Title, Body}). %% @doc Spawns the server and registers the local name (unique) --spec(start_link() -> +-spec(start_link(Opts :: list()) -> {ok, Pid :: pid()} | ignore | {error, Reason :: term()}). -start_link() -> - gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). +start_link(Props) when is_list(Props) -> + gen_server:start_link(?MODULE, [Props], []). %%%=================================================================== %%% gen_server callbacks @@ -53,25 +54,65 @@ start_link() -> -spec(init(Args :: term()) -> {ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} | {stop, Reason :: term()} | ignore). -init([]) -> - {ok, ApnsPid} = apns:connect(#{ - name => my_first_conn, - apple_host => "api.sandbox.push.apple.com", - apple_port => 443, - certfile => "/usr/local/code/erl/dimension_apn/apps/dimension_apn/priv/aps_development.pem", - keyfile => "/usr/local/code/erl/dimension_apn/apps/dimension_apn/priv/priv_key.pem", - type => cert, - timeout => 5000, +init([Props]) -> + ConnectionOpts0 = proplists:get_value(connection_opts, Props), + Headers0 = proplists:get_value(headers, Props), + + ConnectionOpts = connection_opts(ConnectionOpts0), + Headers = parse_headers(Headers0), + + lager:debug("[dimension_apn_pusher] connection opts: ~p, headers: ~p", [ConnectionOpts, Headers]), + + {ok, ApnsPid} = apns:connect(ConnectionOpts), + ok = apns:wait_for_connection_up(ApnsPid), + lager:debug("[dimension_apn_pusher]connect get pid: ~p", [ApnsPid]), + + {ok, #state{apns_pid = ApnsPid, headers = Headers}}. + +-spec parse_headers(Headers :: list()) -> map(). +parse_headers(Headers) -> + parse_headers(Headers, #{}). +parse_headers([], Acc) -> + Acc; +parse_headers([{apns_expiration, ApnsExpiration}|Headers], Acc) -> + parse_headers(Headers, Acc#{apns_expiration => integer_to_list(ApnsExpiration)}); +parse_headers([{apns_priority, ApnsPriority}|Headers], Acc) -> + parse_headers(Headers, Acc#{apns_priority => integer_to_list(ApnsPriority)}); +parse_headers([{apns_topic, Topic}|Headers], Acc) -> + parse_headers(Headers, Acc#{apns_topic => Topic}); +parse_headers([{apns_push_type, PushType}|Headers], Acc) -> + parse_headers(Headers, Acc#{apns_push_type => PushType}); +parse_headers([_|Headers], Acc) -> + parse_headers(Headers, Acc). + +%% 解析连接参数 +-spec connection_opts(Opts :: list()) -> map(). +connection_opts(Opts) -> + connection_opts(Opts, #{}). +connection_opts([], Acc) -> + Acc#{ + name => undefined, ssl_opts => [ {verify, verify_peer}, {log_level, debug} ] - }), - ok = apns:wait_for_connection_up(ApnsPid), - - lager:debug("connect get pid: ~p", [ApnsPid]), - - {ok, #state{apns_pid = ApnsPid}}. + }; +connection_opts([{apple_host, AppleHost}|ConnectionOpts], Acc) -> + connection_opts(ConnectionOpts, Acc#{apple_host => AppleHost}); +connection_opts([{apple_port, ApplePort}|ConnectionOpts], Acc) -> + connection_opts(ConnectionOpts, Acc#{apple_port => ApplePort}); +connection_opts([{certfile, CertFile}|ConnectionOpts], Acc) -> + PrivDir = code:priv_dir(dimension_apn) ++ "/", + connection_opts(ConnectionOpts, Acc#{certfile => PrivDir ++ CertFile}); +connection_opts([{keyfile, Keyfile}|ConnectionOpts], Acc) -> + PrivDir = code:priv_dir(dimension_apn) ++ "/", + connection_opts(ConnectionOpts, Acc#{keyfile => PrivDir ++ Keyfile}); +connection_opts([{type, Type}|ConnectionOpts], Acc) -> + connection_opts(ConnectionOpts, Acc#{type => Type}); +connection_opts([{timeout, Timeout}|ConnectionOpts], Acc) -> + connection_opts(ConnectionOpts, Acc#{timeout => Timeout}); +connection_opts([_|ConnectionOpts], Acc) -> + connection_opts(ConnectionOpts, Acc). %% @private %% @doc Handling call messages @@ -92,7 +133,7 @@ handle_call(_Request, _From, State = #state{}) -> {noreply, NewState :: #state{}} | {noreply, NewState :: #state{}, timeout() | hibernate} | {stop, Reason :: term(), NewState :: #state{}}). -handle_cast({push, DeviceToken, Title, Body}, State = #state{apns_pid = ApnsPid}) -> +handle_cast({push, DeviceToken, Title, Body}, State = #state{apns_pid = ApnsPid, headers = Headers}) -> Notification = #{ aps => #{ alert => #{ @@ -105,29 +146,8 @@ handle_cast({push, DeviceToken, Title, Body}, State = #state{apns_pid = ApnsPid} badge => 1 } }, - - lager:debug("call me here"), - - Headers = #{ - %apns_id => undefined, - apns_expiration => "0", - apns_priority => "10", - apns_topic => "com.jihe.dimensionhub", - %apns_collapse_id => undefined, - apns_push_type => "alert" - }, - PushResult = apns:push_notification(ApnsPid, DeviceToken, Notification, Headers), - lager:debug("[] push result is: ~p", [PushResult]), - - Config = #{ host => "feedback.push.apple.com", - port => 2195, - certfile => "/usr/local/code/erl/dimension_apn/apps/dimension_apn/priv/aps_development.pem", - keyfile => "/usr/local/code/erl/dimension_apn/apps/dimension_apn/priv/priv_key.pem", - timeout => 5000 - }, - FeedResult = apns:get_feedback(Config), - lager:debug("[] feed_result result is: ~p", [FeedResult]), + lager:debug("[dimension_apn_pusher] push result is: ~p", [PushResult]), {noreply, State}. diff --git a/apps/dimension_apn/src/dimension_apn_sup.erl b/apps/dimension_apn/src/dimension_apn_sup.erl index 9d7f3bb..ec6f169 100644 --- a/apps/dimension_apn/src/dimension_apn_sup.erl +++ b/apps/dimension_apn/src/dimension_apn_sup.erl @@ -29,16 +29,15 @@ init([]) -> SupFlags = #{strategy => one_for_one, intensity => 1000, period => 3600}, ChildSpecs = [ - #{ - id => dimension_apn_pusher, - start => {'dimension_apn_pusher', start_link, []}, - restart => permanent, - shutdown => 2000, - type => worker, - modules => ['dimension_apn_pusher'] - } + ], - {ok, {SupFlags, ChildSpecs}}. + {ok, {SupFlags, pools() ++ ChildSpecs}}. %% internal functions + +pools() -> + {ok, Pools} = application:get_env(dimension_apn, pools), + lists:map(fun({Name, PoolArgs, WorkerArgs}) -> + poolboy:child_spec(Name, [{name, {local, Name}}|PoolArgs], WorkerArgs) + end, Pools). \ No newline at end of file diff --git a/config/sys.config b/config/sys.config index f51ea53..ddd6460 100644 --- a/config/sys.config +++ b/config/sys.config @@ -1,10 +1,36 @@ [ {dimension_apn, [ + + %% http服务器 {http_server, [ {port, 18080}, {acceptors, 500}, {max_connections, 10240}, {backlog, 10240} + ]}, + + {pools, [ + %% 推送设置 + {apns_pool, + [{size, 1}, {max_overflow, 1}, {worker_module, dimension_apn_pusher}], + [ + {connection_opts, [ + {apple_host, "api.sandbox.push.apple.com"}, + {apple_port, 443}, + {certfile, "aps_development.pem"}, + {keyfile, "priv_key.pem"}, + {type, cert}, + {timeout, 5000} + ]}, + {headers, [ + {apns_expiration, 0}, + {apns_priority, 10}, + {apns_topic, "com.jihe.dimensionhub"}, + {apns_push_type, "alert"} + ]} + ] + } + ]} ]},