This commit is contained in:
anlicheng 2025-04-03 15:47:10 +08:00
parent c5ee4eec0a
commit ad518db266
3 changed files with 96 additions and 78 deletions

View File

@ -6,7 +6,7 @@
%%% @end %%% @end
%%% Created : 02. 4 2025 19:09 %%% Created : 02. 4 2025 19:09
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(dimension_apn_pusher). -module(dimension_apn_worker).
-author("anlicheng"). -author("anlicheng").
-behaviour(gen_server). -behaviour(gen_server).
@ -14,7 +14,6 @@
%% API %% API
-export([start_link/1]). -export([start_link/1]).
-export([push/4]). -export([push/4]).
-export([test/1]).
%% gen_server callbacks %% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
@ -30,14 +29,9 @@
%%% API %%% 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(). -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) -> 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) %% @doc Spawns the server and registers the local name (unique)
-spec(start_link(Opts :: list()) -> -spec(start_link(Opts :: list()) ->
@ -69,6 +63,73 @@ init([Props]) ->
{ok, #state{apns_pid = ApnsPid, headers = Headers}}. {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(). -spec parse_headers(Headers :: list()) -> map().
parse_headers(Headers) -> parse_headers(Headers) ->
parse_headers(Headers, #{}). parse_headers(Headers, #{}).
@ -112,72 +173,4 @@ connection_opts([{type, Type}|ConnectionOpts], Acc) ->
connection_opts([{timeout, Timeout}|ConnectionOpts], Acc) -> connection_opts([{timeout, Timeout}|ConnectionOpts], Acc) ->
connection_opts(ConnectionOpts, Acc#{timeout => Timeout}); connection_opts(ConnectionOpts, Acc#{timeout => Timeout});
connection_opts([_|ConnectionOpts], Acc) -> connection_opts([_|ConnectionOpts], Acc) ->
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
%%%===================================================================

View File

@ -0,0 +1,25 @@
%%%-------------------------------------------------------------------
%%% @author anlicheng
%%% @copyright (C) 2025, <COMPANY>
%%% @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).

View File

@ -12,7 +12,7 @@
{pools, [ {pools, [
%% 推送设置 %% 推送设置
{apns_pool, {apns_pool,
[{size, 1}, {max_overflow, 1}, {worker_module, dimension_apn_pusher}], [{size, 1}, {max_overflow, 1}, {worker_module, dimension_apn_worker}],
[ [
{connection_opts, [ {connection_opts, [
{apple_host, "api.sandbox.push.apple.com"}, {apple_host, "api.sandbox.push.apple.com"},