ekfa/apps/efka/src/channel/upload_channel.erl
2025-11-12 23:26:47 +08:00

80 lines
2.8 KiB
Erlang

%%%-------------------------------------------------------------------
%%% @author anlicheng
%%% @copyright (C) 2025, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 12. 11月 2025 17:08
%%%-------------------------------------------------------------------
-module(upload_channel).
-author("anlicheng").
%% API
-export([init/2]).
init(Req0, Opts) ->
Method = binary_to_list(cowboy_req:method(Req0)),
lager:debug("[upload_channel] method is: ~p", [Method]),
Headers = cowboy_req:headers(Req0),
lager:debug("headers is: ~p", [Headers]),
case maps:find(<<"content-type">>, Headers) of
{ok, <<"application/octet-stream">>} ->
Filename = maps:get(<<"x-filename">>, Headers),
case filename:extension(Filename) of
<<>> ->
Req = cowboy_req:reply(400, #{
<<"Content-Type">> => <<"text/html;charset=utf-8">>
}, <<"Miss file extension">>, Req0),
{ok, Req, Opts};
_ ->
Basename = filename:basename(Filename),
handle_raw_file(Req0, binary_to_list(Basename)),
Req2 = cowboy_req:reply(400, #{
<<"Content-Type">> => <<"text/html;charset=utf-8">>
}, <<"ok">>, Req0),
{ok, Req2, Opts}
end;
{ok, ContentType} ->
lager:debug("[upload_channel] unexpect content-type: ~p", [ContentType]),
Req = cowboy_req:reply(400, #{
<<"Content-Type">> => <<"text/html;charset=utf-8">>
}, <<"Expected application/octet-stream">>, Req0),
{ok, Req, Opts};
error ->
Req = cowboy_req:reply(400, #{
<<"Content-Type">> => <<"text/html;charset=utf-8">>
}, <<"Miss content-type header">>, Req0),
{ok, Req, Opts}
end.
%% 读取请求体
handle_raw_file(Req, Basename) ->
Filename = make_file(Basename),
{ok, IoDevice} = file:open(Filename, [write]),
ok = handle_raw_file0(Req, IoDevice),
ok = file:close(IoDevice).
handle_raw_file0(Req, IoDevice) ->
case cowboy_req:read_body(Req) of
{ok, Data, Req1} ->
file:write(IoDevice, Data),
ok;
{more, Data, Req1} ->
file:write(IoDevice, Data),
handle_raw_file0(Req1, IoDevice)
end.
make_file(Basename) when is_list(Basename) ->
{ok, UploadDir} = application:get_env(efka, upload_dir),
{{Y, M, D}, _} = calendar:local_time(),
DateDir = io_lib:format("~p-~p-~p", [Y, M, D]),
BaseDir = UploadDir ++ DateDir,
case filelib:is_dir(BaseDir) of
true ->
ok;
false ->
ok = file:make_dir(BaseDir)
end,
BaseDir ++ "/" ++ Basename.