aboutsummaryrefslogtreecommitdiff
path: root/src/xdg_pipe_menu_cli.erl
blob: aa2f98a09a8ba9ff6d9af8df7b6233c890954423 (plain)
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
%%%-------------------------------------------------------------------
%% @doc Entry point invoked by Openbox as the pipe menu command.
%%
%% Tries the running daemon's Unix socket first for an instant,
%% pre-rendered response; if the daemon isn't reachable, falls back to
%% scanning, parsing and rendering inline so the menu still works.
%% @end
%%%-------------------------------------------------------------------

-module(xdg_pipe_menu_cli).

-export([main/1]).

-define(CONNECT_TIMEOUT_MS, 200).
-define(RECV_TIMEOUT_MS, 1000).

main(_Args) ->
    Menu =
        case from_daemon() of
            {ok, Bin} -> Bin;
            error -> xdg_pipe_menu_cache:build(xdg_pipe_menu_scanner:data_dirs())
        end,
    io:put_chars(Menu).

from_daemon() ->
    Path = xdg_pipe_menu_socket:socket_path(),
    case gen_tcp:connect({local, Path}, 0, [binary, {active, false}], ?CONNECT_TIMEOUT_MS) of
        {ok, Socket} ->
            Result = recv_all(Socket, []),
            gen_tcp:close(Socket),
            Result;
        {error, _Reason} ->
            error
    end.

recv_all(Socket, Acc) ->
    case gen_tcp:recv(Socket, 0, ?RECV_TIMEOUT_MS) of
        {ok, Data} -> recv_all(Socket, [Data | Acc]);
        {error, closed} -> {ok, iolist_to_binary(lists:reverse(Acc))};
        {error, _Reason} -> error
    end.