Remove extraneous functions from GUI template and add arg handling

This commit is contained in:
Craig Everett 2019-12-27 21:11:32 +09:00
parent e05b4c61f5
commit 0cca3d300d
54 changed files with 68 additions and 760 deletions

View File

@ -1 +1 @@
0.5.2
0.5.4

View File

@ -1,296 +0,0 @@
%%% @doc
%%% *PROJECT NAME* Client Manager
%%%
%%% This is the "manager" part of the service->worker pattern.
%%% It keeps track of who is connected and can act as a router among the workers.
%%% Having this process allows us to abstract and customize service-level concepts
%%% (the high-level ideas we care about in terms of solving an external problem in the
%%% real world) and keep them separate from the lower-level details of supervision that
%%% OTP should take care of for us.
%%% @end
-module(*PREFIX*client_man).
-behavior(gen_server).
*AUTHOR*
*COPYRIGHT*
*LICENSE*
-export([listen/1, ignore/0]).
-export([enroll/0, echo/1]).
-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
code_change/3, terminate/2]).
%%% Type and Record Definitions
-record(s, {port_num = none :: none | inet:port_number(),
listener = none :: none | gen_tcp:socket(),
clients = [] :: [pid()]}).
-type state() :: #s{}.
%%% Service Interface
-spec listen(PortNum) -> Result
when PortNum :: inet:port_number(),
Result :: ok
| {error, Reason},
Reason :: {listening, inet:port_number()}.
%% @doc
%% Tell the service to start listening on a given port.
%% Only one port can be listened on at a time in the current implementation, so
%% an error is returned if the service is already listening.
listen(PortNum) ->
gen_server:call(?MODULE, {listen, PortNum}).
-spec ignore() -> ok.
%% @doc
%% Tell the service to stop listening.
%% It is not an error to call this function when the service is not listening.
ignore() ->
gen_server:cast(?MODULE, ignore).
%%% Client Process Interface
-spec enroll() -> ok.
%% @doc
%% Clients register here when they establish a connection.
%% Other processes can enroll as well.
enroll() ->
gen_server:cast(?MODULE, {enroll, self()}).
-spec echo(Message) -> ok
when Message :: string().
%% @doc
%% The function that tells the manager to broadcast a message to all clients.
%% This can broadcast arbitrary strings to clients from non-clients as well.
echo(Message) ->
gen_server:cast(?MODULE, {echo, Message, self()}).
%%% Startup Functions
-spec start_link() -> Result
when Result :: {ok, pid()}
| {error, Reason :: term()}.
%% @private
%% This should only ever be called by *PREFIX*clients (the service-level supervisor).
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, none, []).
-spec init(none) -> {ok, state()}.
%% @private
%% Called by the supervisor process to give the process a chance to perform any
%% preparatory work necessary for proper function.
init(none) ->
ok = io:format("Starting.~n"),
State = #s{},
{ok, State}.
%%% gen_server Message Handling Callbacks
-spec handle_call(Message, From, State) -> Result
when Message :: term(),
From :: {pid(), reference()},
State :: state(),
Result :: {reply, Response, NewState}
| {noreply, State},
Response :: ok
| {error, {listening, inet:port_number()}},
NewState :: state().
%% @private
%% The gen_server:handle_call/3 callback.
%% See: http://erlang.org/doc/man/gen_server.html#Module:handle_call-3
handle_call({listen, PortNum}, _, State) ->
{Response, NewState} = do_listen(PortNum, State),
{reply, Response, NewState};
handle_call(Unexpected, From, State) ->
ok = io:format("~p Unexpected call from ~tp: ~tp~n", [self(), From, Unexpected]),
{noreply, State}.
-spec handle_cast(Message, State) -> {noreply, NewState}
when Message :: term(),
State :: state(),
NewState :: state().
%% @private
%% The gen_server:handle_cast/2 callback.
%% See: http://erlang.org/doc/man/gen_server.html#Module:handle_cast-2
handle_cast({enroll, Pid}, State) ->
NewState = do_enroll(Pid, State),
{noreply, NewState};
handle_cast({echo, Message, Sender}, State) ->
ok = do_echo(Message, Sender, State),
{noreply, State};
handle_cast(ignore, State) ->
NewState = do_ignore(State),
{noreply, NewState};
handle_cast(Unexpected, State) ->
ok = io:format("~p Unexpected cast: ~tp~n", [self(), Unexpected]),
{noreply, State}.
-spec handle_info(Message, State) -> {noreply, NewState}
when Message :: term(),
State :: state(),
NewState :: state().
%% @private
%% The gen_server:handle_info/2 callback.
%% See: http://erlang.org/doc/man/gen_server.html#Module:handle_info-2
handle_info({'DOWN', Mon, process, Pid, Reason}, State) ->
NewState = handle_down(Mon, Pid, Reason, State),
{noreply, NewState};
handle_info(Unexpected, State) ->
ok = io:format("~p Unexpected info: ~tp~n", [self(), Unexpected]),
{noreply, State}.
%%% OTP Service Functions
-spec code_change(OldVersion, State, Extra) -> Result
when OldVersion :: {down, Version} | Version,
Version :: term(),
State :: state(),
Extra :: term(),
Result :: {ok, NewState}
| {error, Reason :: term()},
NewState :: state().
%% @private
%% The gen_server:code_change/3 callback.
%% See: http://erlang.org/doc/man/gen_server.html#Module:code_change-3
code_change(_, State, _) ->
{ok, State}.
-spec terminate(Reason, State) -> no_return()
when Reason :: normal
| shutdown
| {shutdown, term()}
| term(),
State :: state().
%% @private
%% The gen_server:terminate/2 callback.
%% See: http://erlang.org/doc/man/gen_server.html#Module:terminate-2
terminate(_, _) ->
ok.
%%% Doer Functions
-spec do_listen(PortNum, State) -> {Result, NewState}
when PortNum :: inet:port_number(),
State :: state(),
Result :: ok
| {error, Reason :: {listening, inet:port_number()}},
NewState :: state().
%% @private
%% The "doer" procedure called when a "listen" message is received.
do_listen(PortNum, State = #s{port_num = none}) ->
SocketOptions =
[inet6,
{active, once},
{mode, binary},
{keepalive, true},
{reuseaddr, true}],
{ok, Listener} = gen_tcp:listen(PortNum, SocketOptions),
{ok, _} = *PREFIX*client:start(Listener),
{ok, State#s{port_num = PortNum, listener = Listener}};
do_listen(_, State = #s{port_num = PortNum}) ->
ok = io:format("~p Already listening on ~p~n", [self(), PortNum]),
{{error, {listening, PortNum}}, State}.
-spec do_ignore(State) -> NewState
when State :: state(),
NewState :: state().
%% @private
%% The "doer" procedure called when an "ignore" message is received.
do_ignore(State = #s{listener = none}) ->
State;
do_ignore(State = #s{listener = Listener}) ->
ok = gen_tcp:close(Listener),
State#s{listener = none}.
-spec do_enroll(Pid, State) -> NewState
when Pid :: pid(),
State :: state(),
NewState :: state().
do_enroll(Pid, State = #s{clients = Clients}) ->
case lists:member(Pid, Clients) of
false ->
Mon = monitor(process, Pid),
ok = io:format("Monitoring ~tp @ ~tp~n", [Pid, Mon]),
State#s{clients = [Pid | Clients]};
true ->
State
end.
-spec do_echo(Message, Sender, State) -> ok
when Message :: string(),
Sender :: pid(),
State :: state().
%% @private
%% The "doer" procedure called when an "echo" message is received.
do_echo(Message, Sender, #s{clients = Clients}) ->
Send = fun(Client) -> Client ! {relay, Sender, Message} end,
lists:foreach(Send, Clients).
-spec handle_down(Mon, Pid, Reason, State) -> NewState
when Mon :: reference(),
Pid :: pid(),
Reason :: term(),
State :: state(),
NewState :: state().
%% @private
%% Deal with monitors. When a new process enrolls as a client a monitor is set and
%% the process is added to the client list. When the process terminates we receive
%% a 'DOWN' message from the monitor. More sophisticated work managers typically have
%% an "unenroll" function, but this echo service doesn't need one.
handle_down(Mon, Pid, Reason, State = #s{clients = Clients}) ->
case lists:member(Pid, Clients) of
true ->
NewClients = lists:delete(Pid, Clients),
State#s{clients = NewClients};
false ->
Unexpected = {'DOWN', Mon, process, Pid, Reason},
ok = io:format("~p Unexpected info: ~tp~n", [self(), Unexpected]),
State
end.

View File

@ -1,68 +0,0 @@
%%% @doc
%%% *PROJECT NAME* Client Supervisor
%%%
%%% This process supervises the client socket handlers themselves. It is a peer of the
%%% *PREFIX*client_man (the manager interface to this network service component), and a
%%% child of the supervisor named *PREFIX*clients.
%%%
%%% Because we don't know (or care) how many client connections the server may end up
%%% handling this is a simple_one_for_one supervisor which can spawn and manage as
%%% many identically defined workers as required, but cannot supervise any other types
%%% of processes (one of the tradeoffs of the "simple" in `simple_one_for_one').
%%%
%%% http://erlang.org/doc/design_principles/sup_princ.html#id79244
%%% @end
-module(*PREFIX*client_sup).
-behaviour(supervisor).
*AUTHOR*
*COPYRIGHT*
*LICENSE*
-export([start_acceptor/1]).
-export([start_link/0]).
-export([init/1]).
-spec start_acceptor(ListenSocket) -> Result
when ListenSocket :: gen_tcp:socket(),
Result :: {ok, pid()}
| {error, Reason},
Reason :: {already_started, pid()}
| {shutdown, term()}
| term().
%% @private
%% Spawns the first listener at the request of the *PREFIX*client_man when es:listen/1
%% is called, or the next listener at the request of the currently listening *PREFIX*client
%% when a connection is made.
%%
%% Error conditions, supervision strategies and other important issues are
%% explained in the supervisor module docs:
%% http://erlang.org/doc/man/supervisor.html
start_acceptor(ListenSocket) ->
supervisor:start_child(?MODULE, [ListenSocket]).
-spec start_link() -> {ok, pid()}.
%% @private
%% This supervisor's own start function.
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, none).
-spec init(none) -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}.
%% @private
%% The OTP init/1 function.
init(none) ->
RestartStrategy = {simple_one_for_one, 1, 60},
Client = {*PREFIX*client,
{*PREFIX*client, start_link, []},
temporary,
brutal_kill,
worker,
[*PREFIX*client]},
{ok, {RestartStrategy, [Client]}}.

View File

@ -1,203 +0,0 @@
%%% @doc
%%% *PROJECT NAME* Client
%%%
%%% An extremely naive (currently Telnet) client handler.
%%% Unlike other modules that represent discrete processes, this one does not adhere
%%% to any OTP behavior. It does, however, adhere to OTP.
%%%
%%% In some cases it is more comfortable to write socket handlers or a certain
%%% category of state machines as "pure" Erlang processes. This approach is made
%%% OTP-able by use of the proc_lib module, which is the underlying library used
%%% to write the stdlib's behaviors like gen_server, gen_statem, gen_fsm, etc.
%%%
%%% http://erlang.org/doc/design_principles/spec_proc.html
%%% @end
-module(*PREFIX*client).
*AUTHOR*
*COPYRIGHT*
*LICENSE*
-export([start/1]).
-export([start_link/1, init/2]).
-export([system_continue/3, system_terminate/4,
system_get_state/1, system_replace_state/2]).
%%% Type and Record Definitions
-record(s, {socket = none :: none | gen_tcp:socket()}).
%% An alias for the state record above. Aliasing state can smooth out annoyances
%% that can arise from using the record directly as its own type all over the code.
-type state() :: #s{}.
%%% Service Interface
-spec start(ListenSocket) -> Result
when ListenSocket :: gen_tcp:socket(),
Result :: {ok, pid()}
| {error, Reason},
Reason :: {already_started, pid()}
| {shutdown, term()}
| term().
%% @private
%% How the *PREFIX*client_man or a prior *PREFIX*client kicks things off.
%% This is called in the context of *PREFIX*client_man or the prior *PREFIX*client.
start(ListenSocket) ->
*PREFIX*client_sup:start_acceptor(ListenSocket).
-spec start_link(ListenSocket) -> Result
when ListenSocket :: gen_tcp:socket(),
Result :: {ok, pid()}
| {error, Reason},
Reason :: {already_started, pid()}
| {shutdown, term()}
| term().
%% @private
%% This is called by the *PREFIX*client_sup. While start/1 is called to iniate a startup
%% (essentially requesting a new worker be started by the supervisor), this is
%% actually called in the context of the supervisor.
start_link(ListenSocket) ->
proc_lib:start_link(?MODULE, init, [self(), ListenSocket]).
-spec init(Parent, ListenSocket) -> no_return()
when Parent :: pid(),
ListenSocket :: gen_tcp:socket().
%% @private
%% This is the first code executed in the context of the new worker itself.
%% This function does not have any return value, as the startup return is
%% passed back to the supervisor by calling proc_lib:init_ack/2.
%% We see the initial form of the typical arity-3 service loop form here in the
%% call to listen/3.
init(Parent, ListenSocket) ->
ok = io:format("~p Listening.~n", [self()]),
Debug = sys:debug_options([]),
ok = proc_lib:init_ack(Parent, {ok, self()}),
listen(Parent, Debug, ListenSocket).
-spec listen(Parent, Debug, ListenSocket) -> no_return()
when Parent :: pid(),
Debug :: [sys:dbg_opt()],
ListenSocket :: gen_tcp:socket().
%% @private
%% This function waits for a TCP connection. The owner of the socket is still
%% the *PREFIX*client_man (so it can still close it on a call to *PREFIX*client_man:ignore/0),
%% but the only one calling gen_tcp:accept/1 on it is this process. Closing the socket
%% is one way a manager process can gracefully unblock child workers that are blocking
%% on a network accept.
%%
%% Once it makes a TCP connection it will call start/1 to spawn its successor.
listen(Parent, Debug, ListenSocket) ->
case gen_tcp:accept(ListenSocket) of
{ok, Socket} ->
{ok, _} = start(ListenSocket),
{ok, Peer} = inet:peername(Socket),
ok = io:format("~p Connection accepted from: ~p~n", [self(), Peer]),
ok = *PREFIX*client_man:enroll(),
State = #s{socket = Socket},
loop(Parent, Debug, State);
{error, closed} ->
ok = io:format("~p Retiring: Listen socket closed.~n", [self()]),
exit(normal)
end.
-spec loop(Parent, Debug, State) -> no_return()
when Parent :: pid(),
Debug :: [sys:dbg_opt()],
State :: state().
%% @private
%% The service loop itself. This is the service state. The process blocks on receive
%% of Erlang messages, TCP segments being received themselves as Erlang messages.
loop(Parent, Debug, State = #s{socket = Socket}) ->
ok = inet:setopts(Socket, [{active, once}]),
receive
{tcp, Socket, <<"bye\r\n">>} ->
ok = io:format("~p Client saying goodbye. Bye!~n", [self()]),
ok = gen_tcp:send(Socket, "Bye!\r\n"),
ok = gen_tcp:shutdown(Socket, read_write),
exit(normal);
{tcp, Socket, Message} ->
ok = io:format("~p received: ~tp~n", [self(), Message]),
ok = *PREFIX*client_man:echo(Message),
loop(Parent, Debug, State);
{relay, Sender, Message} when Sender == self() ->
ok = gen_tcp:send(Socket, ["Message from YOU: ", Message]),
loop(Parent, Debug, State);
{relay, Sender, Message} ->
From = io_lib:format("Message from ~tp: ", [Sender]),
ok = gen_tcp:send(Socket, [From, Message]),
loop(Parent, Debug, State);
{tcp_closed, Socket} ->
ok = io:format("~p Socket closed, retiring.~n", [self()]),
exit(normal);
{system, From, Request} ->
sys:handle_system_msg(Request, From, Parent, ?MODULE, Debug, State);
Unexpected ->
ok = io:format("~p Unexpected message: ~tp", [self(), Unexpected]),
loop(Parent, Debug, State)
end.
-spec system_continue(Parent, Debug, State) -> no_return()
when Parent :: pid(),
Debug :: [sys:dbg_opt()],
State :: state().
%% @private
%% The function called by the OTP internal functions after a system message has been
%% handled. If the worker process has several possible states this is one place
%% resumption of a specific state can be specified and dispatched.
system_continue(Parent, Debug, State) ->
loop(Parent, Debug, State).
-spec system_terminate(Reason, Parent, Debug, State) -> no_return()
when Reason :: term(),
Parent :: pid(),
Debug :: [sys:dbg_opt()],
State :: state().
%% @private
%% Called by the OTP inner bits to allow the process to terminate gracefully.
%% Exactly when and if this is callback gets called is specified in the docs:
%% See: http://erlang.org/doc/design_principles/spec_proc.html#msg
system_terminate(Reason, _Parent, _Debug, _State) ->
exit(Reason).
-spec system_get_state(State) -> {ok, State}
when State :: state().
%% @private
%% This function allows the runtime (or anything else) to inspect the running state
%% of the worker process at any arbitrary time.
system_get_state(State) -> {ok, State}.
-spec system_replace_state(StateFun, State) -> {ok, NewState, State}
when StateFun :: fun(),
State :: state(),
NewState :: term().
%% @private
%% This function allows the system to update the process state in-place. This is most
%% useful for state transitions between code types, like when performing a hot update
%% (very cool, but sort of hard) or hot patching a running system (living on the edge!).
system_replace_state(StateFun, State) ->
{ok, StateFun(State), State}.

View File

@ -1,47 +0,0 @@
%%% @doc
%%% *PROJECT NAME* Client Service Supervisor
%%%
%%% This is the service-level supervisor of the system. It is the parent of both the
%%% client connection handlers and the client manager (which manages the client
%%% connection handlers). This is the child of *PREFIX*sup.
%%%
%%% See: http://erlang.org/doc/apps/kernel/application.html
%%% @end
-module(*PREFIX*clients).
-behavior(supervisor).
*AUTHOR*
*COPYRIGHT*
*LICENSE*
-export([start_link/0]).
-export([init/1]).
-spec start_link() -> {ok, pid()}.
%% @private
%% This supervisor's own start function.
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, none).
-spec init(none) -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}.
%% @private
%% The OTP init/1 function.
init(none) ->
RestartStrategy = {rest_for_one, 1, 60},
ClientSup = {*PREFIX*client_sup,
{*PREFIX*client_sup, start_link, []},
permanent,
5000,
supervisor,
[*PREFIX*client_sup]},
ClientMan = {*PREFIX*client_man,
{*PREFIX*client_man, start_link, []},
permanent,
5000,
worker,
[*PREFIX*client_man]},
Children = [ClientSup, ClientMan],
{ok, {RestartStrategy, Children}}.

View File

@ -1,43 +0,0 @@
%%% @doc
%%% *PROJECT NAME* Top-level Supervisor
%%%
%%% The very top level supervisor in the system. It only has one service branch: the
%%% client handling service. In a more complex system the client handling service would
%%% only be one part of a larger system. Were this a game system, for example, the
%%% item data management service would be a peer, as would a login credential provision
%%% service, game world event handling, and so on.
%%%
%%% See: http://erlang.org/doc/design_principles/applications.html
%%% See: http://zxq9.com/archives/1311
%%% @end
-module(*PREFIX*sup).
-behaviour(supervisor).
*LICENSE*
-export([start_link/0]).
-export([init/1]).
-spec start_link() -> {ok, pid()}.
%% @private
%% This supervisor's own start function.
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
-spec init([]) -> {ok, {supervisor:sup_flags(), [supervisor:child_spec()]}}.
%% @private
%% The OTP init/1 function.
init([]) ->
RestartStrategy = {one_for_one, 1, 60},
Clients = {*PREFIX*clients,
{*PREFIX*clients, start_link, []},
permanent,
5000,
supervisor,
[*PREFIX*clients]},
Children = [Clients],
{ok, {RestartStrategy, Children}}.

View File

@ -1,75 +0,0 @@
%%% @doc
%%% *PROJECT NAME*
%%% @end
-module(*APP MOD*).
-behavior(application).
*AUTHOR*
*COPYRIGHT*
*LICENSE*
-export([listen/1, ignore/0]).
-export([start/0, start/1]).
-export([start/2, stop/1]).
-spec listen(PortNum) -> Result
when PortNum :: inet:port_num(),
Result :: ok
| {error, {listening, inet:port_num()}}.
%% @doc
%% Make the server start listening on a port.
%% Returns an {error, Reason} tuple if it is already listening.
listen(PortNum) ->
*PREFIX*client_man:listen(PortNum).
-spec ignore() -> ok.
%% @doc
%% Make the server stop listening if it is, or continue to do nothing if it isn't.
ignore() ->
*PREFIX*client_man:ignore().
-spec start() -> ok.
%% @doc
%% Start the server in an "ignore" state.
start() ->
ok = application:ensure_started(sasl),
ok = application:start(example_server),
io:format("Starting es...").
-spec start(PortNum) -> ok
when PortNum :: inet:port_number().
%% @doc
%% Start the server and begin listening immediately. Slightly more convenient when
%% playing around in the shell.
start(PortNum) ->
ok = start(),
ok = *PREFIX*client_man:listen(PortNum),
io:format("Startup complete, listening on ~w~n", [PortNum]).
-spec start(normal, term()) -> {ok, pid()}.
%% @private
%% Called by OTP to kick things off. This is for the use of the "application" part of
%% OTP, not to be called by user code.
%% See: http://erlang.org/doc/apps/kernel/application.html
start(normal, _Args) ->
*PREFIX*sup:start_link().
-spec stop(term()) -> ok.
%% @private
%% Similar to start/2 above, this is to be called by the "application" part of OTP,
%% not client code. Causes a (hopefully graceful) shutdown of the application.
stop(_State) ->
ok.

View File

@ -1,6 +1,6 @@
{application,zx,
[{description,"An Erlang development tool and Zomp user client"},
{vsn,"0.5.2"},
{vsn,"0.5.4"},
{applications,[stdlib,kernel]},
{modules,[zx,zx_auth,zx_conn,zx_conn_sup,zx_daemon,zx_key,
zx_lib,zx_local,zx_net,zx_peer,zx_peer_man,

View File

@ -24,7 +24,7 @@
%%% @end
-module(zx).
-vsn("0.5.2").
-vsn("0.5.4").
-behavior(application).
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").

View File

@ -9,7 +9,7 @@
%%% @end
-module(zx_auth).
-vsn("0.5.2").
-vsn("0.5.4").
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").
-license("GPL-3.0").

View File

@ -7,7 +7,7 @@
%%% @end
-module(zx_conn).
-vsn("0.5.2").
-vsn("0.5.4").
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").
-license("GPL-3.0").

View File

@ -5,7 +5,7 @@
%%% @end
-module(zx_conn_sup).
-vsn("0.5.2").
-vsn("0.5.4").
-behavior(supervisor).
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").

View File

@ -138,7 +138,7 @@
%%% @end
-module(zx_daemon).
-vsn("0.5.2").
-vsn("0.5.4").
-behavior(gen_server).
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").

View File

@ -8,7 +8,7 @@
%%% @end
-module(zx_key).
-vsn("0.5.2").
-vsn("0.5.4").
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").
-license("GPL-3.0").

View File

@ -10,7 +10,7 @@
%%% @end
-module(zx_lib).
-vsn("0.5.2").
-vsn("0.5.4").
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").
-license("GPL-3.0").

View File

@ -6,7 +6,7 @@
%%% @end
-module(zx_local).
-vsn("0.5.2").
-vsn("0.5.4").
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").
-license("GPL-3.0").

View File

@ -5,7 +5,7 @@
%%% @end
-module(zx_net).
-vsn("0.5.2").
-vsn("0.5.4").
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").
-license("GPL-3.0").

View File

@ -8,7 +8,7 @@
%%% @end
-module(zx_peer).
-vsn("0.5.2").
-vsn("0.5.4").
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").
-license("GPL-3.0").

View File

@ -9,7 +9,7 @@
%%% @end
-module(zx_peer_man).
-vsn("0.5.2").
-vsn("0.5.4").
-behavior(gen_server).
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").

View File

@ -6,7 +6,7 @@
%%% @end
-module(zx_peer_sup).
-vsn("0.5.2").
-vsn("0.5.4").
-behaviour(supervisor).
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").

View File

@ -10,7 +10,7 @@
%%% @end
-module(zx_peers).
-vsn("0.5.2").
-vsn("0.5.4").
-behavior(supervisor).
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").

View File

@ -5,7 +5,7 @@
%%% @end
-module(zx_proxy).
-vsn("0.5.2").
-vsn("0.5.4").
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").
-license("GPL-3.0").

View File

@ -5,7 +5,7 @@
%%% @end
-module(zx_sup).
-vsn("0.5.2").
-vsn("0.5.4").
-behavior(supervisor).
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").

View File

@ -6,7 +6,7 @@
%%% @end
-module(zx_tty).
-vsn("0.5.2").
-vsn("0.5.4").
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").
-license("GPL-3.0").

View File

@ -5,7 +5,7 @@
%%% @end
-module(zx_userconf).
-vsn("0.5.2").
-vsn("0.5.4").
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").
-license("GPL-3.0").

View File

@ -7,7 +7,7 @@
%%% @end
-module(zx_zsp).
-vsn("0.5.2").
-vsn("0.5.4").
-author("Craig Everett <zxq9@zxq9.com>").
-copyright("Craig Everett <zxq9@zxq9.com>").
-license("GPL-3.0").

View File

@ -0,0 +1,39 @@
%%% @doc
%%% *PROJECT NAME*
%%% @end
-module(*APP MOD*).
-behavior(application).
*AUTHOR*
*COPYRIGHT*
*LICENSE*
-export([start/2, stop/1]).
-spec start(normal, Args :: term()) -> {ok, pid()}.
%% @private
%% Called by OTP to kick things off. This is for the use of the "application" part of
%% OTP, not to be called by user code.
%%
%% NOTE:
%% The commented out second argument would come from ebin/*APP MOD*.app's 'mod'
%% section, which is difficult to define dynamically so is not used by default
%% here (if you need this, you already know how to change it).
%%
%% Optional runtime arguments passed in at start time can be obtained by calling
%% zx_daemon:argv/0 anywhere in the body of the program.
%%
%% See: http://erlang.org/doc/apps/kernel/application.html
start(normal, _Args) ->
*PREFIX*sup:start_link().
-spec stop(term()) -> ok.
%% @private
%% Similar to start/2 above, this is to be called by the "application" part of OTP,
%% not client code. Causes a (hopefully graceful) shutdown of the application.
stop(_State) ->
ok.

View File

@ -58,8 +58,8 @@ init(none) ->
Window = *PREFIX*gui:start_link("Hello, WX!"),
ok = log(info, "Window: ~p", [Window]),
State = #s{window = Window},
String = "This is a text string.",
ok = *PREFIX*gui:show(String),
ArgV = zx_daemon:argv(),
ok = *PREFIX*gui:show(ArgV),
{ok, State}.

View File

@ -36,8 +36,8 @@
show(String) ->
wx_object:cast(?MODULE, {show, String}).
show(Terms) ->
wx_object:cast(?MODULE, {show, Terms}).
@ -87,8 +87,8 @@ handle_call(Unexpected, From, State) ->
%% The gen_server:handle_cast/2 callback.
%% See: http://erlang.org/doc/man/gen_server.html#Module:handle_cast-2
handle_cast({show, String}, State) ->
ok = do_show(String, State),
handle_cast({show, Terms}, State) ->
ok = do_show(Terms, State),
{noreply, State};
handle_cast(Unexpected, State) ->
ok = log(warning, "Unexpected cast: ~tp~n", [Unexpected]),
@ -136,5 +136,6 @@ terminate(Reason, State) ->
do_show(String, #s{text = TextC}) ->
do_show(Terms, #s{text = TextC}) ->
String = io_lib:format("Received args: ~tp", [Terms]),
wxTextCtrl:changeValue(TextC, String).

View File

@ -8,7 +8,7 @@
{license,"MIT"}.
{modules,[]}.
{name,"zx"}.
{package_id,{"otpr","zx",{0,5,2}}}.
{package_id,{"otpr","zx",{0,5,4}}}.
{prefix,"zx_"}.
{repo_url,"https://gitlab.com/zxq9/zx"}.
{tags,["tools","package manager","erlang"]}.