{"id":13391967,"url":"https://github.com/kbrw/exos","last_synced_at":"2025-04-03T03:11:25.521Z","repository":{"id":20809721,"uuid":"24095229","full_name":"kbrw/exos","owner":"kbrw","description":"Exos is a simple Port Wrapper : a GenServer which forwards cast and call to a linked Port.","archived":false,"fork":false,"pushed_at":"2021-10-29T09:55:29.000Z","size":19,"stargazers_count":78,"open_issues_count":0,"forks_count":7,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-24T08:42:20.995Z","etag":null,"topics":["clojure","elixir","nodejs","python"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kbrw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-09-16T10:26:57.000Z","updated_at":"2024-05-31T07:49:18.000Z","dependencies_parsed_at":"2022-09-14T06:31:46.571Z","dependency_job_id":null,"html_url":"https://github.com/kbrw/exos","commit_stats":null,"previous_names":["awetzel/exos"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbrw%2Fexos","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbrw%2Fexos/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbrw%2Fexos/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kbrw%2Fexos/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kbrw","download_url":"https://codeload.github.com/kbrw/exos/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246927839,"owners_count":20856198,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","elixir","nodejs","python"],"created_at":"2024-07-30T16:00:16.258Z","updated_at":"2025-04-03T03:11:25.501Z","avatar_url":"https://github.com/kbrw.png","language":"Elixir","funding_links":[],"categories":["Actors","Languages Integration"],"sub_categories":[],"readme":"Exos\n====\n\nExos is a simple Port Wrapper : a GenServer which forwards cast and call to a\nlinked Port. Requests and responses are converted using binary erlang term\nexternal representation.\n\nYou can use it to create a GenServer for Python, Clojure, NodeJS with :\n- [clojure-erlastic](http://github.com/awetzel/clojure-erlastic)\n- [python-erlastic](http://github.com/awetzel/python-erlastic)\n- [node-erlastic](http://github.com/kbrw/node_erlastic)\n\n## Launching a Clojure/Python/NodeJS GenServer and use it in Elixir ##\n\nUsage : `Exos.Proc.start_link` (see function documentation), then the resulting\nprocess is a GenServer where cast and call are binary encoded through stdio to\nthe underlying process. If the GenServer receive messages outside of a call, an\nanonymous function can be attached to be called on each message.\n\nSee `test/port_example.exs` for a reference implementation of a server that can\nbe launched in a port with `Exos.Proc`, and `test/exos_test.exs` for its use.\n`clojure/python/node_erlastic` projects can be used to launch a\njava/python/javascript GenServer.\n\nSee above an example of an account manager server developped in\npython/nodejs/clojure.\n\n```elixir\ndefmodule Account do\n  def cmd do\n    case Application.get_env(:account_impl) do\n      :python-\u003e \"venv/bin/python -u account.py\"\n      :node-\u003e \"node account.js\"\n      :clojure-\u003e \"java -cp 'target/*' clojure.main account.clj\"\n    end\n  end\n  def start_link(ini), do: Exos.Proc.start_link(cmd,ini,[cd: \"#{:code.priv_dir(:myproj)}/account\"],name: __MODULE__)\n  def add(v), do: GenServer.cast(__MODULE__,{:add,v})\n  def rem(v), do: GenServer.cast(__MODULE__,{:rem,v})\n  def get, do: GenServer.call(__MODULE__,:get,:infinity)\nend\n\ndefmodule MyProj.App do\n  use Application\n  def start(_,_), do: MyProj.App.Sup.start_link\n\n  defmodule Sup do\n    use Supervisor\n    def start_link, do: Supervisor.start_link(__MODULE__,[])\n    def init([]), do: supervise([\n      worker(Account,[0])\n    ], strategy: :one_for_one)\n  end\nend\n```\n\n\u003e vim mix.exs\n\n```elixir\ndef application do\n  [mod: { MyProj.App, [] }]\nend\n```\n\nFinally just implement your account server in any language as describe below,\nand use it as a standard GenServer.\n\n\u003e iex -S mix\n\n```elixir\nAccount.add(5)\nAccount.rem(1)\n4 == Account.get\n```\n\n## Account Server Implementation in clojure ##\n\n```bash\nmix new myproj\ncd myproj ; mkdir -p priv/account; cd priv/account\nvim project.clj\n```\n\n```clojure\n(defproject account \"0.0.1\" \n  :dependencies [[clojure-erlastic \"0.2.3\"]\n                 [org.clojure/core.match \"0.2.1\"]])\n```\n\n```bash\nlein uberjar\nvim account.clj\n```\n\n```clojure\n(require '[clojure-erlastic.core :refer [run-server]])\n(use '[clojure.core.match :only (match)])\n(run-server\n  (fn [term count] (match term\n    [:add n] [:noreply (+ count n)]\n    [:rem n] [:noreply (- count n)]\n    :get [:reply count count])))\n```\n\n## Account Server Implementation in Python \u003e3.4 ##\n\n```bash\nmix new myproj\ncd myproj ; mkdir -p priv/account; cd priv/account\necho \"git://github.com/awetzel/python-erlastic.git#egg=erlastic\" \u003e requirements.txt\npyvenv venv\n./venv/bin/pip install -r requirements.txt\nvim account.py\n```\n\n```python\nmailbox,port = port_connection()\naccount = next(mailbox) #first msg is initial state\nfor req in mailbox:\n  if req == \"get\": port.send(account)\n  else:\n    (op,amount) = req\n    account = (account+amount) if op==\"add\" else (account-amount)\n```\n\n## Account Server Implementation in NodeJS ##\n\n```bash\nmix new myproj\ncd myproj ; mkdir -p priv/account; cd priv/account\nnpm init\nnpm install node_erlastic --save\nvim account.js\n```\n\n```javascript\nrequire('node_erlastic').server(function(term,from,current_amount,done){\n  if (term == \"get\") return done(\"reply\",current_amount);\n  if (term[0] == \"add\") return done(\"noreply\",current_amount+term[1]);\n  if (term[0] == \"rem\") return done(\"noreply\",current_amount-term[1]);\n  throw new Error(\"unexpected request\")\n});\n```\n\n# CONTRIBUTING\n\nHi, and thank you for wanting to contribute.\nPlease refer to the centralized informations available at: https://github.com/kbrw#contributing\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkbrw%2Fexos","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkbrw%2Fexos","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkbrw%2Fexos/lists"}