Git Product home page Git Product logo

ionian's Introduction

Ionian

Gem Version

A Ruby library to simplify interaction with IO streams. This includes network sockets, file sockets, and serial streams like the console and RS232. Features regular expression matching and notification of received data.

Supported Ruby Versions

  • MRI >= 2.0.0

Installation

gem install ionian

Issues, Bugs, Feature Requests

Any bugs and feature requests should be reported on the GitHub issue tracker:

https://github.com/amclain/ionian/issues

Pull requests are preferred via GitHub.

Mercurial users can use Hg-Git to interact with GitHub repositories.

Code Examples

Creating A Socket

socket = Ionian::Socket.new host: '127.0.0.1', port: 23

Sending And Receiving Data

socket = Ionian::Socket.new host: 'google.com', port: 80
socket.write "GET / HTTP/1.1\r\n\r\n"
socket.read_match { |match| p match; puts '' }

Match Expressions And Named Captures

# A simple IRC client.

socket = Ionian::Socket.new \
  host: 'chat.freenode.net:6667',
  # Break up the matches into named captures so it's easier
  # to sort through the server's responses.
  expression: /:(?<server>.*?)\s*:(?<msg>.*?)[\r\n]+/

# Log on to IRC and send a message.
socket.write "NICK ionian-demo\r\nUSER ionian-demo ionian-demo chat.freenode.net :ionian-demo"
socket.write "PROTOCL NAMESX\r\n"
socket.write "JOIN #ionian-demo\r\n"
socket.write "PRIVMSG #ionian-demo :this is a test\r\n"


loop do
  socket.read_match do |match|
  	# Print the body of the server's responses.
    puts match.msg
    
    # Exit when the server has caught up.
    exit if match.msg.include? 'End of /NAMES list.'
  end
end

Simple Server

host = 'localhost:5000'

server = Ionian::Server.new interface: host do |client|
  # Greet the connected client.
  client.write "Welcome! You are connected to the server.\n"
end

socket = Ionian::Socket.new host: host
# Retrieve the greeting message.
puts socket.read_all

ionian's People

Contributors

amclain avatar jemc avatar

Stargazers

Shiva Bhusal avatar  avatar  avatar

Watchers

James Cloos avatar  avatar

ionian's Issues

Socket port is initialized to 0

The default port according to the docs is 23, but in the following code it is initialized to 0.

Ionian::Socket.new host: '10.0.5.20'
C:/ruby/Ruby21-x64/lib/ruby/gems/2.1.0/gems/ionian-0.6.10/lib/ionian/socket.rb:2
80:in `initialize': The requested address is not valid in its context. - connect
(2) for "10.0.5.20" port 0 (Errno::EADDRNOTAVAIL)
        from C:/ruby/Ruby21-x64/lib/ruby/gems/2.1.0/gems/ionian-0.6.10/lib/ionian/socket.rb:280:in `new'
        from C:/ruby/Ruby21-x64/lib/ruby/gems/2.1.0/gems/ionian-0.6.10/lib/ionian/socket.rb:280:in `create_socket'
        from C:/ruby/Ruby21-x64/lib/ruby/gems/2.1.0/gems/ionian-0.6.10/lib/ionian/socket.rb:142:in `initialize'
        from C:/Users/Alex/Desktop/test.rb:3:in `new'
        from C:/Users/Alex/Desktop/test.rb:3:in `<main>'

Add heartbeating

Add the ability to automatically send a heartbeat string at a specified interval. This may be able to be consolidated into the #run_match method.

Cases:

  1. Only the heartbeat string clears the timer.
  2. Any outgoing data clears the timer.
  3. Outgoing or incoming data clears the timer.

Automatic reconnect when persistent:true

Socket should automatically try to reconnect to the server if the persistent flag is true. There should also be a reconnect kwarg that can be set false if this behavior is not desired.

ManagedSocket fails to auto-reconnect if not connected the first time

[23] pry(main)> s = Ionian::ManagedSocket.new host: '10.0.11.3:1023',
auto_reconnect: true, connect_timeout: 10

Errno::EHOSTUNREACH: No route to host
ionian-0.7.0/lib/ionian/socket.rb:373:in `rescue in create_socket'
[24] pry(main)>

This should get raised through the on_error handler and another connection attempt should happen.

Add block to Ionian::Socket.new

Sockets should work like the File class and others do, where the open socket can be used in a block. The socket should be flushed and closed automatically when exiting the block.

Ionian::Socket.new host: "127.0.0.1:1234" do |socket|
  socket.write 'test data'
  foo = socket.read_all
  # do stuff with foo
  # Socket automatically closes here.
end

Break out non-persistent sockets into their own class

Non-persistent sockets (close after message sent) implement a special kind of behavior and therefore should have their own NonPersistentSocket class to be able to opt-in to that functionality. Also, methods like #run_match that don't make sense for this socket type should be disabled/undefined.

Add :broadcast to Ionian::Socket.new keyword args

Add :broadcast to Ionian::Socket.new keyword args.

Maybe broadcast should be set automatically if the host address given is a broadcast address?

Note that you get Errno::EACCES if @socket.connect is called with a broadcast address before the broadcast socket option is set, so if the keyword arg is there, the socket option should be set before connect.

MRI 2.2.0 Compatibility

Ionian::Extension::IO ....................FF...

  1) Ionian::Extension::IO can read all of the data in the buffer
     Failure/Error: result.size.should eq data.size

       expected: 131072
            got: 109440

       (compared using ==)
     # ./spec/extension/io_spec.rb:167:in `block (2 levels) in <top (required)>'

  2) Ionian::Extension::IO can match large data in the buffer
     Failure/Error: match.empty?.should eq false

       expected: false
            got: true

       (compared using ==)
     # ./spec/extension/io_spec.rb:185:in `block (2 levels) in <top (required)>'
Ionian::Extension::Socket .............................................................
Ionian::Server ...........................
Ionian::Socket ...........................................................FFFFFF..FFFFFFF.....................................................

  3) Ionian::Socket  initializer block 
     Failure/Error: Ionian::Socket.new **kwargs do |socket|
     Errno::ECONNREFUSED:
       Connection refused - connect(2) for "localhost" port 5050
     # ./lib/ionian/socket.rb:286:in `initialize'
     # ./lib/ionian/socket.rb:286:in `new'
     # ./lib/ionian/socket.rb:286:in `block in create_socket'
     # ./lib/ionian/socket.rb:283:in `create_socket'
     # ./lib/ionian/socket.rb:146:in `initialize'
     # ./spec/socket_spec.rb:144:in `new'
     # ./spec/socket_spec.rb:144:in `block (4 levels) in <top (required)>'
     # ./spec/socket_spec.rb:87:in `block (2 levels) in <top (required)>'
     # ./spec/socket_spec.rb:139:in `block (5 levels) in <top (required)>'
     # ./spec/socket_spec.rb:139:in `block (4 levels) in <top (required)>'

  4) Ionian::Socket  initializer block socket is closed by developer 
     Failure/Error: around(:each) { |test| Timeout.timeout(1) { test.run } }
     Timeout::Error:
       execution expired
     # ./spec/listener_socket_context.rb:43:in `close'
     # ./spec/listener_socket_context.rb:43:in `block (3 levels) in <top (required)>'
     # ./spec/listener_socket_context.rb:43:in `each'
     # ./spec/listener_socket_context.rb:43:in `block (2 levels) in <top (required)>'
     # ./spec/socket_spec.rb:139:in `block (5 levels) in <top (required)>'
     # ./spec/socket_spec.rb:139:in `block (4 levels) in <top (required)>'

  5) Ionian::Socket  run_match should terminate gracefully when the socket is closed
     Failure/Error: Unable to find matching line from backtrace
     Errno::EADDRINUSE:
       Address already in use - bind(2) for nil port 5050
     # ./spec/listener_socket_context.rb:54:in `initialize'
     # ./spec/listener_socket_context.rb:54:in `new'
     # ./spec/listener_socket_context.rb:54:in `block (2 levels) in <top (required)>'
     # ./spec/listener_socket_context.rb:23:in `block (2 levels) in <top (required)>'

  6) Ionian::Socket  on_match returns a match only once when run_match thread is running
     Failure/Error: Unable to find matching line from backtrace
     Errno::EADDRINUSE:
       Address already in use - bind(2) for nil port 5050
     # ./spec/listener_socket_context.rb:54:in `initialize'
     # ./spec/listener_socket_context.rb:54:in `new'
     # ./spec/listener_socket_context.rb:54:in `block (2 levels) in <top (required)>'
     # ./spec/listener_socket_context.rb:23:in `block (2 levels) in <top (required)>'

  7) Ionian::Socket  on_match returns a match only once when run_match thread is not running
     Failure/Error: Unable to find matching line from backtrace
     Errno::EADDRINUSE:
       Address already in use - bind(2) for nil port 5050
     # ./spec/listener_socket_context.rb:54:in `initialize'
     # ./spec/listener_socket_context.rb:54:in `new'
     # ./spec/listener_socket_context.rb:54:in `block (2 levels) in <top (required)>'
     # ./spec/listener_socket_context.rb:23:in `block (2 levels) in <top (required)>'

  8) Ionian::Socket existing socket can convert an existing tcp socket 
     Failure/Error: Unable to find matching line from backtrace
     Errno::EADDRINUSE:
       Address already in use - bind(2) for nil port 5050
     # ./spec/listener_socket_context.rb:54:in `initialize'
     # ./spec/listener_socket_context.rb:54:in `new'
     # ./spec/listener_socket_context.rb:54:in `block (2 levels) in <top (required)>'
     # ./spec/listener_socket_context.rb:23:in `block (2 levels) in <top (required)>'

  9) Ionian::Socket with protocol: :tcp 
     Failure/Error: Unable to find matching line from backtrace
     Errno::EADDRINUSE:
       Address already in use - bind(2) for nil port 5050
     # ./spec/listener_socket_context.rb:54:in `initialize'
     # ./spec/listener_socket_context.rb:54:in `new'
     # ./spec/listener_socket_context.rb:54:in `block (2 levels) in <top (required)>'
     # ./spec/listener_socket_context.rb:23:in `block (2 levels) in <top (required)>'

  10) Ionian::Socket with protocol: :tcp protocol? 
     Failure/Error: Unable to find matching line from backtrace
     Errno::EADDRINUSE:
       Address already in use - bind(2) for nil port 5050
     # ./spec/listener_socket_context.rb:54:in `initialize'
     # ./spec/listener_socket_context.rb:54:in `new'
     # ./spec/listener_socket_context.rb:54:in `block (2 levels) in <top (required)>'
     # ./spec/listener_socket_context.rb:23:in `block (2 levels) in <top (required)>'

  11) Ionian::Socket with protocol: :tcp persistent? 
     Failure/Error: Unable to find matching line from backtrace
     Errno::EADDRINUSE:
       Address already in use - bind(2) for nil port 5050
     # ./spec/listener_socket_context.rb:54:in `initialize'
     # ./spec/listener_socket_context.rb:54:in `new'
     # ./spec/listener_socket_context.rb:54:in `block (2 levels) in <top (required)>'
     # ./spec/listener_socket_context.rb:23:in `block (2 levels) in <top (required)>'

  12) Ionian::Socket with protocol: :tcp closed? 
     Failure/Error: Unable to find matching line from backtrace
     Errno::EADDRINUSE:
       Address already in use - bind(2) for nil port 5050
     # ./spec/listener_socket_context.rb:54:in `initialize'
     # ./spec/listener_socket_context.rb:54:in `new'
     # ./spec/listener_socket_context.rb:54:in `block (2 levels) in <top (required)>'
     # ./spec/listener_socket_context.rb:23:in `block (2 levels) in <top (required)>'

  13) Ionian::Socket with protocol: :tcp behaves like a persistent ionian socket can write data
     Failure/Error: Unable to find matching line from backtrace
     Errno::EADDRINUSE:
       Address already in use - bind(2) for nil port 5050
     Shared Example Group: "a persistent ionian socket" called from ./spec/socket_spec.rb:289
     # ./spec/listener_socket_context.rb:54:in `initialize'
     # ./spec/listener_socket_context.rb:54:in `new'
     # ./spec/listener_socket_context.rb:54:in `block (2 levels) in <top (required)>'
     # ./spec/listener_socket_context.rb:23:in `block (2 levels) in <top (required)>'

  14) Ionian::Socket with protocol: :tcp behaves like a persistent ionian socket behaves like an ionian socket can write data with the '<<' operator
     Failure/Error: Unable to find matching line from backtrace
     Errno::EADDRINUSE:
       Address already in use - bind(2) for nil port 5050
     Shared Example Group: "an ionian socket" called from ./spec/socket_spec.rb:44
     # ./spec/listener_socket_context.rb:54:in `initialize'
     # ./spec/listener_socket_context.rb:54:in `new'
     # ./spec/listener_socket_context.rb:54:in `block (2 levels) in <top (required)>'
     # ./spec/listener_socket_context.rb:23:in `block (2 levels) in <top (required)>'

  15) Ionian::Socket with protocol: :tcp behaves like a persistent ionian socket behaves like an ionian socket can 'puts' data
     Failure/Error: Unable to find matching line from backtrace
     Errno::EADDRINUSE:
       Address already in use - bind(2) for nil port 5050
     Shared Example Group: "an ionian socket" called from ./spec/socket_spec.rb:44
     # ./spec/listener_socket_context.rb:54:in `initialize'
     # ./spec/listener_socket_context.rb:54:in `new'
     # ./spec/listener_socket_context.rb:54:in `block (2 levels) in <top (required)>'
     # ./spec/listener_socket_context.rb:23:in `block (2 levels) in <top (required)>'

Finished in 10 minutes 17 seconds (files took 0.27361 seconds to load)
240 examples, 15 failures

Failed examples:

rspec ./spec/extension/io_spec.rb:156 # Ionian::Extension::IO can read all of the data in the buffer
rspec ./spec/extension/io_spec.rb:171 # Ionian::Extension::IO can match large data in the buffer
rspec ./spec/socket_spec.rb:151 # Ionian::Socket  initializer block 
rspec ./spec/socket_spec.rb:151 # Ionian::Socket  initializer block socket is closed by developer 
rspec ./spec/socket_spec.rb:182 # Ionian::Socket  run_match should terminate gracefully when the socket is closed
rspec ./spec/socket_spec.rb:198 # Ionian::Socket  on_match returns a match only once when run_match thread is running
rspec ./spec/socket_spec.rb:211 # Ionian::Socket  on_match returns a match only once when run_match thread is not running
rspec ./spec/socket_spec.rb:241 # Ionian::Socket existing socket can convert an existing tcp socket 
rspec ./spec/socket_spec.rb:287 # Ionian::Socket with protocol: :tcp 
rspec ./spec/socket_spec.rb:283 # Ionian::Socket with protocol: :tcp protocol? 
rspec ./spec/socket_spec.rb:284 # Ionian::Socket with protocol: :tcp persistent? 
rspec ./spec/socket_spec.rb:285 # Ionian::Socket with protocol: :tcp closed? 
rspec ./spec/socket_spec.rb:31 # Ionian::Socket with protocol: :tcp behaves like a persistent ionian socket can write data
rspec ./spec/socket_spec.rb:11 # Ionian::Socket with protocol: :tcp behaves like a persistent ionian socket behaves like an ionian socket can write data with the '<<' operator
rspec ./spec/socket_spec.rb:20 # Ionian::Socket with protocol: :tcp behaves like a persistent ionian socket behaves like an ionian socket can 'puts' data

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.