forked from DOBRO/binbo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
binbo_uci_connection.erl
100 lines (87 loc) · 3.35 KB
/
binbo_uci_connection.erl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
%% Copyright (c) 2019-2022, Sergei Semichev <chessvegas@chessvegas.com>. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
-module(binbo_uci_connection).
-export([connect/1, disconnect/1]).
-export([send_command/2]).
%%%------------------------------------------------------------------------------
%%% Types
%%%------------------------------------------------------------------------------
-type tcp_host() :: inet:socket_address() | inet:hostname().
-type tcp_port() :: inet:port_number().
-type tcp_socket() :: inet:socket().
-type engine_path() :: binary() | string() | {tcp_host(), tcp_port(), timeout()}.
-type socket_info() :: {erlang, port()} | {gen_tcp, tcp_socket()}.
-export_type([tcp_host/0, tcp_port/0]).
-export_type([engine_path/0]).
-export_type([socket_info/0]).
%%%------------------------------------------------------------------------------
%%% API
%%%------------------------------------------------------------------------------
%% connect/1
-spec connect(binary() | string())
-> {ok, {erlang, port()}} | {error, any()}
;({tcp_host(), tcp_port(), timeout()})
-> {ok, {gen_tcp, tcp_socket()}} | {error, timeout | inet:posix()}.
connect(EnginePath) when is_list(EnginePath) orelse is_binary(EnginePath) ->
try erlang:open_port({spawn_executable, EnginePath}, [binary, stream]) of
Port -> {ok, {erlang, Port}}
catch
_:Reason -> {error, Reason}
end;
connect({Host, Port, Timeout}) ->
Opts = [binary, {active, true}, {packet, raw}],
case gen_tcp:connect(Host, Port, Opts, Timeout) of
{ok, Socket} ->
{ok, {gen_tcp, Socket}};
{error, Reason} ->
{error, Reason}
end.
%% disconnect/1
-spec disconnect(socket_info() | undefined) -> ok.
disconnect({erlang, Port} = SocketInfo) ->
_ = case erlang:port_info(Port, id) of
undefined ->
undefined;
_ ->
try
_ = send_command(SocketInfo, "quit"),
erlang:port_close(Port)
catch
_:_ -> ok % we don't care
end
end,
ok;
disconnect({gen_tcp, Socket} = SocketInfo) ->
_ = send_command(SocketInfo, "quit"),
_ = gen_tcp:close(Socket),
ok;
disconnect(undefined) ->
ok.
%% send_command/2
-spec send_command(socket_info(), iodata()) -> ok.
send_command(SocketInfo, Command) ->
send(SocketInfo, [Command, $\n]).
%%%------------------------------------------------------------------------------
%%% Internal functions
%%%------------------------------------------------------------------------------
%% send/2
-spec send(socket_info(), iodata()) -> ok.
send(SocketInfo, IoData) ->
_ = case SocketInfo of
{erlang, Port} ->
erlang:port_command(Port, IoData);
{gen_tcp, Socket} ->
gen_tcp:send(Socket, IoData)
end,
ok.