Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
awetzel committed Sep 16, 2014
0 parents commit 8f59e92
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 0 deletions.
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/_build
/deps
*.errlog
erl_crash.dump
*.ez
*_data
*.config
*.swp
.DS_Store
.idea
*gz
*nugs

83 changes: 83 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
Exos
====

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 [clojure-erlastic](http://github.com/awetzel/clojure-erlastic),
[python-erlastic](http://github.com/awetzel/python-erlastic), etc.

## Exemple usage : a clojure calculator ##

Using [clojure-erlastic](http://github.com/awetzel/clojure-erlastic), your can easily create
a port and communicate with it.

> mix new myproj
> cd myproj ; mkdir -p priv/calculator
> vim project.clj
```clojure
(defproject calculator "0.0.1"
:dependencies [[clojure-erlastic "0.2.3"]
[org.clojure/core.match "0.2.1"]])
```

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

Then in your project, you can use Exos.Proc GenServer as a proxy to the clojure
port.

```elixir
defmodule Calculator do
def start_link(ini), do: GenServer.start_link(Exos.Proc,{"#{:code.priv_dir(:myproj)}/calculator","java -cp 'target/*' clojure.main calculator.clj",ini},name: __MODULE__)
def add(v), do: GenServer.cast(__MODULE__,{:add,v})
def rem(v), do: GenServer.cast(__MODULE__,{:rem,v})
def get, do: GenServer.call(__MODULE__,:get,:infinity)
end

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([
worker(Calculator,0)
], strategy: :one_for_one)
end
end
```

> vim mix.exs
```elixir
def application do
[mod: { MyProj.App, [] }]
end
```

Then you can use the calculator

> iex -S mix
```elixir
Calculator.add(5)
Calculator.rem(1)
4 == Calculator.get
```
24 changes: 24 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# This file is responsible for configuring your application
# and its dependencies with the aid of the Mix.Config module.
use Mix.Config

# This configuration is loaded before any dependency and is restricted
# to this project. If another project depends on this project, this
# file won't be loaded nor affect the parent project. For this reason,
# if you want to provide default values for your application for third-
# party users, it should be done in your mix.exs file.

# Sample configuration:
#
# config :logger, :console,
# level: :info,
# format: "$date $time [$level] $metadata$message\n",
# metadata: [:user_id]

# It is also possible to import configuration files, relative to this
# directory. For example, you can emulate configuration per environment
# by uncommenting the line below and defining dev.exs, test.exs and such.
# Configuration from the imported file will override the ones defined
# here (which is why it is important to import them last).
#
# import_config "#{Mix.env}.exs"
24 changes: 24 additions & 0 deletions lib/exos.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
defmodule Exos.Proc do
use GenServer

def init({cd,cmd,initarg}) do
port = Port.open({:spawn,'#{cmd}'}, [:binary,:exit_status, packet: 4, cd: '#{cd}'])
send(port,{self,{:command,:erlang.term_to_binary(initarg)}})
{:ok,port}
end

def handle_info({port,{:exit_status,0}},port), do: {:stop,:normal,port}
def handle_info({port,{:exit_status,_}},port), do: {:stop,:port_terminated,port}
def handle_info(_,port), do: {:noreply,port}

def handle_cast(term,port) do
send(port,{self,{:command,:erlang.term_to_binary(term)}})
{:noreply,port}
end

def handle_call(term,_,port) do
send(port,{self,{:command,:erlang.term_to_binary(term)}})
result = receive do {^port,{:data,b}}->:erlang.binary_to_term(b) end
{:reply,result,port}
end
end
14 changes: 14 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
defmodule Exos.Mixfile do
use Mix.Project

def project do
[app: :exos,
version: "0.0.1",
elixir: "~> 1.0.0",
deps: []]
end

def application do
[applications: [:logger]]
end
end
7 changes: 7 additions & 0 deletions test/exos_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
defmodule ExosTest do
use ExUnit.Case

test "the truth" do
assert 1 + 1 == 2
end
end
1 change: 1 addition & 0 deletions test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ExUnit.start()

0 comments on commit 8f59e92

Please sign in to comment.