Download src/hk_api_util.erl from Snapkitty/hyperkitty-chromium: direct link, hf CLI and curl.
- Browser
- Download file 3.19 kB
-
https://huggingface.co/Snapkitty/hyperkitty-chromium/resolve/main/src/hk_api_util.erl
- Command line
-
hf download hf://Snapkitty/hyperkitty-chromium/src/hk_api_util.erl
-
curl -L -o hk_api_util.erl https://huggingface.co/Snapkitty/hyperkitty-chromium/resolve/main/src/hk_api_util.erl
3.19 kB
| %%%------------------------------------------------------------------- | |
| %%% @doc Shared helpers for the Cowboy request handlers under | |
| %%% `hk_api_sup': request-id propagation, JSON body/response | |
| %%% handling, and the accepted/succeeded/failed operation-tracking | |
| %%% wrapper every mutating endpoint uses. | |
| %%% @end | |
| %%%------------------------------------------------------------------- | |
| -module(hk_api_util). | |
| -include("hyperkitty.hrl"). | |
| -export([request_id/1, read_json_body/1, reply_json/3, reply_error/3, | |
| run_operation/4]). | |
| %% @doc Every request has a request id: reuse the caller-supplied | |
| %% `x-request-id' header if present (so a client's own tracing | |
| %% correlates), otherwise mint one. | |
| -spec request_id(cowboy_req:req()) -> binary(). | |
| request_id(Req) -> | |
| case cowboy_req:header(<<"x-request-id">>, Req) of | |
| undefined -> hk_id:new(<<"req">>); | |
| Id -> Id | |
| end. | |
| -spec read_json_body(cowboy_req:req()) -> {ok, map(), cowboy_req:req()} | {error, term()}. | |
| read_json_body(Req) -> | |
| case cowboy_req:has_body(Req) of | |
| false -> | |
| {ok, #{}, Req}; | |
| true -> | |
| {ok, Body, Req2} = cowboy_req:read_body(Req), | |
| try {ok, jsx:decode(Body, [return_maps]), Req2} | |
| catch _:_ -> {error, invalid_json} | |
| end | |
| end. | |
| -spec reply_json(non_neg_integer(), term(), cowboy_req:req()) -> cowboy_req:req(). | |
| reply_json(Status, Data, Req) -> | |
| cowboy_req:reply(Status, #{<<"content-type">> => <<"application/json">>}, | |
| jsx:encode(Data), Req). | |
| -spec reply_error(non_neg_integer(), term(), cowboy_req:req()) -> cowboy_req:req(). | |
| reply_error(Status, Reason, Req) -> | |
| reply_json(Status, #{error => term_bin(Reason)}, Req). | |
| %% @doc Run a mutating operation with full lifecycle tracking: | |
| %% create an `accepted' `#operation{}', invoke `Fun/0', mark the | |
| %% operation `succeeded'/`failed' based on the result, and reply | |
| %% with `{operation_id, ..., result: ...}' or an error body. `Fun/0' | |
| %% must return `{ok, Subject, ResultMap}' or `{error, Reason}'. | |
| -spec run_operation(binary(), atom(), fun(() -> {ok, term(), map()} | {error, term()}), | |
| cowboy_req:req()) -> cowboy_req:req(). | |
| run_operation(Kind, RequestId, Fun, Req) -> | |
| hk_operation_store:ensure_table(), | |
| Op = hk_operation_store:create(RequestId, Kind, undefined), | |
| case Fun() of | |
| {ok, Subject, ResultMap} -> | |
| hk_operation_store:complete(Op#operation.operation_id, Subject), | |
| reply_json(200, #{operation_id => Op#operation.operation_id, | |
| request_id => RequestId, | |
| status => succeeded, | |
| result => ResultMap}, Req); | |
| {error, Reason} -> | |
| hk_operation_store:fail(Op#operation.operation_id, #{reason => term_bin(Reason)}), | |
| reply_json(422, #{operation_id => Op#operation.operation_id, | |
| request_id => RequestId, | |
| status => failed, | |
| error => term_bin(Reason)}, Req) | |
| end. | |
| term_bin(Term) when is_binary(Term) -> Term; | |
| term_bin(Term) -> iolist_to_binary(io_lib:format("~p", [Term])). | |