How to convert the misultin API to cowboy API

I want to achieve a RTMP service, found on the web GitHub - windock/erlyvideo: Erlang RTMP server,

It doesn’t work under erlang/otp 25 anymore,
And it doesn’t update misultin anymore

So, I’m going to copy all the rtmp*.erl modules from erlyvideo into a new project based on cowboy ( GitHub - imboy-pub/imboy: 使用erlang做后端、flutter做前端开发的一款开源的即时聊天解决方案(基于erlang/otp的高性能web框架 cowboy 做后端服务,用 "8核16G 主机(100万PPS)"压测,保持100万+TCP稳定在线90分钟以上) 支持基于webrtc 一对一视频通话功能 ), I need to convert the https://github.com/windock/erlyvideo/blob/master/src/ems_http.erl API service based on cowboy

./src/rtmp_handler.erl

-module(rtmp_handler).
-behavior(cowboy_rest).

-export([init/2]).

-ifdef(EUNIT).
-include_lib("eunit/include/eunit.hrl").
-endif.
-include_lib("kernel/include/logger.hrl").
-include_lib("imboy/include/common.hrl").
-include_lib("imboy/include/ems.hrl").

init(Req0, State0) ->
    Method = cowboy_req:method(Req0),
    Path = cowboy_req:path(Req0),
    handle(Method, Path, State0, Req0).

handle(<<"POST">>, <<"/rtmp/open/", ChunkNumber/binary>>, _State, Req) ->
    lager:info("Request: open/~p.\n", [ChunkNumber]),
    SessionId = generate_session_id(),
    % {ok, _Pid} = rtmpt_client:start(SessionId),
    lager:info("Opened session ~p, timeout ~p.\n", [SessionId]),
    cowboy_req:reply(200
        , #{
            <<"Content-Type">> => ?RTMP_CONTENT_TYPE
            , <<"server">> => ?RTMP_SERVER
        }
        , SessionId
        , Req);
% handle the 404 page not found
handle(_, Path, State, Req) ->
    lager:info(io_lib:format("rtmp_handler/handle: ~p ~n", [Path])),
    cowboy_req:reply(404, State, Req).

-spec generate_session_id() -> list().
generate_session_id() ->
    {T1, T2, T3} = erlang:timestamp(),
    lists:flatten(io_lib:format("~p:~p:~p", [T1, T2, T3])).

HTTP has a normal response, but the console reports the following error, for guidance:

2023-08-08 15:16:55.823 UTC [info] imboy@127.0.0.1#<0.20708.0> FORMAT ERROR: "Opened session ~p, timeout ~p.\n" ["1691:507815:823485"]1I1
2023-08-08 15:16:55.823 UTC [error] imboy@127.0.0.1#<0.20708.0> CRASH REPORT Process <0.20708.0> with 0 neighbours crashed with reason: no try clause matching #{bindings => #{},body_length => 0,cert => undefined,has_body => false,has_sent_resp => true,headers => #{<<"accept">> => <<"*/*">>,<<"accept-encoding">> => <<"gzip, deflate, br">>,<<"accept-language">> => <<"zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7">>,<<"connection">> => <<"keep-alive">>,<<"content-length">> => <<"0">>,<<"content-type">> => <<"text/plain;charset=UTF-8">>,<<"cookie">> => <<"remember_tenant_59ba36addc2b2f9401580f014c7f58ea4e30989d=eyJpdiI6IktEc3NyYW5QNlhjTmdtdXV5d0pHaHc9PSIsInZhbH...">>,...},...} in cowboy_handler:execute/2 line 371E1
2023-08-08 15:16:55.825 UTC [error] imboy@127.0.0.1#<0.20708.0> Cowboy stream 1 with ranch listener imboy_listener and connection process <0.20707.0> had its request process exit with reason: no try clause matching #{bindings => #{},body_length => 0,cert => undefined,has_body => false,has_sent_resp => true,headers => #{<<"accept">> => <<"*/*">>,<<"accept-encoding">> => <<"gzip, deflate, br">>,<<"accept-language">> => <<"zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7">>,<<"connection">> => <<"keep-alive">>,<<"content-length">> => <<"0">>,<<"content-type">> => <<"text/plain;charset=UTF-8">>,<<"cookie">> => <<"remember_tenant_59ba36addc2b2f9401580f014c7f58ea4e30989d=eyJpdiI6IktEc3NyYW5QNlhjTmdtdXV5d0pHaHc9PSIsInZhbH...">>,...},...} in cowboy_handler:execute/2 line 371E1

If I write it this way, I won’t make mistakes

cowboy_handler:execute/2 line 37

handle(<<"POST">>, <<"/rtmpt/open/", ChunkNumber/binary>>, State, Req) ->
    lager:info("Request: open/~p.\n", [ChunkNumber]),
    SessionId = generate_session_id(),
    % {ok, _Pid} = rtmpt_client:start(SessionId),
    lager:info("Opened session ~p, timeout ~p.\n", [SessionId]),
    {ok, State, cowboy_req:reply(200
        , #{
            <<"Content-Type">> => ?RTMP_CONTENT_TYPE
            , <<"server">> => ?RTMP_SERVER
        }
        , iolist_to_binary([SessionId, "\n"])
        , Req)
    };

The cowboy handler expects a return value of the form {ok, Req, State} (see Nine Nines: Handlers). In the first post, you only return {ok, Req} and in your latest reply, you return {ok, State, Req}. Both are incorrect.

handle(<<"POST">>, <<"/rtmp/open/", ChunkNumber/binary>>, _State, Req) ->
    lager:info("Request: open/~p.\n", [ChunkNumber]),
    SessionId = generate_session_id(),
    % {ok, _Pid} = rtmpt_client:start(SessionId),
    lager:info("Opened session ~p, timeout ~p.\n", [SessionId]),
    {ok, NewReq} = cowboy_req:reply(200
        , #{
            <<"Content-Type">> => ?RTMP_CONTENT_TYPE
            , <<"server">> => ?RTMP_SERVER
        }
        , SessionId
        , Req),
   {ok, NewReq, State};
...

this would be fitting cowboy’s expectations in terms of returned values.

Thank you very much for your help !
It was careless of me not to notice this detail.