概要
paiza.ioでelixirやってみた。
練習問題、やってみた。
練習問題
rtmpのHandshakeを実装せよ。
参考にしたページ。
サンプルコード
defmodule ExRTMP.Handshake do
defstruct [:stage, :buf, :complete, :time, :client_time]
def new do
%__MODULE__{stage: :c0, buf: <<>>, complete: false, time: elem(:erlang.timestamp(), 0)}
end
def buffer(%__MODULE__{buf: buf} = handshake, new_buf) do
%{handshake | buf: buf <> new_buf}
end
def send_c0(socket) do
:gen_tcp.send(socket, <<0x03>>)
end
def send_c1(socket) do
time = :erlang.timestamp()
|> elem(0)
|> Integer.to_string()
zeros = <<0::8*4>>
msg = time <> zeros <> rand()
:gen_tcp.send(socket, msg)
end
def send_c2(socket, time) do
time2 = :erlang.timestamp()
|> elem(0)
msg = <<time::size(32), time2::size(32)>> <> rand()
:gen_tcp.send(socket, msg)
end
def send_s0(socket) do
:gen_tcp.send(socket, <<0x03>>)
end
def send_s1(socket, time) do
zeros = <<0::8*4>>
msg = <<time::size(32)>> <> zeros <> rand()
:gen_tcp.send(socket, msg)
end
def send_s2(socket, time, client_time) do
msg = <<time::size(32), client_time::size(32)>> <> rand()
:gen_tcp.send(socket, msg)
end
def rand do
fn ->
Enum.random('abcdefghijklmnopqrstuvwxyz0123456789')
end
|> Stream.repeatedly()
|> Enum.take(1528)
|> to_string
end
def parse(%__MODULE__{buf: msg} = handshake) do
case msg do
<<0x03::size(8), rest::binary>> ->
%{handshake | buf: rest, stage: :c1}
<<time::unsigned-size(32), 0::unsigned-size(32), _garbage::binary-size(1528)>> ->
%{handshake | buf: <<>>, stage: :c2}
<<time::unsigned-size(32), time2::unsigned-size(32), _garbage::binary-size(1528), rest::binary>> ->
%{handshake | buf: <<>>, stage: :c2, complete: true, client_time: time}
_ ->
{:invalid, msg}
end
end
def parse(msg) do
case msg do
<<0x03::size(8), rest::binary>> ->
{:s0, rest}
<<time::size(32), 0::size(32), _garbage::size(1528), rest::binary>> ->
{:s1, time, rest}
<<_time::size(32), _time2::size(32), _garbage::binary-size(1528), rest::binary>> ->
{:s2, rest}
_ ->
{:invalid, msg}
end
end
end
ExRTMP.Handshake.new
{:ok, socket} = :gen_tcp.connect('media3.scctv.net', 1935, [:binary, active: false])
|> IO.inspect
ExRTMP.Handshake.send_c0(socket)
|> IO.inspect
ExRTMP.Handshake.send_c1(socket)
|> IO.inspect
{:ok, data} = :gen_tcp.recv(socket, 0)
ExRTMP.Handshake.parse(data)
|> IO.inspect
{:ok, data} = :gen_tcp.recv(socket, 0)
ExRTMP.Handshake.parse(data)
|> IO.inspect
time = elem(:erlang.timestamp(), 0)
ExRTMP.Handshake.send_c2(socket, time)
|> IO.inspect
{:ok, data} = :gen_tcp.recv(socket, 0)
ExRTMP.Handshake.parse(data)
|> IO.inspect
実行結果
{:ok, #Port<0.6>}
:ok
:ok
{:s0,
<<5, 197, 208, 132, 3, 0, 1, 1, 66, 70, 91, 180, 233, 116, 43, 101, 50, 254,
30, 74, 200, 126, 175, 19, 151, 63, 64, 62, 97, 183, 90, 188, 22, 228, 21,
177, 219, 137, 238, 59, 246, 128, 209, 17, 46, 207, 7, 116, ...>>}
{:invalid,
<<147, 150, 12, 203, 30, 12, 99, 200, 251, 233, 51, 30, 57, 246, 111, 168, 234,
17, 176, 65, 144, 137, 124, 63, 103, 11, 13, 211, 255, 190, 245, 239, 92, 75,
204, 7, 193, 171, 150, 36, 126, 198, 15, 86, 17, 7, 215, 141, ...>>}
:ok
{:invalid,
"lj4gtcxizs4rddejegb6ugx4betyz29lynpazi0tfvnz3214pky8livtgavdderm024lqp3fe6xdp5k61v9wod9pkdylipf9yilvos6hx3vtxtzqlsp6is8kzg1zayv4efaw33o9uupgitfsy0zu1zcy4"}
成果物
以上。