Giter VIP home page Giter VIP logo

bertgate's Introduction

BertGate

Kind-of-compatible BERT-rpc server and client for Elixir.

See http://bert-rpc.org/

Features

  1. it's secure: only functions in special modules can be called
  2. it's secure: authentication for accessing particular modules
  3. it isn't secure: you can still be DDOSed by excessive atom creation
  4. (kind of) BERT-rpc compatible
  5. Elixir exceptions are transparently transported to the client and raised here
  6. cast and call implemented
  7. info not implemented (-> no control signals, caching etc.)

Installation

For testing:

# git clone https://github.com/mprymek/bertgate
# cd bertgate
# mix do deps.get, compile

For mix.exs:

{ :bertgate, github: "mprymek/bertgate" }

Test

Start server:

# mix server
Erlang/OTP 17 [erts-6.0] [source] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]

[NOTIC] BertGate server listening on port 9484 with 20 acceptors
[NOTIC] Public modules: [:Bert]

Test connection to the server:

# iex -S mix client
Erlang/OTP 17 [erts-6.0] [source] [64-bit] [smp:2:2] [async-threads:10] [hipe] [kernel-poll:false]

Interactive Elixir (0.14.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> conn=BertGate.Client.connect("localhost")
#Port<0.1268>
iex(2)> BertGate.Client.call(conn,:'Bert',:ping,[])
:pong

Or you can run unit tests:

# mix test

Usage

  1. define your functions in BertGate.Modules.YourModule, BertGate.Modules.OtherModule, ...
  2. if you want private modules, define custom authenticator. If not, list your modules in "public" option (see below)

Example user modules:

defmodule BertGate.Modules.CalcPublic do
  def sum(_auth_data,x,y), do: x+y
end

defmodule BertGate.Modules.CalcPrivate do
  def sum(_auth_data,x,y), do: {:really_confident_result,x+y}
end

Authenticator receives authentication token (arbitrary Erlang term) and returns nil (failed authentication) or new list of user-accessible modules and arbitrary auth_data. auth_data is then passed as a first argument to every remotely invocated function. You can store any user-related data to it, BertGate doesn't use it, just passes is from authenticator to your functions.

How to start server:

# authenticator(old_allowed,old_auth_data,token) -> {new_allowed,auth_data}
authenticator = fn
   _,_,:calc_auth_token -> {[:'CalcPrivate'],:some_auth_data}
   _,_,_ -> nil
end
{:ok, server} = BertGate.Server.start_link(%{
   port: your_custom_port,          # optional 
   authenticator: authenticator,    # only needed if you want authenticated modules
   public: [:'Bert',:'CalcPublic'], # public modules
})

You can call your functions from client like this:

iex(1)> conn=BertGate.Client.connect("localhost")
#Port<0.3540>
iex(2)> BertGate.Client.call(conn,:'CalcPublic',:sum,[5,6])
11
iex(3)> BertGate.Client.auth(conn,:calc_auth_token)
:ok
iex(4)> BertGate.Client.call(conn,:'CalcPrivate',:sum,[5,6])
{:really_confident_result,11}

Connection Manager

Manages connections to :rpc and BertGate servers. Whenever network error occur, the client is automatically reconnected using stored options.

Server:

# iex --sname server -S mix server
[...]
iex(server@mydomain)1> BertGate.Server.start_link
[NOTIC] BertGate server listening on port 9484 with 20 acceptors

Client:

# iex --sname client -S mix client
[...]
iex(client@mydomain)1> Rpc.add_bert_server :local_bert, "localhost"
:ok
iex(client@mydomain)2> Rpc.call :local_bert, :'Bert', :ping
:pong
iex(client@mydomain)3> Rpc.add_rpc_node :local_rpc, :server@mydomain
:ok
iex(client@mydomain)4> Rpc.call :local_rpc, BertGate.Modules.Bert, :ping, [nil]
:pong

Authenticated connections:

iex(client@mydomain)2> Rpc.add_bert_server :calc_private, "localhost", %{auth: :calc_auth_token}
:ok
iex(client@mydomain)2> Rpc.call :calc_private, :'CalcPrivate', :sum, [5,6]
11

Python Interoperability

# easy_install bertrpc
# python
[...]
>>> import bertrpc
>>> service = bertrpc.Service('localhost', 9484)
>>> service.request('call').Bert.ping()
Atom('pong')
>>> service.request('call').Bert.some_integer()
1234
>>> service.request('call').Bert.some_float()
1.234
>>> service.request('call').Bert.some_atom()
Atom('this_is_atom')
>>> service.request('call').Bert.some_tuple()
(1, 2, 3, 4)
>>> service.request('call').Bert.some_bytelist()
[1, 2, 3, 4]
>>> service.request('call').Bert.some_list()
[1, 2, [3, 4]]
>>> service.request('call').Bert.some_binary()
'This is a binary'
>>> service.request('call').Bert.some_map()
{Atom('a'): 1, Atom('b'): 2}
>>> service.request('call').Bert.sum(1,6)
7

Async call:

>>> service.request('cast').Bert.ping()

Authentication:

>>> service.request('call').Auth.auth("secret")
Atom('ok')

Exceptions raised by user functions (server side) are also somehow supported on python side. You can distinguish them by code 601.

>>> service.request('call').Bert.exception1()
Traceback (most recent call last):
[...]
bertrpc.error.UserError: Class: Elixir.RuntimeError
Code: 601
UserError: [{Atom('__struct__'): Atom('Elixir.RuntimeError'), Atom('__exception__'): True, Atom('message'): 'Test exception'}]

Performance

BertGate's performance is similar to the erlang :rpc module:

# elixir --sname server -S mix server
# elixir --sname client -S mix SpeedTest server@yourdomain
**** BertGate
Range: 125 - 25341 us
Median: 162 us
Average: 209 us

**** :rpc
Range: 137 - 35067 us
Median: 177 us
Average: 219 us

bertgate's People

Contributors

mprymek avatar

Watchers

Tyr Chen avatar James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.