backport 0.3.0 → 1.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9693d9fb93dc1efb03c85d3abe258cd54e2fa4bca03e8bc2f64a45a56783269a
4
- data.tar.gz: a7abdaa602ccbfda748cdace2af071af73651ecff42663ac237def501260f457
3
+ metadata.gz: ef66ad1688e603cf9a8c9844c5551bbc3ca9187abf747bca2064e46fb7c2600f
4
+ data.tar.gz: 3952f19adbe1639f82c98568d4adc97aa0c690d5fa568fef768efbcf6134ee7c
5
5
  SHA512:
6
- metadata.gz: bbc92f9838a571f7cb9ea71334961cf34013a41e1010147ec4f54d4c5efde68c37b4f7cb9f0d9d52ad8ebe23ac9fa83e24568d690044ed200d838a1cb2c50358
7
- data.tar.gz: a5cdf05eb09d40bc352fd07ed2d23b85107875551c9718e0145e7abdf92f670ff784e99b50b8daf5879c7a0cbe92dca1d8ca4b3a42ed73a482610085fd56e986
6
+ metadata.gz: 334cb82482d72e1b617fa9fa2a1a1b87764b800e4a8abf6ecc2c63fc012406fb05bf744b362aa6f3211aae0f868ab188902132825602ee3909b54358e2cd1813
7
+ data.tar.gz: 2ff55f4495545b50e4e226f961d38b5471cc8d1890a4339091f126139f61422e1ae3af1e1a8c3fc80aafb915b187da099ef312a5e7da1ad4a500f737e9a6909c
@@ -2,3 +2,5 @@ Style/MethodDefParentheses:
2
2
  Enabled: false
3
3
  Layout/EmptyLineAfterGuardClause:
4
4
  Enabled: false
5
+ Style/StringLiterals:
6
+ Enabled: false
@@ -1,7 +1,6 @@
1
1
  ---
2
2
  sudo: false
3
3
  language: ruby
4
- cache: bundler
5
4
  rvm:
6
5
  - 2.1
7
6
  - 2.2
@@ -9,6 +8,7 @@ rvm:
9
8
  - 2.4
10
9
  - 2.5.1
11
10
  - 2.5.3
11
+ - 2.6
12
12
  - jruby-9.0.5.0
13
13
  - jruby-9.1.16.0
14
14
  matrix:
@@ -1,3 +1,7 @@
1
+ ## 1.0.0 - February 19, 2019
2
+ - Renamed Adapter#sending to Adapter#receiving
3
+ - Travis tests up to Ruby 2.6
4
+
1
5
  ## 0.3.0 - January 10, 2019
2
6
  - Basic logging
3
7
  - Differentiate between "expected" and "unexpected" exceptions in Tcpip
data/README.md CHANGED
@@ -1,80 +1,80 @@
1
- # Backport
2
-
3
- A pure Ruby library for event-driven IO.
4
-
5
- This library is designed with portability as the highest priority, which is why it's written in pure Ruby. Consider [EventMachine](https://github.com/eventmachine/eventmachine) if you need a solution that's faster, more mature, and scalable.
6
-
7
- ## Installation
8
-
9
- Install the gem:
10
-
11
- ```
12
- gem install backport
13
- ```
14
-
15
- Or add it to your application's Gemfile:
16
-
17
- ```ruby
18
- gem 'backport'
19
- ```
20
-
21
- ## Usage
22
-
23
- ### Examples
24
-
25
- A simple echo server:
26
-
27
- ```ruby
28
- require 'backport'
29
-
30
- module MyAdapter
31
- def opening
32
- puts "Opening a connection"
33
- end
34
-
35
- def closing
36
- puts "Closing a connection"
37
- end
38
-
39
- def sending data
40
- write "Client sent: #{data}"
41
- end
42
- end
43
-
44
- Backport.run do
45
- Backport.prepare_tcp_server(host: 'localhost', port: 8000, adapter: MyAdapter)
46
- end
47
- ```
48
-
49
- An interval server that runs once per second:
50
-
51
- ```ruby
52
- require 'backport'
53
-
54
- Backport.run do
55
- Backport.prepare_interval 1 do
56
- puts "tick"
57
- end
58
- end
59
- ```
60
-
61
- ### Using Adapters
62
-
63
- Backport servers that handle client connections, such as TCP servers, use an
64
- adapter to provide an application interface to the client. Developers can
65
- provide their own adapter implementations in two ways: a Ruby module that will
66
- be used to extend a Backport::Adapter object, or a class that extends
67
- Backport::Adapter. In either case, the adapter should provide the following
68
- methods:
69
-
70
- * `opening`: A callback triggered when the client connection is accepted
71
- * `closing`: A callback triggered when the client connection is closed
72
- * `sending(data)`: A callback triggered when the server receives data from the client
73
-
74
- Backport::Adapter also provides the following methods:
75
-
76
- * `write(data)`: Send raw data to the client
77
- * `write_line(data)`: Send a line of data to the client
78
- * `close`: Disconnect the client from the server
79
- * `closed?`: True if the connection is closed
80
- * `remote`: A hash of data about the client, e.g., the remote IP address
1
+ # Backport
2
+
3
+ A pure Ruby library for event-driven IO.
4
+
5
+ This library is designed with portability as the highest priority, which is why it's written in pure Ruby. Consider [EventMachine](https://github.com/eventmachine/eventmachine) if you need a solution that's faster, more mature, and scalable.
6
+
7
+ ## Installation
8
+
9
+ Install the gem:
10
+
11
+ ```
12
+ gem install backport
13
+ ```
14
+
15
+ Or add it to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'backport'
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ### Examples
24
+
25
+ A simple echo server:
26
+
27
+ ```ruby
28
+ require 'backport'
29
+
30
+ module MyAdapter
31
+ def opening
32
+ puts "Opening a connection"
33
+ end
34
+
35
+ def closing
36
+ puts "Closing a connection"
37
+ end
38
+
39
+ def receiving data
40
+ write "Client sent: #{data}"
41
+ end
42
+ end
43
+
44
+ Backport.run do
45
+ Backport.prepare_tcp_server(host: 'localhost', port: 8000, adapter: MyAdapter)
46
+ end
47
+ ```
48
+
49
+ An interval server that runs once per second:
50
+
51
+ ```ruby
52
+ require 'backport'
53
+
54
+ Backport.run do
55
+ Backport.prepare_interval 1 do
56
+ puts "tick"
57
+ end
58
+ end
59
+ ```
60
+
61
+ ### Using Adapters
62
+
63
+ Backport servers that handle client connections, such as TCP servers, use an
64
+ adapter to provide an application interface to the client. Developers can
65
+ provide their own adapter implementations in two ways: a Ruby module that will
66
+ be used to extend a Backport::Adapter object, or a class that extends
67
+ Backport::Adapter. In either case, the adapter should provide the following
68
+ methods:
69
+
70
+ * `opening`: A callback triggered when the client connection is accepted
71
+ * `closing`: A callback triggered when the client connection is closed
72
+ * `receiving(data)`: A callback triggered when the server receives data from the client
73
+
74
+ Backport::Adapter also provides the following methods:
75
+
76
+ * `write(data)`: Send raw data to the client
77
+ * `write_line(data)`: Send a line of data to the client
78
+ * `close`: Disconnect the client from the server
79
+ * `closed?`: True if the connection is closed
80
+ * `remote`: A hash of data about the client, e.g., the remote IP address
@@ -1,27 +1,28 @@
1
-
2
- lib = File.expand_path("../lib", __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "backport/version"
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "backport"
8
- spec.version = Backport::VERSION
9
- spec.authors = ["Fred Snyder"]
10
- spec.email = ["fsnyder@castwide.com"]
11
-
12
- spec.summary = %q{A pure Ruby library for event-driven IO}
13
- spec.homepage = "http://github.com/castwide/backport"
14
- spec.license = "MIT"
15
-
16
- # Specify which files should be added to the gem when it is released.
17
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
19
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
- end
21
- spec.require_paths = ["lib"]
22
-
23
- spec.add_development_dependency "bundler", "~> 1.17"
24
- spec.add_development_dependency "rake", "~> 10.0"
25
- spec.add_development_dependency "rspec", "~> 3.0"
26
- spec.add_development_dependency "simplecov", "~> 0.14"
27
- end
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "backport/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "backport"
8
+ spec.version = Backport::VERSION
9
+ spec.authors = ["Fred Snyder"]
10
+ spec.email = ["fsnyder@castwide.com"]
11
+
12
+ spec.summary = %q{A pure Ruby library for event-driven IO}
13
+ spec.homepage = "http://github.com/castwide/backport"
14
+ spec.license = "MIT"
15
+
16
+ # Specify which files should be added to the gem when it is released.
17
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
19
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
+ end
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.required_ruby_version = '>= 2.1'
24
+
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.0"
27
+ spec.add_development_dependency "simplecov", "~> 0.14"
28
+ end
@@ -1,4 +1,4 @@
1
- require "backport/version"
1
+ require 'backport/version'
2
2
  require 'logger'
3
3
 
4
4
  # An event-driven IO library.
@@ -40,13 +40,13 @@ module Backport
40
40
  # @return [void]
41
41
  def closing; end
42
42
 
43
- # A callback triggered when the client sends data to the server. Subclasses
44
- # and/or modules should override this method to provide their own
45
- # functionality.
43
+ # A callback triggered when the server receives data from the client.
44
+ # Subclasses and/or modules should override this method to provide their
45
+ # own functionality.
46
46
  #
47
47
  # @param data [String]
48
48
  # @return [void]
49
- def sending(data); end
49
+ def receiving(data); end
50
50
 
51
51
  # Send data to the client.
52
52
  #
@@ -5,6 +5,10 @@ module Backport
5
5
  # @return [Adapter]
6
6
  attr_reader :adapter
7
7
 
8
+ # @param input [IO]
9
+ # @param output [IO]
10
+ # @param adapter [Class, Module]
11
+ # @param remote [Hash]
8
12
  def initialize input, output, adapter, remote = {}
9
13
  @in = input
10
14
  @out = output
@@ -13,6 +17,8 @@ module Backport
13
17
  @buffer = ''
14
18
  end
15
19
 
20
+ # True if the client is stopped.
21
+ #
16
22
  def stopped?
17
23
  @stopped ||= false
18
24
  end
@@ -41,13 +47,22 @@ module Backport
41
47
  # @deprecated Prefer #start to #run for non-blocking client/server methods
42
48
  alias run start
43
49
 
44
- # Notify the adapter that the client is sending data.
50
+ # Handle a tick from the server. This method will check for client input
51
+ # and update the adapter accordingly, or stop the client if the adapter is
52
+ # closed.
45
53
  #
46
- # @param data [String]
47
- def sending data
48
- @adapter.sending data
54
+ # @return [void]
55
+ def tick
56
+ if adapter.closed?
57
+ stop
58
+ else
59
+ input = read
60
+ @adapter.receiving input unless input.nil?
61
+ end
49
62
  end
50
63
 
64
+ private
65
+
51
66
  # Read the client input. Return nil if the input buffer is empty.
52
67
  #
53
68
  # @return [String, nil]
@@ -60,8 +75,7 @@ module Backport
60
75
  return tmp unless tmp.empty?
61
76
  end
62
77
 
63
- private
64
-
78
+ # @return [Adapter]
65
79
  def make_adapter cls_mod, remote
66
80
  if cls_mod.is_a?(Class) && cls_mod <= Backport::Adapter
67
81
  @adapter = cls_mod.new(@out, remote)
@@ -73,25 +87,34 @@ module Backport
73
87
  end
74
88
  end
75
89
 
90
+ # @return [Mutex]
76
91
  def mutex
77
92
  @mutex ||= Mutex.new
78
93
  end
79
94
 
95
+ # Start the thread that checks the input IO for client data.
96
+ #
97
+ # @return [void]
80
98
  def run_input_thread
81
99
  Thread.new do
82
- until stopped?
83
- @in.flush
84
- begin
85
- chars = @in.sysread(255)
86
- rescue EOFError, Errno::ECONNRESET
87
- chars = nil
88
- end
89
- if chars.nil?
90
- stop
91
- break
92
- end
93
- mutex.synchronize { @buffer.concat chars }
94
- end
100
+ read_input until stopped?
101
+ end
102
+ end
103
+
104
+ # Read input from the client.
105
+ #
106
+ # @return [void]
107
+ def read_input
108
+ @in.flush
109
+ begin
110
+ chars = @in.sysread(255)
111
+ rescue EOFError, Errno::ECONNRESET
112
+ chars = nil
113
+ end
114
+ if chars.nil?
115
+ stop
116
+ else
117
+ mutex.synchronize { @buffer.concat chars }
95
118
  end
96
119
  end
97
120
  end
@@ -50,6 +50,9 @@ module Backport
50
50
  @servers ||= []
51
51
  end
52
52
 
53
+ # Update the machine's servers.
54
+ #
55
+ # @return [void]
53
56
  def tick
54
57
  servers.delete_if(&:stopped?)
55
58
  stop if servers.empty?
@@ -58,6 +61,9 @@ module Backport
58
61
 
59
62
  private
60
63
 
64
+ # Start the thread that updates servers via the #tick method.
65
+ #
66
+ # @return [void]
61
67
  def run_server_thread
62
68
  servers.map(&:start)
63
69
  until stopped?
@@ -6,9 +6,9 @@ module Backport
6
6
  #
7
7
  module Connectable
8
8
  def tick
9
- clients.each do |client|
10
- input = client.read
11
- client.sending input unless input.nil?
9
+ mutex.synchronize do
10
+ clients.each(&:tick)
11
+ clients.delete_if(&:stopped?)
12
12
  end
13
13
  end
14
14
 
@@ -24,6 +24,12 @@ module Backport
24
24
  def clients
25
25
  @clients ||= []
26
26
  end
27
+
28
+ private
29
+
30
+ def mutex
31
+ @mutex ||= Mutex.new
32
+ end
27
33
  end
28
34
  end
29
35
  end
@@ -14,20 +14,6 @@ module Backport
14
14
  @stopped = false
15
15
  end
16
16
 
17
- def tick
18
- mutex.synchronize do
19
- clients.each do |client|
20
- if client.adapter.closed?
21
- client.stop
22
- next
23
- end
24
- input = client.read
25
- client.sending input unless input.nil?
26
- end
27
- clients.delete_if(&:stopped?)
28
- end
29
- end
30
-
31
17
  def starting
32
18
  start_accept_thread
33
19
  end
@@ -37,8 +23,8 @@ module Backport
37
23
  return if socket.closed?
38
24
  begin
39
25
  socket.shutdown Socket::SHUT_RDWR
40
- rescue Errno::ENOTCONN, IOError => e
41
- Backport.logger.info "Minor exception while stopping server [#{e.class}] #{e.message}"
26
+ rescue Errno::ENOTCONN, IOError => err
27
+ Backport.logger.info "Minor exception while stopping server [#{err.class}] #{err.message}"
42
28
  end
43
29
  socket.close
44
30
  end
@@ -63,13 +49,13 @@ module Backport
63
49
  clients.push Client.new(conn, conn, @adapter, data)
64
50
  clients.last.run
65
51
  result = clients.last
66
- rescue IO::WaitReadable, Errno::EAGAIN => e
52
+ rescue IO::WaitReadable, Errno::EAGAIN
67
53
  # ignore
68
- rescue Errno::ENOTSOCK, IOError => e
69
- Backport.logger.info "Server stopped with minor exception [#{e.class}] #{e.message}"
54
+ rescue Errno::ENOTSOCK, IOError => err
55
+ Backport.logger.info "Server stopped with minor exception [#{err.class}] #{err.message}"
70
56
  stop
71
- rescue Exception => e
72
- Backport.logger.warn "Server stopped with major exception [#{e.class}] #{e.message}"
57
+ rescue Exception => err
58
+ Backport.logger.warn "Server stopped with major exception [#{err.class}] #{err.message}"
73
59
  stop
74
60
  end
75
61
  end
@@ -81,10 +67,6 @@ module Backport
81
67
  # @return [TCPSocket]
82
68
  attr_reader :socket
83
69
 
84
- def mutex
85
- @mutex ||= Mutex.new
86
- end
87
-
88
70
  def start_accept_thread
89
71
  Thread.new do
90
72
  until stopped?
@@ -1,3 +1,3 @@
1
1
  module Backport
2
- VERSION = '0.3.0'.freeze
2
+ VERSION = '1.0.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: backport
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fred Snyder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-10 00:00:00.000000000 Z
11
+ date: 2019-02-19 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.17'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.17'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: rake
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -108,7 +94,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
108
94
  requirements:
109
95
  - - ">="
110
96
  - !ruby/object:Gem::Version
111
- version: '0'
97
+ version: '2.1'
112
98
  required_rubygems_version: !ruby/object:Gem::Requirement
113
99
  requirements:
114
100
  - - ">="