Compare commits

..

26 Commits
master ... poll

Author SHA1 Message Date
Karchnu b5d8c5a6b1 blah 2020-07-13 14:16:25 +02:00
Karchnu df269e4423 fixed segfault 2020-07-11 10:46:17 +02:00
Karchnu 46cad71e4b fixes 2020-07-10 14:58:41 +02:00
Karchnu b4bdc44897 fixing ipc_ctx_fd_type 2020-07-09 09:33:34 +02:00
Karchnu 4c47461ac9 fixing ctx structure 2020-07-09 01:46:22 +02:00
Karchnu 91fd87ae5d fixing 2020-07-08 19:35:28 +02:00
Karchnu f0055cfdef fixing context 2020-07-08 19:34:31 +02:00
Karchnu bc11af9ac5 fixing 2020-07-08 19:31:29 +02:00
Karchnu 66f1b45de1 lowlevel switching cb 2020-07-08 18:57:08 +02:00
Karchnu 50107123ea adding switch functions 2020-07-08 16:49:09 +02:00
Karchnu 58ec731530 s/events_loop/wait_event/ 2020-07-06 08:40:56 +02:00
Karchnu 8935db7126 libipc version 2020-07-03 22:56:31 +02:00
Karchnu 70a102dbd7 things 2020-07-03 22:44:34 +02:00
Karchnu 77026a249a timer 2020-07-03 22:41:07 +02:00
Karchnu 6b47af9e9f improvments 2020-07-03 19:11:10 +02:00
Karchnu fd62919770 Timer is just crazy. 2020-07-03 16:23:52 +02:00
Karchnu 57ce9d2e38 compiles 2020-07-03 16:14:46 +02:00
Karchnu 12f397ed2b E_TOOMUCHCODEDELETE 2020-07-03 15:40:30 +02:00
Karchnu 6b1426f10b connection type 2020-07-03 13:48:39 +02:00
Karchnu 158cc47897 Context 2020-07-03 13:42:19 +02:00
Karchnu ffcb734bfd Int => Int32 2020-07-02 22:36:51 +02:00
Karchnu 0f2b8e1009 Connections => Ctx 2020-07-02 22:30:40 +02:00
Karchnu 7afd12e242 UInt64T 2020-07-02 22:29:35 +02:00
Karchnu 7b963433b9 blah 2020-07-02 21:48:17 +02:00
Karchnu ac7bb07d95 High level API: first take. 2020-07-02 21:13:54 +02:00
Karchnu 6f5aa676b5 Low-level changes for poll(2) version of the LibIPC. 2020-07-01 16:24:13 +02:00
17 changed files with 58 additions and 700 deletions

View File

@ -1,5 +1,5 @@
name: ipc
version: 0.7.0
version: 0.6.0
authors:
- Philippe Pittoli <karchnu@karchnu.fr>
@ -8,18 +8,7 @@ authors:
description: |
High-level Crystal bindings to libipc.
dependencies:
cbor:
branch: master
git: https://git.baguette.netlib.re/Baguette/crystal-cbor
targets:
pongd:
main: tests/pongd.cr
pongc:
main: tests/pongc.cr
libraries:
libipc: ">= 0.7"
libipc: ">= 0.6"
license: ISC

View File

@ -1,58 +0,0 @@
require "cbor"
require "./ipc.cr"
class IPC::CBOR
include ::CBOR::Serializable
#@[::CBOR::Field(ignored: true)]
#getter type = -1
class_getter type = -1
property id : ::CBOR::Any?
def type
@@type
end
macro message(id, type, &block)
class {{id}} < ::IPC::CBOR
include ::CBOR::Serializable
@@type = {{type}}
{{yield}}
end
end
end
class IPC::Context
def send(fd : Int32, message : IPC::CBOR)
send fd, message.type.to_u8, message.to_cbor
end
def send_now(fd : Int32, message : IPC::CBOR)
send_now fd, message.type.to_u8, message.to_cbor
end
end
class IPC::Client
def send(message : IPC::CBOR)
send @server_fd.not_nil!, message.type.to_u8, message.to_cbor
end
def send_now(message : IPC::CBOR)
send_now @server_fd.not_nil!, message.type.to_u8, message.to_cbor
end
end
# CAUTION: Only use this method on an Array(IPC::CBOR.class)
class Array(T)
def parse_ipc_cbor(message : IPC::Message) : IPC::CBOR?
message_type = find &.type.==(message.utype)
if message_type.nil?
raise "invalid message type (#{message.utype})"
end
message_type.from_cbor message.payload
end
end

View File

@ -1,39 +1,15 @@
class IPC::Client < IPC::Context
property server_fd : Int32?
# By default, this is a client.
def initialize(service_name : String)
super()
serverfd = 0
r = LibIPC.ipc_connection(self.pointer, service_name, pointerof(serverfd))
r = LibIPC.ipc_connection(self.pointer, service_name)
if r.error_code != 0
m = String.new r.error_message.to_slice
raise Exception.new "error during connection establishment: #{m}"
end
@server_fd = serverfd
# Very important as there are filesystem side-effects.
at_exit { close }
end
def fd
@server_fd
end
def read
unless (fd = @server_fd).nil?
message = LibIPC::Message.new
r = LibIPC.ipc_read_fd(fd, pointerof(message))
if r.error_code != 0
m = String.new r.error_message.to_slice
raise Exception.new "error reading a message: #{m}"
end
IPC::Message.new pointerof(message)
else
raise "Client not connected to a server"
end
end
end

View File

@ -1,15 +1,9 @@
class IPC::Context
# TODO: FIXME: base timer default is 30 seconds, INFTIM was causing trouble.
property base_timer : Int32 = 30_000 # LibIPC::INFTIM
property timer : Int32 = 30_000 # LibIPC::INFTIM
property base_timer : Int32 = LibIPC::INFTIM
property timer : Int32 = LibIPC::INFTIM
getter context : LibIPC::Ctx
# On message reception, the message is contained into the event structure.
# This message is automatically deallocated on the next ipc_wait_event call.
# Therefore, we must keep this structure.
property event = LibIPC::Event.new
def initialize
@context = LibIPC::Ctx.new
end
@ -46,57 +40,46 @@ class IPC::Context
end
end
def wait_event : IPC::Event::Events | Exception
r = LibIPC.ipc_wait_event self.pointer, pointerof(@event), pointerof(@timer)
event_type = @event.type.unsafe_as(LibIPC::EventType)
def wait_event(&block) : IPC::Event::Events | Exception
event = LibIPC::Event.new
r = LibIPC.ipc_wait_event self.pointer, pointerof(event), pointerof(@timer)
if r.error_code != 0
m = String.new r.error_message.to_slice
case event_type
when LibIPC::EventType::Disconnection # User disconnected.
# In this case, error_code may not be 0, disconnections can happen at any time.
return IPC::Event::Disconnection.new @event.origin, @event.index
end
# Special case where the fd is closed.
if r.error_code == 107
# Baguette::Log.error "ERROR 107: fd #{@event.origin}"
return IPC::Event::Disconnection.new @event.origin, @event.index
else
# Baguette::Log.error "ERROR #{r.error_code}: fd #{@event.origin}"
end
return IPC::Exception.new "error waiting for a new event: #{m}"
yield IPC::Exception.new "error waiting for a new event: #{m}"
end
# if event type is Timer, there is no file descriptor nor message
case event_type
eventtype = event.type.unsafe_as(LibIPC::EventType)
# if event type is Timer, there is no connection nor message
case eventtype
when LibIPC::EventType::NotSet
return IPC::Event::EventNotSet.new @event.origin, @event.index
return Exception.new "'Event type: not set"
when LibIPC::EventType::Error
return IPC::Event::Error.new @event.origin, @event.index
return IPC::Event::Error.new event.origin, event.index
when LibIPC::EventType::ExtraSocket # Message received from a non IPC socket.
return IPC::Event::ExtraSocket.new @event.origin, @event.index
return IPC::Event::ExtraSocket.new event.origin, event.index
when LibIPC::EventType::Switch # Message to send to a corresponding fd.
return IPC::Event::Switch.new @event.origin, @event.index
return IPC::Event::Switch.new event.origin, event.index
when LibIPC::EventType::Connection # New user.
return IPC::Event::Connection.new @event.origin, @event.index
return IPC::Event::Connection.new event.origin, event.index
when LibIPC::EventType::Disconnection # User disconnected.
return IPC::Event::Disconnection.new @event.origin, @event.index
return IPC::Event::Disconnection.new event.origin, event.index
when LibIPC::EventType::Message # New message.
lowlevel_message = @event.message.unsafe_as(Pointer(LibIPC::Message))
lowlevel_message = event.message.unsafe_as(Pointer(LibIPC::Message))
ipc_message = IPC::Message.new lowlevel_message
return IPC::Event::MessageReceived.new @event.origin, @event.index, ipc_message
return IPC::Event::MessageReceived.new event.origin, event.index, ipc_message
when LibIPC::EventType::LookUp # Client asking for a service through ipcd.
# for now, the libipc does not provide lookup events
# ipcd uses a simple LibIPC::EventType::Message
return IPC::Event::LookUp.new @event.origin, @event.index
return IPC::Event::LookUp.new event.origin, event.index
when LibIPC::EventType::Timer # Timeout in the poll(2) function.
return IPC::Event::Timer.new
when LibIPC::EventType::Tx # Message sent.
return IPC::Event::MessageSent.new @event.origin, @event.index
return IPC::Event::MessageSent.new event.origin, event.index
end
return Exception.new "Cannot understand the event type: #{event_type}"
return Exception.new "Cannot understand the event type: #{eventtype}"
end
def loop(&block : Proc(IPC::Event::Events|Exception, Nil))
@ -105,57 +88,30 @@ class IPC::Context
@timer = @base_timer
end
yield wait_event
yield wait_event &block
end
end
def send_now(message : LibIPC::Message)
r = LibIPC.ipc_write_fd(message.fd, pointerof(message))
if r.error_code != 0
m = String.new r.error_message.to_slice
raise Exception.new "error writing a message: #{m}"
end
end
def send_now(message : IPC::Message)
send_now fd: message.fd, utype: message.utype, payload: message.payload
end
def send_now(fd : Int32, utype : UInt8, payload : Bytes)
message = LibIPC::Message.new fd: fd,
type: LibIPC::MessageType::Data.to_u8,
user_type: utype,
length: payload.bytesize,
payload: payload.to_unsafe
send_now message
end
def send_now(fd : Int32, utype : UInt8, payload : String)
send_now fd, utype, payload.to_slice
end
def send(message : LibIPC::Message)
r = LibIPC.ipc_write(self.pointer, pointerof(message))
if r.error_code != 0
m = String.new r.error_message.to_slice
raise Exception.new "error writing a message: #{m}"
end
end
def send(message : IPC::Message)
send fd: message.fd, utype: message.utype, payload: message.payload
end
def send(fd : Int32, utype : UInt8, payload : Bytes)
message = LibIPC::Message.new fd: fd,
type: LibIPC::MessageType::Data.to_u8,
user_type: utype,
length: payload.bytesize,
payload: payload.to_unsafe
send message
r = LibIPC.ipc_write(self.pointer, pointerof(message))
if r.error_code != 0
m = String.new r.error_message.to_slice
raise Exception.new "error writing a message: #{m}"
end
end
def send(fd : Int32, utype : UInt8, payload : String)
send fd, utype, payload.to_slice
send(fd, utype, Bytes.new(payload.to_unsafe, payload.bytesize))
end
def send(message : IPC::Message)
send(message.fd, message.utype, message.payload)
end
def read(index : UInt32)
@ -174,9 +130,13 @@ class IPC::Context
pointerof(@context)
end
# sanitizer
def fd
@connection.fd
end
def close
return if @closed
r = LibIPC.ipc_close_all(self.pointer)
if r.error_code != 0
m = String.new r.error_message.to_slice

View File

@ -1,7 +1,6 @@
class IPC::Event
alias Events = IPC::Event::Timer |
IPC::Event::EventNotSet |
IPC::Event::Error |
IPC::Event::Connection |
IPC::Event::Disconnection |
@ -53,6 +52,3 @@ end
class IPC::Event::MessageSent < IPC::Event::Base
end
class IPC::Event::EventNotSet < IPC::Event::Base
end

View File

@ -11,9 +11,8 @@ lib LibIPC
end
struct Connection
type : ConnectionType #
more_to_read : Int16* #
spath : LibC::Char* # [4096] # [PATH_MAX]
type : ConnectionType #
spath : LibC::Char* # [4096] # [PATH_MAX]
end
struct Pollfd
@ -25,9 +24,9 @@ lib LibIPC
struct Switching
origin : LibC::Int
dest : LibC::Int
orig_cb_in : (Int32, Pointer(Message), Int16*) -> ConnectionType
orig_cb_in : (Int32, Pointer(Message)) -> ConnectionType
orig_cb_out : (Int32, Pointer(Message)) -> ConnectionType
dest_cb_in : (Int32, Pointer(Message), Int16*) -> ConnectionType
dest_cb_in : (Int32, Pointer(Message)) -> ConnectionType
dest_cb_out : (Int32, Pointer(Message)) -> ConnectionType
end
@ -94,7 +93,7 @@ lib LibIPC
# Connection functions.
# Context is allocated, ipcd is requested and the connection/initialisation is performed.
fun ipc_server_init(ctx : Ctx*, sname : LibC::Char*) : IPCError
fun ipc_connection(Ctx*, LibC::Char*, Int32*) : IPCError
fun ipc_connection(Ctx*, LibC::Char*) : IPCError
fun ipc_connection_switched(Ctx*, LibC::Char*, LibC::Int, Pointer(LibC::Int)) : IPCError
# ipc_message_copy: pm, @fd, @mtype, @utype, @payload
@ -119,10 +118,6 @@ lib LibIPC
# Sending a message (will wait the fd to become available for IO operations).
fun ipc_write(Ctx*, Message*) : IPCError
# Sending a message NOW.
# WARNING: unbuffered send do not wait the fd to become available.
fun ipc_write_fd(Int32, Message*) : IPCError
# This function let the user get the default error message based on the error code.
# The error message is contained in the IPCError structure, this function should not be used, in most cases.
fun ipc_errors_get (LibC::Int) : LibC::Char*
@ -147,11 +142,10 @@ lib LibIPC
# , enum ipccb cb_in (fd, *ipc_message)
# , enum ipccb cb_out (fd, *ipc_message)
fun ipc_switching_callbacks(Ctx*, LibC::Int,
(LibC::Int, LibIPC::Message*, Int16* -> LibIPC::IPCCB),
(LibC::Int, LibIPC::Message* -> LibIPC::IPCCB),
(LibC::Int, LibIPC::Message* -> LibIPC::IPCCB))
fun ipc_ctx_switching_add (ctx : Ctx*, fd1 : LibC::Int, fd2 : LibC::Int) # Void
fun ipc_ctx_switching_del (ctx : Ctx*, fd : LibC::Int) : LibC::Int
fun ipc_switching_add (switch : Switchings*, fd1 : LibC::Int, fd2 : LibC::Int) # Void
fun ipc_switching_del (switch : Switchings*, fd : LibC::Int ) : LibC::Int
fun ipc_switching_get (switch : Switchings*, fd : LibC::Int ) : LibC::Int
@ -159,7 +153,6 @@ lib LibIPC
# non public functions
fun ipc_read(ctx : Ctx*, index : LibC::UInt, message : Message*) : IPCError
fun ipc_read_fd(fd : Int32, message : Message*) : IPCError
# for testing purposes
fun ipc_switching_print (switch : Switchings*) # Void

View File

@ -1,4 +1,3 @@
require "cbor"
require "json"
# JSON is currently used for messages over websockets
@ -10,8 +9,6 @@ class IPC::Message
property utype : UInt8 # libipc user message type
property payload : Bytes
# Clients send and receive JSON (or CBOR) payloads.
struct JSONMessage
include JSON::Serializable
@ -23,37 +20,16 @@ class IPC::Message
end
end
def self.from_json (str : String) : IPC::Message
def self.from_json (str : String)
jsonmessage = JSONMessage.from_json str
IPC::Message.new 0, jsonmessage.mtype, jsonmessage.utype, jsonmessage.payload
end
def to_json : String
def to_json
JSONMessage.new(@utype, String.new(@payload), @mtype).to_json
end
struct CBORMessage
include CBOR::Serializable
property mtype : UInt8 = 1 # libipc message type
property utype : UInt8 # libipc user message type
property payload : Bytes
def initialize(@utype, @payload, @mtype = 1)
end
end
def self.from_cbor (m : Bytes) : IPC::Message
cbor_message = CBORMessage.from_cbor m
IPC::Message.new 0, cbor_message.mtype, cbor_message.utype, cbor_message.payload
end
def to_cbor : Bytes
CBORMessage.new(@utype, @payload, @mtype).to_cbor
end
def initialize(message : Pointer(LibIPC::Message))
if message.null?
@mtype = LibIPC::MessageType::Error.to_u8

View File

@ -11,8 +11,7 @@ class IPC::Server < IPC::Context
end
# Very important as there are filesystem side-effects.
# FIXME: for now, let's forget that.
# at_exit { close }
at_exit { close }
end
end

View File

@ -5,20 +5,20 @@ require "./ipc.cr"
class IPC::JSON
include ::JSON::Serializable
#@[::JSON::Field(ignored: true)]
class_property type = -1
@[::JSON::Field(ignored: true)]
getter type = -1
class_getter type = -1
property id : ::JSON::Any?
def type
@@type
end
macro message(id, type, &block)
class {{id}} < ::IPC::JSON
include ::JSON::Serializable
@@type = {{type}}
def type
@@type
end
{{yield}}
end
@ -26,20 +26,8 @@ class IPC::JSON
end
class IPC::Context
def send(fd : Int32, message : IPC::JSON)
send fd, message.type.to_u8, message.to_json
end
def send_now(fd : Int32, message : IPC::JSON)
send_now fd, message.type.to_u8, message.to_json
end
end
class IPC::Client
def send(message : IPC::JSON)
send @server_fd.not_nil!, message.type.to_u8, message.to_json
end
def send_now(message : IPC::JSON)
send_now @server_fd.not_nil!, message.type.to_u8, message.to_json
send message.type.to_u8, message.to_json
end
end

View File

@ -1,5 +0,0 @@
CRED = "\033[31m"
CBLUE = "\033[36m"
CGREEN = "\033[32m"
CRESET = "\033[00m"
CORANGE = "\033[33m"

View File

@ -1,48 +0,0 @@
# Context class, so the variables are available everywhere.
class Context
class_property requests = [] of IPC::CBOR.class
class_property responses = [] of IPC::CBOR.class
end
class IPC::CBOR
def handle
raise "unimplemented"
end
end
IPC::CBOR.message Message, 10 do
property content : String?
property some_number : Int32?
def initialize(@content = nil, @some_number = nil)
end
def handle
info "message received: #{@content}, number: #{@some_number}"
if number = @some_number
::MessageReceived.new number - 1
else
::MessageReceived.new
end
end
end
Context.requests << Message
IPC::CBOR.message Error, 0 do
property reason : String
def initialize(@reason)
end
end
Context.responses << Error
IPC::CBOR.message MessageReceived, 20 do
property minus_one : Int32?
def initialize(@minus_one = nil)
end
def handle
info "<< MessageReceived (#{@minus_one})"
end
end
Context.responses << MessageReceived

View File

@ -1,3 +0,0 @@
require "../src/ipc.cr"
IPC::Client.new "pong"

View File

@ -1,117 +0,0 @@
require "option_parser"
require "../src/ipc.cr"
require "../src/cbor.cr"
require "./prints.cr"
require "cbor"
require "./message"
class IPC::CBOR
def handle
raise "unimplemented"
end
end
class CLI
class_property service_name = "pong"
class_property message : String? = nil
class_property type = 1
class_property user_type = 42
class_property verbosity = 1
class_property rounds = 1
end
OptionParser.parse do |parser|
parser.on "-s service_name", "--service-name service_name", "URI" do |optsn|
CLI.service_name = optsn
end
parser.on "-v verbosity", "--verbosity verbosity", "Verbosity (0 = nothing is printed, 1 = only events, 2 = events and messages). Default: 1" do |optsn|
CLI.verbosity = optsn.to_i
end
parser.on "-t message_type",
"--type message_type",
"(internal) message type." do |opt|
CLI.type = opt.to_i
end
parser.on "-u user_message_type",
"--user-type user_message_type",
"Message type." do |opt|
CLI.user_type = opt.to_i
end
parser.on "-r rounds", "--rounds count", "Number of messages sent." do |opt|
CLI.rounds = opt.to_i
end
parser.on "-m message", "--message m", "Message to sent." do |opt|
CLI.message = opt
end
parser.on "-h", "--help", "Show this help" do
puts parser
exit 0
end
end
def main
client = IPC::Client.new CLI.service_name
client.base_timer = 30_000 # 30 seconds
client.timer = 30_000 # 30 seconds
server_fd = client.server_fd
if server_fd.nil?
puts "there is no server_fd!!"
exit 1
end
nb_messages_remaining = CLI.rounds
# Listening on STDIN.
client << 0
client.loop do |event|
case event
when IPC::Event::ExtraSocket
info "reading on #{event.fd}"
mstr = if CLI.message.nil?
if event.fd == 0 STDIN.gets || "STDIN failed!" else "coucou" end
else
CLI.message.not_nil!
end
m = Message.new mstr, nb_messages_remaining
info ">> Message"
CLI.rounds.times do |i|
client.send server_fd.not_nil!, m
end
when IPC::Event::MessageReceived
nb_messages_remaining -= 1
response = Context.responses.parse_ipc_cbor event.message
response.handle
case response
when MessageReceived
info "#{nb_messages_remaining} messages remaining"
if nb_messages_remaining == 0
exit 0
end
when Error
end
when IPC::Event::Disconnection
info "Disconnection from #{event.fd}"
if event.fd == 0
client.remove_fd 0
end
else
info "unhandled event: #{event.class}"
end
end
end
main

View File

@ -1,101 +0,0 @@
require "option_parser"
require "../src/ipc.cr"
require "./prints.cr"
class CLI
class_property service_name = "pong"
class_property message : String? = nil
class_property type = 1
class_property user_type = 42
class_property verbosity = 1
class_property rounds = 1
end
OptionParser.parse do |parser|
parser.on "-s service_name", "--service-name service_name", "URI" do |optsn|
CLI.service_name = optsn
end
parser.on "-v verbosity", "--verbosity verbosity", "Verbosity (0 = nothing is printed, 1 = only events, 2 = events and messages). Default: 1" do |optsn|
CLI.verbosity = optsn.to_i
end
parser.on "-t message_type",
"--type message_type",
"(internal) message type." do |opt|
CLI.type = opt.to_i
end
parser.on "-u user_message_type",
"--user-type user_message_type",
"Message type." do |opt|
CLI.user_type = opt.to_i
end
parser.on "-r rounds", "--rounds count", "Number of messages sent." do |opt|
CLI.rounds = opt.to_i
end
parser.on "-m message", "--message m", "Message to sent." do |opt|
CLI.message = opt
end
parser.on "-h", "--help", "Show this help" do
puts parser
exit 0
end
end
def main
client = IPC::Client.new CLI.service_name
client.base_timer = 30_000 # 30 seconds
client.timer = 30_000 # 30 seconds
server_fd = client.server_fd
if server_fd.nil?
puts "there is no server_fd!!"
exit 1
end
nb_messages_remaining = CLI.rounds
# Listening on STDIN.
client << 0
client.loop do |event|
case event
when IPC::Event::ExtraSocket
puts "extra socket fd #{event.fd}"
info "reading on #{event.fd}"
if event.fd == 0
puts "reading on STDIN"
end
mstr = if CLI.message.nil?
if event.fd == 0 STDIN.gets || "STDIN failed!" else "coucou" end
else
CLI.message.not_nil!
end
CLI.rounds.times do |i|
client.send server_fd.not_nil!, CLI.user_type.to_u8, mstr.to_slice
end
when IPC::Event::MessageReceived
nb_messages_remaining -= 1
info "new message from #{event.fd}: #{event.message.to_s}, remaining #{nb_messages_remaining}"
if nb_messages_remaining == 0
exit 0
end
when IPC::Event::Disconnection
info "Disconnection from #{event.fd}"
if event.fd == 0
client.remove_fd 0
end
else
info "unhandled event: #{event.class}"
end
end
end
main

View File

@ -1,96 +0,0 @@
require "option_parser"
require "cbor"
require "../src/ipc.cr"
require "../src/cbor.cr"
require "./prints.cr"
require "./message"
class CLI
class_property service_name = "pong"
class_property verbosity = 1
class_property timer = 30_000
class_property no_response = false
end
OptionParser.parse do |parser|
parser.on "-s service_name", "--service-name service_name", "URI" do |optsn|
CLI.service_name = optsn
end
parser.on "-n", "--no-response", "Do not provide any response back." do
CLI.no_response = true
end
parser.on "-t timer", "--timer ms", "Timer in ms. Default: 30 000" do |optsn|
CLI.timer = optsn.to_i
end
parser.on "-v verbosity", "--verbosity verbosity", "Verbosity (0 = nothing is printed, 1 = only events, 2 = events and messages). Default: 1" do |optsn|
CLI.verbosity = optsn.to_i
end
parser.on "-h", "--help", "Show this help" do
puts parser
exit 0
end
end
def main
service = IPC::Server.new CLI.service_name
service.base_timer = CLI.timer # default: 30 seconds
service.timer = CLI.timer # default: 30 seconds
service.loop do |event|
# service.pp
case event
when IPC::Event::Timer
info "IPC::Event::Timer"
when IPC::Event::Connection
info "IPC::Event::Connection, client: #{event.fd}"
when IPC::Event::Disconnection
info "IPC::Event::Disconnection, client: #{event.fd}"
when IPC::Event::MessageSent
begin
info "IPC::Event::MessageSent, client: #{event.fd}"
rescue e
important "#{e.message}"
service.remove_fd event.fd
end
when IPC::Event::MessageReceived
begin
info "IPC::Event::MessageReceived, client: #{event.fd}"
request = Context.requests.parse_ipc_cbor event.message
if request.nil?
raise "unknown request type"
end
info "<< #{request.class.name}"
response = begin
request.handle
rescue e
important "#{request.class.name} generic error #{e}"
::Error.new "unknown error"
end
unless CLI.no_response
info ">> #{response.class.name}"
service.send event.fd, response.not_nil!
end
rescue e
important "#{e.message}"
service.remove_fd event.fd
end
else
important "Exception: message #{event}"
end
end
end
main

View File

@ -1,78 +0,0 @@
require "option_parser"
require "../src/ipc.cr"
require "./prints.cr"
class CLI
class_property service_name = "pong"
class_property verbosity = 1
class_property timer = 30_000
class_property no_response = false
end
OptionParser.parse do |parser|
parser.on "-s service_name", "--service-name service_name", "URI" do |optsn|
CLI.service_name = optsn
end
parser.on "-n", "--no-response", "Do not provide any response back." do
CLI.no_response = true
end
parser.on "-t timer", "--timer ms", "Timer in ms. Default: 30 000" do |optsn|
CLI.timer = optsn.to_i
end
parser.on "-v verbosity", "--verbosity verbosity", "Verbosity (0 = nothing is printed, 1 = only events, 2 = events and messages). Default: 1" do |optsn|
CLI.verbosity = optsn.to_i
end
parser.on "-h", "--help", "Show this help" do
puts parser
exit 0
end
end
def main
service = IPC::Server.new CLI.service_name
service.base_timer = CLI.timer # default: 30 seconds
service.timer = CLI.timer # default: 30 seconds
service.loop do |event|
# service.pp
case event
when IPC::Event::Timer
info "IPC::Event::Timer"
when IPC::Event::Connection
info "IPC::Event::Connection, client: #{event.fd}"
when IPC::Event::Disconnection
info "IPC::Event::Disconnection, client: #{event.fd}"
when IPC::Event::MessageSent
begin
info "IPC::Event::MessageSent, client: #{event.fd}"
rescue e
important "#{e.message}"
service.remove_fd event.fd
end
when IPC::Event::MessageReceived
begin
info "IPC::Event::MessageReceived, client: #{event.fd}"
m = String.new event.message.payload
debug "message type #{event.message.utype}: #{m}"
unless CLI.no_response
service.send event.message
debug "sending message..."
end
rescue e
important "#{e.message}"
service.remove_fd event.fd
end
else
important "Exception: message #{event}"
end
end
end
main

View File

@ -1,13 +0,0 @@
require "./colors"
def important(message : String)
puts "#{CRED}#{message}#{CRESET}" if CLI.verbosity > 0
end
def info(message : String)
puts "#{CGREEN}#{message}#{CRESET}" if CLI.verbosity > 1
end
def debug(message : String)
puts "#{CBLUE}#{message}#{CRESET}" if CLI.verbosity > 2
end