tcp_client

A simple LFE TCP client connection manager


Keywords
erlang, tcp, beam, tcp-client, lfe, connection-manager
License
Apache-2.0

Documentation

tcp-client

A simple LFE TCP client connection manager

Build Status LFE Versions Erlang Versions Tag

Project Logo

About

This library provides a simple TCP client for use in non-critical BEAM applications such as command line tools and REPLs. That being said, it is intended to be used from OTP release apps (e.g., making use of configuration data in ./config/sys.config).

Exponential backoff for an unavailable TCP server is provided via Fred's Erlang backoff library.

Configuration

Update your application's sys.config to include the following:

[
 %% any other confit entries ...
 {'tcp-client', [
     {server, [
         %% where to connect the client
         {host, "localhost"},
         {port, 7099},
         {options, [
             %% gen_tcp options
             {tcp, [binary, {active, true}, {packet, 0}]},
             %% The M/F responseible for parsing the packet; Func is arity 2,
             %% taking the packet data as the first argument and a tuple of
             %% the reporter {Mod, Func} as the second argument. This M/F is
             %% called by `connect` when a TCP packet is received.
             {parser, {Mod, Func}},
             %% It is up to the parser to call this next M/F, but the reporter
             %% tuple is what gets passed to the paser M/F.
             {reporter, {Mod, Func}},
             %% Exponential backoff support with initial and max values
             {'init-backoff', 500}, % in ms
             {'max-backoff', 60000} % in ms
         ]}
     ]}
 ]}
].

You will need to update the M/Fs for both the paser and the reporter.

Usage

Start up the connection manager:

lfe> (application:start 'tcp-client)

Send a message that will wait for a response ("call"):

lfe> (tcp-client:call-msg data)

Send a message that will return immediately ("cast"):

lfe> (tcp-client:cast-msg data)

The undertone project uses this library with the following parser and reporter definitions:

(defun parse-response
  ((packet `#(,reporter-mod ,reporter-func))
   (let* ((raw-msgs (split-xt-packet packet))
          (msgs (maybe-one-msg raw-msgs)))
     (list-comp
       ((<- x raw-msgs))
       (apply reporter-mod reporter-func `(,x)))
     (log-debug "Parsed packet: ~p" `(,msgs))
     msgs)))

(defun report (data)
  (log-debug "Got data from TCP server: ~p" `(,data)))

(defun rcv-delim () #b(0))

(defun split-xt-packet (packet)
  (list-comp
    ((<- x (when (=/= x #b()))
         (binary:split packet (rcv-delim) '(global))))
    (xt.lang:->lfe x)))

(defun maybe-one-msg
  ((`(,msg . ()))
    msg)
   ((msgs)
    msgs))

Licence

Copyright © 2015, Carlos Andres Bolaños

Copyright © 2019, Andrea Leopardi

Copyright © 2020, Duncan McGreggor