Exos is a simple Port Wrapper : a GenServer which forwards cast and call to a
linked Port. Requests and responses are converted using binary erlang term
external representation.

You can use it to create a GenServer for Python, Clojure, NodeJS with :
- [clojure-erlastic](
- [python-erlastic](
- [node-erlastic](

## Launching a Clojure/Python/NodeJS GenServer and use it in Elixir ##

Usage : `Exos.Proc.start_link` (see function documentation), then the resulting
process is a GenServer where cast and call are binary encoded through stdio to
the underlying process. If the GenServer receive messages outside of a call, a
GenEvent can be attached to receive these messages as events.

See `test/port_example.exs` for a reference implementation of a server that can
be launched in a port with `Exos.Proc`, and `test/exos_test.exs` for its use.
`clojure/python/node_erlastic` projects can be used to launch a
java/python/javascript GenServer.

See above an example of an account manager server developped in

defmodule Account do
  def cmd do
    case Application.get_env(:account_impl) do
      :python-> "venv/bin/python -u"
      :node-> "node account.js"
      :clojure-> "java -cp 'target/*' clojure.main account.clj"
  def start_link(ini), do: Exos.Proc.start_link(cmd,ini,[cd: "#{:code.priv_dir(:myproj)}/account"],name: __MODULE__)
  def add(v), do: GenServer.cast(__MODULE__,{:add,v})
  def rem(v), do: GenServer.cast(__MODULE__,{:rem,v})
  def get, do:,:get,:infinity)

defmodule MyProj.App do
  use Application
  def start(_,_), do: MyProj.App.Sup.start_link

  defmodule Sup do
    use Supervisor
    def start_link, do: Supervisor.start_link(__MODULE__,[])
    def init([]), do: supervise([
    ], strategy: :one_for_one)

> vim mix.exs

def application do
  [mod: { MyProj.App, [] }]

Finally just implement your account server in any language as describe below,
and use it as a standard GenServer.

> iex -S mix

4 == Account.get

## Account Server Implementation in clojure ##

mix new myproj
cd myproj ; mkdir -p priv/account; cd priv/account
vim project.clj

(defproject account "0.0.1" 
  :dependencies [[clojure-erlastic "0.2.3"]
                 [org.clojure/core.match "0.2.1"]])

lein uberjar
vim account.clj

(require '[clojure-erlastic.core :refer [run-server]])
(use '[clojure.core.match :only (match)])
  (fn [term count] (match term
    [:add n] [:noreply (+ count n)]
    [:rem n] [:noreply (- count n)]
    :get [:reply count count])))

## Account Server Implementation in Python >3.4 ##

mix new myproj
cd myproj ; mkdir -p priv/account; cd priv/account
echo "git://" > requirements.txt
pyvenv venv
./venv/bin/pip install -r requirements.txt

mailbox,port = port_connection()
account = next(mailbox) #first msg is initial state
for req in mailbox:
  if req == "get": port.send(account)
    (op,amount) = req
    account = (account+amount) if op=="add" else (account-amount)

## Account Server Implementation in NodeJS ##

mix new myproj
cd myproj ; mkdir -p priv/account; cd priv/account
npm init
npm install node_erlastic --save
vim account.js

  if (term == "get") return done("reply",current_amount);
  if (term[0] == "add") return done("noreply",current_amount+term[1]);
  if (term[0] == "rem") return done("noreply",current_amount-term[1]);
  throw new Error("unexpected request")