socketry 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,185 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Socketry
4
- # User Datagram Protocol: "fire-and-forget" packet protocol
5
- module UDP
6
- # User Datagram Protocol sockets
7
- class Socket
8
- include Socketry::Timeout
9
-
10
- attr_reader :addr_family, :read_timeout, :write_timeout, :resolver, :socket_class
11
-
12
- # Create a UDP socket matching the given socket's address family
13
- #
14
- # @param remote_addr [String] Address to connect/bind to
15
- # @param resolver [Object] Resolver object to use for resolving DNS names
16
- #
17
- # @return [Socketry::UDP::Socket]
18
- def self.from_addr(remote_addr, resolver: Socketry::Resolver::DEFAULT_RESOLVER)
19
- addr = resolver.resolve(remote_addr)
20
- if addr.ipv4? then new(addr_family: :ipv4)
21
- elsif addr.ipv6? then new(addr_family: :ipv6)
22
- else raise Socketry::AddressError, "unsupported IP address family: #{addr}"
23
- end
24
- end
25
-
26
- # Create a UDP server bound to the given address and port
27
- #
28
- # @param local_addr [String] Local DNS name or IP address to listen on
29
- # @param local_port [Fixnum] Local UDP port to listen on
30
- # @param resolver [Object] Resolver object to use for resolving DNS names
31
- #
32
- # @return [Socketry::UDP::Socket]
33
- def self.bind(local_addr, local_port, resolver: Socketry::Resolver::DEFAULT_RESOLVER)
34
- from_addr(local_addr, resolver: resolver).bind(local_addr, local_port)
35
- end
36
-
37
- # Connect to the given address and port
38
- #
39
- # @param remote_addr [String] DNS name or IP address of the host to connect to
40
- # @param remote_port [Fixnum] UDP port to connect to
41
- # @param resolver [Object] Resolver object to use for resolving DNS names
42
- #
43
- # @return [Socketry::UDP::Socket]
44
- def self.connect(remote_addr, remote_port, resolver: Socketry::Resolver::DEFAULT_RESOLVER)
45
- from_addr(remote_addr, resolver: resolver).connect(remote_addr, remote_port)
46
- end
47
-
48
- # Create a new UDP socket
49
- #
50
- # @param addr_family [:ipv4, :ipv6] (default :ipv4) address family for this socket
51
- # @param read_timeout [Numeric] Seconds to wait before an uncompleted read errors
52
- # @param write_timeout [Numeric] Seconds to wait before an uncompleted write errors
53
- # @param timer [Object] Time interval object to use for measuring timeouts
54
- # @param resolver [Object] Resolver object to use for resolving DNS names
55
- # @param socket_class [Object] Underlying socket class which implements I/O ops
56
- #
57
- # @raise [ArgumentError] an invalid argument was given
58
- #
59
- # @return [Socketry::UDP::Socket]
60
- def initialize(
61
- addr_family: :ipv4,
62
- read_timeout: Socketry::Timeout::DEFAULT_TIMEOUTS[:read],
63
- write_timeout: Socketry::Timeout::DEFAULT_TIMEOUTS[:write],
64
- timer: Socketry::Timeout::DEFAULT_TIMER.new,
65
- resolver: Socketry::Resolver::DEFAULT_RESOLVER,
66
- socket_class: ::UDPSocket
67
- )
68
- @addr_family = case addr_family
69
- when :ipv4 then ::Socket::AF_INET
70
- when :ipv6 then ::Socket::AF_INET6
71
- when ::Socket::AF_INET, ::Socket::AF_INET6 then addr_family
72
- else raise ArgumentError, "invalid address family: #{addr_family.inspect}"
73
- end
74
-
75
- @socket = socket_class.new(@addr_family)
76
- @read_timeout = read_timeout
77
- @write_timeout = write_timeout
78
- @resolver = resolver
79
-
80
- start_timer(timer)
81
- end
82
-
83
- # Start a UDP server bound to a particular address and port
84
- #
85
- # @param local_addr [String] Local DNS name or IP address to listen on
86
- # @param local_port [Fixnum] Local UDP port to listen on
87
- #
88
- # @return [self]
89
- def bind(local_addr, local_port)
90
- @socket.bind(@resolver.resolve(local_addr).to_s, local_port)
91
- self
92
- rescue Errno::EADDRINUSE => ex
93
- raise AddressInUseError, ex.message, ex.backtrace
94
- rescue => ex
95
- raise Socketry::Error, ex.message, ex.backtrace
96
- end
97
-
98
- # Make a UDP client connection to the given address and port
99
- #
100
- # @param remote_addr [String] DNS name or IP address of the host to connect to
101
- # @param remote_port [Fixnum] UDP port to connect to
102
- #
103
- # @return [self]
104
- def connect(remote_addr, remote_port)
105
- @socket.connect(@resolver.resolve(remote_addr).to_s, remote_port)
106
- self
107
- rescue => ex
108
- # TODO: more specific exceptions
109
- raise Socketry::Error, ex.message, ex.backtrace
110
- end
111
-
112
- # Perform a non-blocking receive
113
- #
114
- # @param maxlen [Fixnum] Maximum packet length to receive
115
- #
116
- # @return [Socketry::UDP::Datagram, :wait_readable] Received datagram or indication to wait
117
- def recvfrom_nonblock(maxlen)
118
- Socketry::UDP::Datagram.new(*@socket.recvfrom_nonblock(maxlen))
119
- rescue ::IO::WaitReadable
120
- :wait_readable
121
- rescue => ex
122
- # TODO: more specific exceptions
123
- raise Socketry::Error, ex.message, ex.backtrace
124
- end
125
-
126
- # Perform a blocking receive
127
- #
128
- # @param maxlen [Fixnum] Maximum packet length to receive
129
- # @param timeout [Numeric] Number of seconds to wait for recvfrom operation to complete
130
- #
131
- # @return [String] Received data
132
- def recvfrom(maxlen, timeout: @read_timeout)
133
- set_timeout(timeout)
134
-
135
- begin
136
- while (result = recvfrom_nonblock(maxlen)) == :wait_readable
137
- next if @socket.wait_readable(time_remaining(timeout))
138
- raise Socketry::TimeoutError, "recvfrom timed out after #{timeout} seconds"
139
- end
140
- ensure
141
- clear_timeout(timeout)
142
- end
143
-
144
- result
145
- end
146
-
147
- # Send a UDP packet to a remote host
148
- #
149
- # @param msg [String] Data to write to the remote host/port
150
- # @param host [String] Remote host to send data to. May be omitted if `connect` was called previously
151
- # @param port [Fixnum] UDP port to send data to. May be omitted if `connect` was called previously
152
- #
153
- # @return [Fixum] Number of bytes sent
154
- def send(msg, host: nil, port: nil)
155
- host = @resolver.resolve(host).to_s if host
156
- if host || port
157
- @socket.send(msg, 0, host, port)
158
- else
159
- @socket.send(msg, 0)
160
- end
161
- rescue => ex
162
- # TODO: more specific exceptions
163
- raise Socketry::Error, ex.message, ex.backtrace
164
- end
165
-
166
- # Close the socket
167
- #
168
- # @return [true, false] true if the socket was open, false if closed
169
- def close
170
- return false if closed?
171
- @socket.close
172
- true
173
- ensure
174
- @socket = nil
175
- end
176
-
177
- # Is the socket closed?
178
- #
179
- # @return [true, false] do we locally think the socket is closed?
180
- def closed?
181
- @socket.nil?
182
- end
183
- end
184
- end
185
- end
data/logo.png DELETED
Binary file
data/socketry.gemspec DELETED
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
- lib = File.expand_path("../lib", __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "socketry/version"
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "socketry"
8
- spec.version = Socketry::VERSION
9
- spec.authors = ["Tony Arcieri"]
10
- spec.email = ["bascule@gmail.com"]
11
- spec.licenses = ["MIT"]
12
- spec.homepage = "https://github.com/socketry/socketry/"
13
- spec.summary = "High-level wrappers for Ruby sockets with advanced thread-safe timeout support"
14
- spec.description = <<-DESCRIPTION.strip.gsub(/\s+/, " ")
15
- Socketry wraps Ruby's sockets with an advanced timeout engine which is able to provide multiple
16
- simultaneous timeout behaviors in a thread-safe way.
17
- DESCRIPTION
18
-
19
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
- spec.bindir = "exe"
21
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
- spec.require_paths = ["lib"]
23
-
24
- spec.required_ruby_version = ">= 2.2.6"
25
-
26
- spec.add_runtime_dependency "hitimes", "~> 1.2"
27
-
28
- spec.add_development_dependency "bundler", "~> 1.0"
29
- end