diff --git a/src/ipc/client.cr b/src/ipc/client.cr index 31960dc..4f2dd8c 100644 --- a/src/ipc/client.cr +++ b/src/ipc/client.cr @@ -19,6 +19,10 @@ class IPC::Client < IPC::Context at_exit { close } end + def fd + @server_fd + end + def read unless (fd = @server_fd).nil? message = LibIPC::Message.new diff --git a/src/ipc/context.cr b/src/ipc/context.cr index 1b94a4a..20758ef 100644 --- a/src/ipc/context.cr +++ b/src/ipc/context.cr @@ -40,13 +40,13 @@ class IPC::Context end end - def wait_event(&block) : IPC::Event::Events | Exception + def wait_event : 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 - yield IPC::Exception.new "error waiting for a new event: #{m}" + return IPC::Exception.new "error waiting for a new event: #{m}" end eventtype = event.type.unsafe_as(LibIPC::EventType) @@ -88,32 +88,55 @@ class IPC::Context @timer = @base_timer end - yield wait_event &block + break if yield wait_event 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(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 - - 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 + send message end def send(fd : Int32, utype : UInt8, payload : String) 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) message = LibIPC::Message.new r = LibIPC.ipc_read(self.pointer, index, pointerof(message)) @@ -130,11 +153,6 @@ class IPC::Context pointerof(@context) end - # sanitizer - def fd - @connection.fd - end - def close return if @closed r = LibIPC.ipc_close_all(self.pointer) diff --git a/src/ipc/lowlevel.cr b/src/ipc/lowlevel.cr index 600bd0d..1b04252 100644 --- a/src/ipc/lowlevel.cr +++ b/src/ipc/lowlevel.cr @@ -118,6 +118,10 @@ 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* diff --git a/tests/pongc.cr b/tests/pongc.cr index 509c301..2d3e8ff 100644 --- a/tests/pongc.cr +++ b/tests/pongc.cr @@ -1,24 +1,101 @@ +require "option_parser" require "../src/ipc.cr" +require "./prints.cr" -client = IPC::Client.new "pong" - -server_fd = client.server_fd - -if server_fd.nil? - puts "there is no server_fd!!" - exit 1 +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 -message = IPC::Message.new server_fd, 1, 42.to_u8, "salut ça va ?" +OptionParser.parse do |parser| + parser.on "-s service_name", "--service-name service_name", "URI" do |optsn| + CLI.service_name = optsn + end -client.send message + 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 -client.loop do |event| - case event - when IPC::Event::MessageReceived - puts "\033[32mthere is a message\033[00m" - puts event.message.to_s - client.close - exit + 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 diff --git a/tests/pongd.cr b/tests/pongd.cr index b3c3314..4862716 100644 --- a/tests/pongd.cr +++ b/tests/pongd.cr @@ -1,22 +1,30 @@ require "option_parser" require "../src/ipc.cr" -require "./colors" +require "./prints.cr" -verbosity = 1 -service_name = "pong" -no_response = false +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| - service_name = optsn + CLI.service_name = optsn end parser.on "-n", "--no-response", "Do not provide any response back." do - no_response = true + 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| - verbosity = optsn.to_i + CLI.verbosity = optsn.to_i end parser.on "-h", "--help", "Show this help" do @@ -25,54 +33,46 @@ OptionParser.parse do |parser| end end -service = IPC::Server.new (service_name) -service.base_timer = 5000 # 5 seconds -service.timer = 5000 # 5 seconds +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| - case event - when IPC::Event::Timer - if verbosity >= 1 - puts "#{CORANGE}IPC::Event::Timer#{CRESET}" - end - when IPC::Event::Connection - if verbosity >= 1 - puts "#{CBLUE}IPC::Event::Connection#{CRESET}, client: #{event.fd}" - end - when IPC::Event::Disconnection - if verbosity >= 1 - puts "#{CBLUE}IPC::Event::Disconnection#{CRESET}, client: #{event.fd}" - end - when IPC::Event::MessageSent - begin - if verbosity >= 1 - puts "#{CGREEN}IPC::Event::MessageSent#{CRESET}, client: #{event.fd}" + 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 - rescue e - puts "#{CRED}#{e.message}#{CRESET}" - service.remove_fd event.fd - end - when IPC::Event::MessageReceived - begin - if verbosity >= 1 - puts "#{CGREEN}IPC::Event::MessageReceived#{CRESET}, client: #{event.fd}" - if verbosity >= 2 - m = String.new event.message.payload - puts "#{CBLUE}message type #{event.message.utype}: #{m} #{CRESET}" + 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 - end - service.send event.message unless no_response - if verbosity >= 2 && ! no_response - puts "#{CBLUE}sending message...#{CRESET}" - end - rescue e - puts "#{CRED}#{e.message}#{CRESET}" - service.remove_fd event.fd - end - else - if verbosity >= 1 - puts "#{CRED}Exception: message #{event} #{CRESET}" + rescue e + important "#{e.message}" + service.remove_fd event.fd + end + else + important "Exception: message #{event}" end end end + +main diff --git a/tests/prints.cr b/tests/prints.cr new file mode 100644 index 0000000..1770699 --- /dev/null +++ b/tests/prints.cr @@ -0,0 +1,13 @@ +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