A general purposed, cross-protocol and cross-serialization RPC framework, designed for easiness, simpleness and performance.
Add this to your application's shard.yml
:
dependencies:
bridge:
github: xqyww123/bridge.cr
Define API and the Protocol to communicate.
require "bridge"
# Msgpack is the default serialization protocol
require "msgpack"
# APIs are defined as the rubyist way.
class Dog
include Bridge::Host
def initialize(@name)
end
api getter name : String
end
class Zoo
include Bridge::Host
directory getter dog : Dog
# A directory is a getter or any method returns Host.
# It maps path "path/to/api" to interface `path.to.api`.
# Currently path with arguments like "book/:id/get" isn't supported, but it's on the plan.
def initialize(@dog)
end
GENDER = {"male" => "gentle", "female" => "lady"}
api def welcome(guest : String, gender : String)
"Welcome #{GENDER[gender]?} #{guest}!"
end
end
# Create the instance of Host and start the server.
dog = Dog.new "Donald"
zoo = Zoo.new dog
server = Bridge::Driver::UnixSocket.new zoo, "/tmp/socks_folder"
server.listen
exit if gets
UnixServer
listens on following files under Msgpack protocol by default.
/tmp/socks_folder/welcome
/tmp/socks_folder/dog/name
Then, call the API in other programs and other languages. Illustrate using Ruby:
require 'msgpack'
require 'socket'
s = UNIXSocket.new("/tmp/socks_folder/welcome")
["Ruby", "female"].to_msgpack s; s.flush
u = MessagePack::Unpacker.new s
puts u.unpack
["Ruby, and the channel is usable", "female"].to_msgpack s; s.flush
puts u.unpack
s2 = UNIXSocket.new("/tmp/socks_folder/dog/name")
# the way to call a method without arguments is just to send nil.
nil.to_msgpack s2; s2.flush
u2 = MessagePack::Unpacker.new s2
puts "Name of the dog is #{u2.unpack}"
You can run the code on your computer. They locate in spec/example/simple.cr & spec/example/simple.rb.
Bridge consists two parts : Host
& Driver
.
Host
maintains two constants Interfaces
and InterfaceProcs
. It also provides class methods interfaces
and interface_procs
to acquire those two constants.
Macro API
accepts a method definition or many other forms, see an example with more detail. API
wraps the method with a new one having the api_
prefix, and register information into Interfaces
& InterfaceProc
.
The wrapper has form def api_APINAME(connection : IO) : Nil
, and it reads arguments from IO and serializes responses back into IO. See Serialization for more details. For example, api def xxx
will generate a method api_xxx(connection : IO)
calling xxx
.
Interfaces
is a Hash(String, Array(Symbol))
mapping interface path to calling chain. For example, calling chain of interface "path/to/api_xxx" is exactly [:path, :to, :api_xxx]
.
InterfaceProcs
is a Hash(String, Proc(InterfaceArgument(Host), Nil))
mapping interface path to a Proc calling the wrapper following the calling chain.
Struct InterfaceArgument
only have two fields currently: obj : Host
and connection : IO
.
For example, the Proc of "path/to/api_xxx" is (InterfaceArgument(Host), Nil)->{|arg| arg.obj.path.to.api_xxx arg.connection }
.
According to those two constants of any given Host, Driver listens and waits for requests, manages connections, figures out which interface to call, and triggers the call finally.
Different Driver could be implemented on different protocols or framework.
Like UnixSocket
binds sockets for each interface following the directory structure, or all in one socket with multiplex depending on configure.
In this example, the UnixSocket
listens on following sockets:
/tmp/socks_folder/welcome
/tmp/socks_folder/dog/name
By default, UnixSocket
opens as many sockets as interfaces following the directory structure, because of lacking a standard way for the multiplex.
Currently, the only default behaviour of UnixSocket
implemented but any other Drivers.
Contributions are highly welcome, especially on Drivers.
- Fork it (https://github.com/xqyww123/bridge/fork)
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request
- xqyww123 Shirotsu Essential - creator, maintainer