From 6c46e3d92b3260067504c402ed34a54c9a821f57 Mon Sep 17 00:00:00 2001 From: anlicheng <244108715@qq.com> Date: Mon, 4 Aug 2025 16:02:26 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AE=80=E5=8C=96=E6=8E=A8=E9=80=81=E7=9A=84?= =?UTF-8?q?=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 47 ++++++++++++++--- apps/dimension_apn/src/api_handler.erl | 10 ---- apps/dimension_apn/src/dimension_apn.app.src | 1 - apps/dimension_apn/src/dimension_apn_app.erl | 5 +- .../src/dimension_apn_worker.erl | 51 ++++++++----------- .../src/dimension_mnesia_manager.erl | 27 ---------- .../dimension_apn/src/mnesia_device_token.erl | 42 --------------- 7 files changed, 63 insertions(+), 120 deletions(-) delete mode 100644 apps/dimension_apn/src/dimension_mnesia_manager.erl delete mode 100644 apps/dimension_apn/src/mnesia_device_token.erl diff --git a/README.md b/README.md index 4d8c6a3..42f7494 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,44 @@ -dimension_apn -===== +# 基于erlang的推送服务 -An OTP application +## mysql + mysql -h127.0.0.1 -uroot -p'r3a-7Qrh#3Q' -Build ------ +## api接口 - $ rebar3 compile + +### 1. 批量推送消息 + url: "/api/push" + method: POST + body: + + [ + { + "device_token": "b48b911e85874b403ce80cbb33864e8ed6f06455e80310b0f6b95e672a3e39dc", + "title": "动物狂响曲", + "body": "第7集(校服与被毛更深处),bilibili已更新", + + "unread_num": 10, + + "custom_data": { + "target": "detail", + "params": { + "drama_id": 1234 + } + } + }, + + { + "device_token": "b48b911e85874b403ce80cbb33864e8ed6f06455e80310b0f6b95e672a3e39dc", + "title": "动物狂响曲", + "body": "第7集(校服与被毛更深处),bilibili已更新", + "custom_data": { + "target": "detail", + "params": { + "drama_id": 1234 + } + } + } + ] + + 字段说明: + 1. custom_data使用指定页面的跳转逻辑,target字段目前固定为: detail;参数部分的: drama_id指定为要进入的详情页面id \ No newline at end of file diff --git a/apps/dimension_apn/src/api_handler.erl b/apps/dimension_apn/src/api_handler.erl index cdf1869..d2c91cd 100644 --- a/apps/dimension_apn/src/api_handler.erl +++ b/apps/dimension_apn/src/api_handler.erl @@ -85,16 +85,6 @@ read_body(Req, AccData) -> %% helper methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% 更新token信息 -handle_request("POST", "/api/device_token", _, #{<<"user_id">> := UserId, <<"token">> := Token}) -> - case mnesia_device_token:insert(UserId, Token, dimension_utils:current_time()) of - ok -> - {ok, 200, dimension_utils:json_data(<<"success">>)}; - {error, Reason} -> - lager:notice("[api_handler] insert user_id: ~p, token: ~p, error: ~p", [UserId, Token, Reason]), - {ok, 200, dimension_utils:json_error(-1, <<"更新token失败"/utf8>>)} - end; - %% 向用户推送数据 handle_request("POST", "/api/push", _, Notifications) -> {ok, Pid} = dimension_apn_worker:start_link(), diff --git a/apps/dimension_apn/src/dimension_apn.app.src b/apps/dimension_apn/src/dimension_apn.app.src index 7107762..55bf54a 100644 --- a/apps/dimension_apn/src/dimension_apn.app.src +++ b/apps/dimension_apn/src/dimension_apn.app.src @@ -13,7 +13,6 @@ ssl, jiffy, apns, - mnesia, kernel, stdlib ]}, diff --git a/apps/dimension_apn/src/dimension_apn_app.erl b/apps/dimension_apn/src/dimension_apn_app.erl index f4231cf..1fa6ccb 100644 --- a/apps/dimension_apn/src/dimension_apn_app.erl +++ b/apps/dimension_apn/src/dimension_apn_app.erl @@ -13,8 +13,6 @@ start(_StartType, _StartArgs) -> io:setopts([{encoding, unicode}]), %% 加速内存的回收 erlang:system_flag(fullsweep_after, 16), - %% 启动mnesia - ok = mnesia:start(), %% 启动http服务 start_http_server(), dimension_apn_sup:start_link(). @@ -34,8 +32,7 @@ start_http_server() -> Dispatcher = cowboy_router:compile([ {'_', [ - {"/api/[...]", http_protocol, [api_handler]}, - {"/ws", ws_channel, []} + {"/api/[...]", api_handler, []} ]} ]), diff --git a/apps/dimension_apn/src/dimension_apn_worker.erl b/apps/dimension_apn/src/dimension_apn_worker.erl index b4d9767..e72ebd6 100644 --- a/apps/dimension_apn/src/dimension_apn_worker.erl +++ b/apps/dimension_apn/src/dimension_apn_worker.erl @@ -32,15 +32,12 @@ test() -> {ok, Pid} = start_link(), - UserId = <<"9df4dbb1-aff7-4caa-9adb-cb426a7dbcca">>, DeviceToken = <<"b48b911e85874b403ce80cbb33864e8ed6f06455e80310b0f6b95e672a3e39dc">>, Title = <<"动物狂响曲"/utf8>>, Body = <<"第7集(校服与被毛更深处),bilibili已更新"/utf8>>, - - mnesia_device_token:insert(UserId, DeviceToken, dimension_utils:current_time()), push(Pid, [ #{ - <<"user_id">> => UserId, + <<"device_token">> => DeviceToken, <<"title">> => Title, <<"body">> => Body, <<"custom_data">> => #{ @@ -107,9 +104,9 @@ handle_call(_Request, _From, State) -> {noreply, NewState :: #state{}, timeout() | hibernate} | {stop, Reason :: term(), NewState :: #state{}}). handle_cast({push, Notifications}, State = #state{apns_pid = ApnsPid, headers = Headers}) -> - lists:foreach(fun(#{<<"user_id">> := UserId, <<"title">> := Title, <<"body">> := Body, <<"custom_data">> := CustomData}) -> - PushResult = push_task(ApnsPid, UserId, Title, Body, CustomData, Headers), - lager:debug("[dimension_apn_pusher] push result is: ~p", [PushResult]) + lists:foreach(fun(#{<<"device_token">> := DeviceToken, <<"title">> := Title, <<"body">> := Body, <<"unread_num">> := UnreadNum, <<"custom_data">> := CustomData}) -> + PushResult = push_task(ApnsPid, DeviceToken, Title, Body, UnreadNum, CustomData, Headers), + lager:debug("[dimension_apn_pusher] device_token: ~p, push result is: ~p", [DeviceToken, PushResult]) end, Notifications), {noreply, State}; @@ -147,30 +144,24 @@ code_change(_OldVsn, State = #state{}, _Extra) -> %%% Internal functions %%%=================================================================== -push_task(ApnsPid, UserId, Title, Body, CustomData, Headers) - when is_pid(ApnsPid), is_binary(UserId), is_binary(Title), is_binary(Body), is_map(CustomData), is_map(Headers) -> - - case mnesia_device_token:get_token(UserId) of - error -> - ok; - {ok, DeviceToken} -> - Notification = #{ - aps => #{ - alert => #{ - title => Title, - body => Body - }, - 'mutable-content' => 1, - % 播放默认声音 - sound => <<"default">>, - % App 图标角标 - badge => 1 - % category => <<"HUB_MESSAGE">> - }, - custom_data => CustomData +push_task(ApnsPid, DeviceToken, Title, Body, UnreadNum, CustomData, Headers) + when is_pid(ApnsPid), is_binary(DeviceToken), is_binary(Title), is_binary(Body), is_integer(UnreadNum), is_map(CustomData), is_map(Headers) -> + Notification = #{ + aps => #{ + alert => #{ + title => Title, + body => Body }, - apns:push_notification(ApnsPid, DeviceToken, Notification, Headers) - end. + 'mutable-content' => 1, + % 播放默认声音 + sound => <<"default">>, + % App 图标角标 + badge => UnreadNum + % category => <<"HUB_MESSAGE">> + }, + custom_data => CustomData + }, + apns:push_notification(ApnsPid, DeviceToken, Notification, Headers). -spec parse_headers(Headers :: list()) -> map(). parse_headers(Headers) -> diff --git a/apps/dimension_apn/src/dimension_mnesia_manager.erl b/apps/dimension_apn/src/dimension_mnesia_manager.erl deleted file mode 100644 index 84cc95a..0000000 --- a/apps/dimension_apn/src/dimension_mnesia_manager.erl +++ /dev/null @@ -1,27 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @author anlicheng -%%% @copyright (C) 2025, -%%% @doc -%%% -%%% @end -%%% Created : 07. 4月 2025 15:47 -%%%------------------------------------------------------------------- --module(dimension_mnesia_manager). --author("anlicheng"). - -%% API --export([init_database/0]). - -%% 只能调用一次 -init_database() -> - %% 清理掉以前的schema - mnesia:stop(), - mnesia:delete_schema([node()]), - - %% 创建schema - ok = mnesia:create_schema([node()]), - ok = mnesia:start(), - %% 创建数据库表 - mnesia_device_token:create_table(), - - ok. \ No newline at end of file diff --git a/apps/dimension_apn/src/mnesia_device_token.erl b/apps/dimension_apn/src/mnesia_device_token.erl deleted file mode 100644 index 821a866..0000000 --- a/apps/dimension_apn/src/mnesia_device_token.erl +++ /dev/null @@ -1,42 +0,0 @@ -%%%------------------------------------------------------------------- -%%% @author anlicheng -%%% @copyright (C) 2025, -%%% @doc -%%% -%%% @end -%%% Created : 07. 4月 2025 14:33 -%%%------------------------------------------------------------------- --module(mnesia_device_token). --author("anlicheng"). --include("dimension_tables.hrl"). - -%% API --export([create_table/0, insert/3, get_token/1]). - -create_table() -> - %% id生成器 - mnesia:create_table(device_token, [ - {attributes, record_info(fields, device_token)}, - {record_name, device_token}, - {disc_copies, [node()]}, - {type, set} - ]). - --spec insert(UserId :: binary(), DeviceToken :: binary(), Timestamp :: integer()) -> ok | {error, Reason :: any()}. -insert(UserId, DeviceToken, Timestamp) when is_binary(UserId), is_binary(DeviceToken), is_integer(Timestamp) -> - Record = #device_token{user_id = UserId, token = DeviceToken, timestamp = Timestamp}, - case mnesia:transaction(fun() -> mnesia:write(device_token, Record, write) end) of - {'atomic', Res} -> - Res; - {'aborted', Reason} -> - {error, Reason} - end. - --spec get_token(UserId :: binary()) -> error | {ok, Token :: binary()}. -get_token(UserId) when is_binary(UserId) -> - case mnesia:dirty_read(device_token, UserId) of - [] -> - error; - [#device_token{token = Token} | _] -> - {ok, Token} - end. \ No newline at end of file