tcp_messenger 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a275fadadf1b8c6dbfbd714fc5a8ddabe142af30
4
+ data.tar.gz: 42c5d4be0247e212352cc705f70ad245994b2fe3
5
+ SHA512:
6
+ metadata.gz: 33c311abd23ecaa1a261c86af77f8d9c17bb2fb26cd9923454a69c0ab81c674c555d3797e5c76181b5240ced19e38f886a600935542166246503205175048b6b
7
+ data.tar.gz: 203ed5eab208e686474dd529f04f5c72e6470f32dc6d52ed04487dd80a249d1440155c5b76d2f0eefc7e8620649080afe64522cd16ba3dad83ffcbbd7284e56f
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 Rob Fors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # TCP Messenger
2
+ Simple library to open/accept TCP connections and send/receive messages of strings over the connection.
@@ -0,0 +1,5 @@
1
+ module TCPMessenger
2
+ class ClosedError < StandardError
3
+
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module TCPMessenger
2
+ class ConnectionError < ClosedError
3
+
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ module TCPMessenger
2
+ class MessageTooLongError < StandardError
3
+
4
+ def initialize(message = "Message too long.")
5
+ super
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,90 @@
1
+ module TCPMessenger
2
+ class Messenger
3
+
4
+ def initialize(socket, duck_types: , max_message_length: )
5
+ @socket = socket
6
+ @max_message_length = max_message_length
7
+ @close_mutex = QuackConcurrency::ReentrantMutex.new(duck_types: duck_types)
8
+ @send_mutex = Mutex.new
9
+ @receive_mutex = Mutex.new
10
+ @closed = false
11
+ end
12
+
13
+ def close
14
+ @close_mutex.synchronize do
15
+ raise ClosedError if closed?
16
+ begin
17
+ @socket.close
18
+ rescue
19
+ raise ConnectionError
20
+ ensure
21
+ @closed = true
22
+ end
23
+ end
24
+ nil
25
+ end
26
+
27
+ def closed?
28
+ @closed
29
+ end
30
+
31
+ def send(message)
32
+ @send_mutex.synchronize do
33
+ raise ClosedError if closed?
34
+ raise "'message' must be a string." unless message.respond_to?(:to_s)
35
+ message = message.to_s
36
+ encoded_message = message.gsub("\n", '\n')
37
+ raise MessageTooLong if encoded_message.length > @max_message_length
38
+ begin
39
+ @socket.puts(encoded_message)
40
+ rescue
41
+ @close_mutex.synchronize do
42
+ raise ClosedError if closed?
43
+ close
44
+ raise ConnectionError
45
+ end
46
+ end
47
+ end
48
+ nil
49
+ end
50
+
51
+ def receive
52
+ @receive_mutex.synchronize do
53
+ encoded_message = ''
54
+ loop do
55
+ char = receive_byte
56
+ break if char == "\n"
57
+ binding.pry if char == nil
58
+ encoded_message << char
59
+ if encoded_message.length > @max_message_length
60
+ @close_mutex.synchronize { close unless closed? }
61
+ loop do
62
+ char = receive_byte
63
+ break if char == "\n"
64
+ end
65
+ raise MessageTooLong
66
+ end
67
+ end
68
+ message = encoded_message.gsub('\n', "\n")
69
+ return message
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def receive_byte
76
+ begin
77
+ char = @socket.getc
78
+ raise if char == nil
79
+ rescue
80
+ @close_mutex.synchronize do
81
+ raise ClosedError if closed?
82
+ close
83
+ raise ConnectionError
84
+ end
85
+ end
86
+ char
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,48 @@
1
+ module TCPMessenger
2
+ class Server
3
+
4
+ def initialize(tcp_server, duck_types: , max_message_length: )
5
+ @tcp_server = tcp_server
6
+ @duck_types = duck_types
7
+ @max_message_length = max_message_length
8
+ @close_mutex = QuackConcurrency::ReentrantMutex.new(duck_types: duck_types)
9
+ @accept_mutex = Mutex.new
10
+ @closed = false
11
+ end
12
+
13
+ def accept
14
+ @accept_mutex.synchronize do
15
+ raise ClosedError if closed?
16
+ begin
17
+ socket = @tcp_server.accept
18
+ rescue
19
+ @close_mutex.synchronize do
20
+ raise ClosedError if closed?
21
+ close
22
+ raise ConnectionError
23
+ end
24
+ end
25
+ return Messenger.new(socket, duck_types: @duck_types, max_message_length: @max_message_length)
26
+ end
27
+ end
28
+
29
+ def close
30
+ @close_mutex.synchronize do
31
+ raise ClosedError if closed?
32
+ begin
33
+ @tcp_server.close
34
+ rescue
35
+ raise ConnectionError
36
+ ensure
37
+ @closed = true
38
+ end
39
+ end
40
+ nil
41
+ end
42
+
43
+ def closed?
44
+ @closed
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,31 @@
1
+ require 'socket'
2
+ require 'io/wait'
3
+ require 'quack_concurrency'
4
+
5
+ require 'tcp_messenger/closed_error'
6
+ require 'tcp_messenger/connection_error'
7
+ require 'tcp_messenger/messenger'
8
+ require 'tcp_messenger/server'
9
+
10
+ module TCPMessenger
11
+
12
+ def self.connect(duck_types: {}, host: , max_message_length: Float::INFINITY, port: )
13
+ tcp_socket_class = duck_types[:tcp_socket] || TCPSocket
14
+ socket = tcp_socket_class.new(host, port)
15
+ Messenger.new(socket, duck_types: duck_types, max_message_length: max_message_length)
16
+ end
17
+
18
+ def self.listen(duck_types: {}, max_message_length: Float::INFINITY, port: )
19
+ tcp_server_class = duck_types[:tcp_server] || TCPServer
20
+ Server.new(tcp_server_class.new(port), duck_types: duck_types, max_message_length: max_message_length)
21
+ end
22
+
23
+ def self.accept(duck_types: {}, max_message_length: Float::INFINITY, port: )
24
+ tcp_server_class = duck_types[:tcp_server] || TCPServer
25
+ server = Server.new(tcp_server_class.new(port), duck_types: duck_types, max_message_length: max_message_length)
26
+ socket = server.accept
27
+ server.close
28
+ socket
29
+ end
30
+
31
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tcp_messenger
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Rob Fors
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-02-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: quack_concurrency
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.0.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.0.1
27
+ description: Simple library to open/accept TCP connections and send/receive messages
28
+ of strings over the connection.
29
+ email: mail@robfors.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - LICENSE
35
+ - README.md
36
+ - lib/tcp_messenger.rb
37
+ - lib/tcp_messenger/closed_error.rb
38
+ - lib/tcp_messenger/connection_error.rb
39
+ - lib/tcp_messenger/message_too_long_error.rb
40
+ - lib/tcp_messenger/messenger.rb
41
+ - lib/tcp_messenger/server.rb
42
+ homepage: https://github.com/robfors/ruby-tcp_messenger
43
+ licenses:
44
+ - MIT
45
+ metadata: {}
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ requirements: []
61
+ rubyforge_project:
62
+ rubygems_version: 2.4.8
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: Send messages over TCP connection.
66
+ test_files: []