module UV

BufferedTokenizer takes a delimiter upon instantiation. It allows input to be spoon-fed from some outside source which receives arbitrary length datagrams which may-or-may-not contain the token by which entities are delimited.

@example Using BufferedTokernizer to parse lines out of incoming data

module LineBufferedConnection
    def receive_data(data)
        (@buffer ||= BufferedTokenizer.new(delimiter: "\n")).extract(data).each do |line|
            receive_line(line)
        end
    end
end

Based on code from github.com/chernesk/net-ping/blob/master/lib/net/ping/external.rb

Constants

VERSION

Public Class Methods

attach_server(sock, handler, *args) click to toggle source
# File lib/uv-rays.rb, line 68
def self.attach_server(sock, handler, *args)
    thread = reactor   # Get the reactor running on this thread
    raise ThreadError, "There is no Libuv reactor running on the current thread" if thread.nil?

    klass = klass_from_handler(InboundConnection, handler, *args)
    sd = sock.respond_to?(:fileno) ? sock.fileno : sock

    UV::TcpServer.new thread, sd, sd, klass, *args
end
connect(server, port, handler, *args) click to toggle source
# File lib/uv-rays.rb, line 52
def self.connect(server, port, handler, *args)
    klass = klass_from_handler(OutboundConnection, handler, *args)

    c = klass.new server, port
    c.post_init *args
    c
end
klass_from_handler(klass, handler = nil, *args) click to toggle source

@private

# File lib/uv-rays.rb, line 28
def self.klass_from_handler(klass, handler = nil, *args)
    klass = if handler and handler.is_a?(Class)
        raise ArgumentError, "must provide module or subclass of #{klass.name}" unless klass >= handler
        handler
    elsif handler
        begin
            handler::UR_CONNECTION_CLASS
        rescue NameError
            handler::const_set(:UR_CONNECTION_CLASS, Class.new(klass) {include handler})
        end
    else
        klass
    end

    arity = klass.instance_method(:post_init).arity
    expected = arity >= 0 ? arity : -(arity + 1)
    if (arity >= 0 and args.size != expected) or (arity < 0 and args.size < expected)
        raise ArgumentError, "wrong number of arguments for #{klass}#post_init (#{args.size} for #{expected})"
    end

    klass
end
open_datagram_socket(handler, server = nil, port = nil, *args) click to toggle source
# File lib/uv-rays.rb, line 78
def self.open_datagram_socket(handler, server = nil, port = nil, *args)
    klass = klass_from_handler(DatagramConnection, handler, *args)

    c = klass.new server, port
    c.post_init *args
    c
end
start_server(server, port, handler, *args) click to toggle source
# File lib/uv-rays.rb, line 60
def self.start_server(server, port, handler, *args)
    thread = reactor   # Get the reactor running on this thread
    raise ThreadError, "There is no Libuv reactor running on the current thread" if thread.nil?

    klass = klass_from_handler(InboundConnection, handler, *args)
    UV::TcpServer.new thread, server, port, klass, *args
end
try_connect(tcp, handler, server, port) click to toggle source
# File lib/uv-rays/connection.rb, line 6
def self.try_connect(tcp, handler, server, port)
    if IPAddress.valid? server
        tcp.finally { handler.on_close }
        tcp.progress { |*data| handler.on_read(*data) }
        tcp.connect server, port do
            tcp.enable_nodelay
            tcp.start_tls(handler.using_tls) if handler.using_tls

            # on_connect could call use_tls so must come after start_tls
            handler.on_connect(tcp)
            tcp.start_read
        end
    else
        tcp.reactor.lookup(server, wait: false).then(
            proc { |result|
                UV.try_connect(tcp, handler, result[0][0], port)
            },
            proc { |failure|
                # TODO:: Log error on reactor
                handler.on_close
            }
        )
    end
end