diff --git a/apps/dimension_apn/src/dimension_apn_pusher.erl b/apps/dimension_apn/src/dimension_apn_worker.erl similarity index 92% rename from apps/dimension_apn/src/dimension_apn_pusher.erl rename to apps/dimension_apn/src/dimension_apn_worker.erl index 12cc33a..991429e 100644 --- a/apps/dimension_apn/src/dimension_apn_pusher.erl +++ b/apps/dimension_apn/src/dimension_apn_worker.erl @@ -6,7 +6,7 @@ %%% @end %%% Created : 02. 4月 2025 19:09 %%%------------------------------------------------------------------- --module(dimension_apn_pusher). +-module(dimension_apn_worker). -author("anlicheng"). -behaviour(gen_server). @@ -14,7 +14,6 @@ %% API -export([start_link/1]). -export([push/4]). --export([test/1]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). @@ -30,14 +29,9 @@ %%% API %%%=================================================================== -test(DeviceToken) -> - Title = <<"这是一个消息通知"/utf8>>, - Body = jiffy:encode(#{<<"id">> => 1234, <<"name">> => <<"英雄第二季"/utf8>>}, [force_utf8]), - gen_server:cast(?SERVER, {push, DeviceToken, Title, Body}). - -spec push(Pid :: pid(), DeviceToken :: binary(), Title :: binary(), Body :: binary()) -> no_return(). push(Pid, DeviceToken, Title, Body) when is_pid(Pid), is_binary(DeviceToken), is_binary(Title), is_binary(Body) -> - gen_server:cast(Pid, {push, DeviceToken, Title, Body}). + gen_server:call(Pid, {push, DeviceToken, Title, Body}). %% @doc Spawns the server and registers the local name (unique) -spec(start_link(Opts :: list()) -> @@ -69,6 +63,73 @@ init([Props]) -> {ok, #state{apns_pid = ApnsPid, headers = Headers}}. +%% @private +%% @doc Handling call messages +-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()}, + State :: #state{}) -> + {reply, Reply :: term(), NewState :: #state{}} | + {reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} | + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), Reply :: term(), NewState :: #state{}} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_call({push, DeviceToken, Title, Body}, _From, State = #state{apns_pid = ApnsPid, headers = Headers}) -> + Notification = #{ + aps => #{ + alert => #{ + title => Title, + body => Body + }, + % 播放默认声音 + sound => <<"default">>, + % App 图标角标 + badge => 1 + } + }, + PushResult = apns:push_notification(ApnsPid, DeviceToken, Notification, Headers), + lager:debug("[dimension_apn_pusher] push result is: ~p", [PushResult]), + {reply, ok, State}. + +%% @private +%% @doc Handling cast messages +-spec(handle_cast(Request :: term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_cast(_Request, State) -> + {noreply, State}. + +%% @private +%% @doc Handling all non call/cast messages +-spec(handle_info(Info :: timeout() | term(), State :: #state{}) -> + {noreply, NewState :: #state{}} | + {noreply, NewState :: #state{}, timeout() | hibernate} | + {stop, Reason :: term(), NewState :: #state{}}). +handle_info(_Info, State = #state{}) -> + {noreply, State}. + +%% @private +%% @doc 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. +-spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()), + State :: #state{}) -> term()). +terminate(_Reason, _State = #state{}) -> + ok. + +%% @private +%% @doc Convert process state when code is changed +-spec(code_change(OldVsn :: term() | {down, term()}, State :: #state{}, + Extra :: term()) -> + {ok, NewState :: #state{}} | {error, Reason :: term()}). +code_change(_OldVsn, State = #state{}, _Extra) -> + {ok, State}. + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== + -spec parse_headers(Headers :: list()) -> map(). parse_headers(Headers) -> parse_headers(Headers, #{}). @@ -112,72 +173,4 @@ connection_opts([{type, Type}|ConnectionOpts], Acc) -> 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 --spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()}, - State :: #state{}) -> - {reply, Reply :: term(), NewState :: #state{}} | - {reply, Reply :: term(), NewState :: #state{}, timeout() | hibernate} | - {noreply, NewState :: #state{}} | - {noreply, NewState :: #state{}, timeout() | hibernate} | - {stop, Reason :: term(), Reply :: term(), NewState :: #state{}} | - {stop, Reason :: term(), NewState :: #state{}}). -handle_call(_Request, _From, State = #state{}) -> - {reply, ok, State}. - -%% @private -%% @doc Handling cast messages --spec(handle_cast(Request :: term(), 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, headers = Headers}) -> - Notification = #{ - aps => #{ - alert => #{ - title => Title, - body => Body - }, - % 播放默认声音 - sound => <<"default">>, - % App 图标角标 - badge => 1 - } - }, - PushResult = apns:push_notification(ApnsPid, DeviceToken, Notification, Headers), - lager:debug("[dimension_apn_pusher] push result is: ~p", [PushResult]), - - {noreply, State}. - -%% @private -%% @doc Handling all non call/cast messages --spec(handle_info(Info :: timeout() | term(), State :: #state{}) -> - {noreply, NewState :: #state{}} | - {noreply, NewState :: #state{}, timeout() | hibernate} | - {stop, Reason :: term(), NewState :: #state{}}). -handle_info(_Info, State = #state{}) -> - {noreply, State}. - -%% @private -%% @doc 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. --spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()), - State :: #state{}) -> term()). -terminate(_Reason, _State = #state{}) -> - ok. - -%% @private -%% @doc Convert process state when code is changed --spec(code_change(OldVsn :: term() | {down, term()}, State :: #state{}, - Extra :: term()) -> - {ok, NewState :: #state{}} | {error, Reason :: term()}). -code_change(_OldVsn, State = #state{}, _Extra) -> - {ok, State}. - -%%%=================================================================== -%%% Internal functions -%%%=================================================================== + connection_opts(ConnectionOpts, Acc). \ No newline at end of file diff --git a/apps/dimension_apn/src/dimension_spn_pusher.erl b/apps/dimension_apn/src/dimension_spn_pusher.erl new file mode 100644 index 0000000..e05add2 --- /dev/null +++ b/apps/dimension_apn/src/dimension_spn_pusher.erl @@ -0,0 +1,25 @@ +%%%------------------------------------------------------------------- +%%% @author anlicheng +%%% @copyright (C) 2025, +%%% @doc +%%% +%%% @end +%%% Created : 03. 4月 2025 15:41 +%%%------------------------------------------------------------------- +-module(dimension_spn_pusher). +-author("anlicheng"). + +%% API +-export([push/3]). +-export([test/1]). + +test(DeviceToken) -> + Title = <<"这是一个消息通知"/utf8>>, + Body = jiffy:encode(#{<<"id">> => 1234, <<"name">> => <<"英雄第二季"/utf8>>}, [force_utf8]), + push(DeviceToken, Title, Body). + +-spec push(DeviceToken :: binary(), Title :: binary(), Body :: binary()) -> no_return(). +push(DeviceToken, Title, Body) when is_binary(DeviceToken), is_binary(Title), is_binary(Body) -> + poolboy:transaction(apns_pool, fun(WorkerPid) -> + dimension_apn_worker:push(WorkerPid, DeviceToken, Title, Body) + end). \ No newline at end of file diff --git a/config/sys.config b/config/sys.config index ddd6460..4aaa4d2 100644 --- a/config/sys.config +++ b/config/sys.config @@ -12,7 +12,7 @@ {pools, [ %% 推送设置 {apns_pool, - [{size, 1}, {max_overflow, 1}, {worker_module, dimension_apn_pusher}], + [{size, 1}, {max_overflow, 1}, {worker_module, dimension_apn_worker}], [ {connection_opts, [ {apple_host, "api.sandbox.push.apple.com"},