async_tcpsocket 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 +15 -0
- data/lib/async_tcpsocket.rb +148 -0
- metadata +65 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZWJlMmUxZDYzMzJmMDliZjQwOTQ3NDZiYWNjMDk2ZjkxZDgwNWQ4ZA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
M2JjNzY2ZjYxMDQzNGRiMmJhOTE3YmRmOTEwYzZlYTA5MmY3N2UwNw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NWQ0NjVlZmUyOTMyNTUxNThlYmRmNDI1NzQ3ZWIyMGZhOTg1MzVhOGY5YmI5
|
10
|
+
ZGQ0NTgwMGM3YmYyNTViY2MxYmQyZTZiOTU5ZjM2MWE5MTc4NTNjMTRiNDBk
|
11
|
+
MzMwNTI1ZDljNjJkOTU2Y2IyMThhM2QzNDkzODgyM2JjYzE3NDA=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZmY5MjYzNTNlYmE5NjEwNWMxODRjMWNmMjc3OTA0MzA2NDYyZDg4NTgxZWM4
|
14
|
+
MjExZTc2ZGY1NmI3ZjYyYTc1NDYyZDYwNDYwZWY4NDQyM2JkMTY3ZDg4ZWY4
|
15
|
+
YjhmZjBhMTY1YTI2ZjBmODZiMDY2MjQ2NjFiZGUxYmE4ZjU0NzY=
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'thread'
|
3
|
+
require 'async_emitter'
|
4
|
+
|
5
|
+
#######################################################################
|
6
|
+
# An asyncronous TCP socket implementation (wraps TCPSocket)
|
7
|
+
#
|
8
|
+
# Inherits AsyncEmitter and emits three events, :data, :close and :error.
|
9
|
+
# :data is emitted when data is recieved,
|
10
|
+
# :close is emitted if the other side closes the connection and it is detected,
|
11
|
+
# :error emits errors
|
12
|
+
#
|
13
|
+
# ==Example
|
14
|
+
#
|
15
|
+
# require 'async_tcpsocket'
|
16
|
+
#
|
17
|
+
# socket = AsyncTCPSocket.new
|
18
|
+
#
|
19
|
+
# socket.once :error, Proc.new { |err|
|
20
|
+
# STDERR.puts "Error: #{err}"
|
21
|
+
# socket.close
|
22
|
+
# }
|
23
|
+
#
|
24
|
+
# socket.once :close, Proc.new { |err|
|
25
|
+
# socket.close
|
26
|
+
# }
|
27
|
+
#
|
28
|
+
# socket.on :data, Proc.new { |data|
|
29
|
+
# puts "#{data}"
|
30
|
+
# }
|
31
|
+
#
|
32
|
+
# socket.connect 'localhost', 80
|
33
|
+
# socket.puts "GET / HTTP 1.1\r\n\r\n"
|
34
|
+
#
|
35
|
+
# #wait for return key
|
36
|
+
# gets
|
37
|
+
#
|
38
|
+
# socket.close
|
39
|
+
#
|
40
|
+
# @author Greg Martin
|
41
|
+
##########################################################################
|
42
|
+
class AsyncTCPSocket < AsyncEmitter
|
43
|
+
|
44
|
+
#################################################################
|
45
|
+
# constructor
|
46
|
+
#
|
47
|
+
# @param socket [TCPSocket] or nil
|
48
|
+
#################################################################
|
49
|
+
def initialize (socket=nil)
|
50
|
+
super()
|
51
|
+
@socket = socket
|
52
|
+
@write_data = nil
|
53
|
+
@write_semaphore = Mutex.new
|
54
|
+
@write_cv = ConditionVariable.new
|
55
|
+
|
56
|
+
if socket != nil
|
57
|
+
threads
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
#################################################################
|
62
|
+
# connect to a server - if the socket is already connected it
|
63
|
+
# will be closed
|
64
|
+
#
|
65
|
+
# @param host [String] the server host address
|
66
|
+
# @param port [FixedNum] the server port
|
67
|
+
#################################################################
|
68
|
+
def connect (host, port)
|
69
|
+
close
|
70
|
+
|
71
|
+
begin
|
72
|
+
@socket = TCPSocket.new host, port
|
73
|
+
rescue Exception => e
|
74
|
+
emit :error, e
|
75
|
+
end
|
76
|
+
|
77
|
+
threads
|
78
|
+
end
|
79
|
+
|
80
|
+
################################################################
|
81
|
+
# closes the connection
|
82
|
+
###############################################################
|
83
|
+
def close
|
84
|
+
if @socket != nil
|
85
|
+
@socket.close
|
86
|
+
Thread.kill @read_thread
|
87
|
+
Thread.kill @write_thread
|
88
|
+
@socket = nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
################################################################
|
93
|
+
# sends data asyncronously - non-string objects will need to be
|
94
|
+
# serialized
|
95
|
+
#
|
96
|
+
# @param data [Object] - the data to send
|
97
|
+
# #############################################################
|
98
|
+
def puts data
|
99
|
+
@write_semaphore.synchronize do
|
100
|
+
@write_data = data
|
101
|
+
@write_cv.signal
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
protected
|
106
|
+
def threads
|
107
|
+
init_sem = Mutex.new
|
108
|
+
cv = ConditionVariable.new
|
109
|
+
|
110
|
+
@read_thread = Thread.new do
|
111
|
+
loop do
|
112
|
+
data = @socket.gets
|
113
|
+
if data == nil
|
114
|
+
e = Exception.exception ("socket closed")
|
115
|
+
emit :close, e
|
116
|
+
break
|
117
|
+
else
|
118
|
+
emit :data, data
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
@write_thread = Thread.new do
|
124
|
+
loop do
|
125
|
+
@write_semaphore.synchronize do
|
126
|
+
init_sem.synchronize do
|
127
|
+
cv.signal
|
128
|
+
end
|
129
|
+
|
130
|
+
@write_cv.wait @write_semaphore
|
131
|
+
begin
|
132
|
+
@socket.puts @write_data
|
133
|
+
rescue Exception => e
|
134
|
+
emit :error, e
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
init_sem.synchronize do
|
142
|
+
cv.wait init_sem
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: async_tcpsocket
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Greg Martin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: async_emitter
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.1'
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.1.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.1'
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.1.1
|
33
|
+
description: An asyncronous tcp socket for ruby
|
34
|
+
email: greg@softsprocket.com
|
35
|
+
executables: []
|
36
|
+
extensions: []
|
37
|
+
extra_rdoc_files: []
|
38
|
+
files:
|
39
|
+
- lib/async_tcpsocket.rb
|
40
|
+
homepage: http://rubygems.org/gems/async_tcpsocket.rb
|
41
|
+
licenses:
|
42
|
+
- MIT
|
43
|
+
metadata: {}
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
requirements: []
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 2.4.6
|
61
|
+
signing_key:
|
62
|
+
specification_version: 4
|
63
|
+
summary: AsyncTCPServer
|
64
|
+
test_files: []
|
65
|
+
has_rdoc:
|