rubysl-gserver 1.0.0 → 2.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 +4 -4
- data/.travis.yml +5 -6
- data/lib/rubysl/gserver/gserver.rb +77 -20
- data/lib/rubysl/gserver/version.rb +1 -1
- data/rubysl-gserver.gemspec +2 -3
- metadata +6 -20
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c66e019aa38de4678577becb51ea434ed86eb284
|
|
4
|
+
data.tar.gz: 4566b0d3787f35db9a222ea6d8e94860881fef1f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1121d30580a3695fb79ac3d6019502edb23ed7cef3fb810d727f09069abe17cff1e1a2e6832506aa70708f3d242671e766671d3592975dace394b7f7831e0ac1
|
|
7
|
+
data.tar.gz: 6a327e9484af7eeff55cfb874e320be054d5757272fb1747a2974c8dc8de4c5424dda6c9109f893419a3c7e3469e6cf58878e477bbc548586ee8a81afdc2ce6b
|
data/.travis.yml
CHANGED
|
@@ -4,16 +4,13 @@
|
|
|
4
4
|
# Author:: John W. Small
|
|
5
5
|
# Documentation:: Gavin Sinclair
|
|
6
6
|
# Licence:: Freeware.
|
|
7
|
-
#
|
|
8
|
-
# See the class GServer for documentation.
|
|
9
|
-
#
|
|
10
7
|
|
|
11
8
|
require "socket"
|
|
12
9
|
require "thread"
|
|
13
10
|
|
|
14
11
|
#
|
|
15
12
|
# GServer implements a generic server, featuring thread pool management,
|
|
16
|
-
# simple logging, and multi-server management. See HttpServer in
|
|
13
|
+
# simple logging, and multi-server management. See HttpServer in
|
|
17
14
|
# <tt>xmlrpc/httpserver.rb</tt> in the Ruby standard library for an example of
|
|
18
15
|
# GServer in action.
|
|
19
16
|
#
|
|
@@ -25,7 +22,7 @@ require "thread"
|
|
|
25
22
|
# you the effort. All events are optionally logged, but you can provide your
|
|
26
23
|
# own event handlers if you wish.
|
|
27
24
|
#
|
|
28
|
-
#
|
|
25
|
+
# == Example
|
|
29
26
|
#
|
|
30
27
|
# Using GServer is simple. Below we implement a simple time server, run it,
|
|
31
28
|
# query it, and shut it down. Try this code in +irb+:
|
|
@@ -34,30 +31,30 @@ require "thread"
|
|
|
34
31
|
#
|
|
35
32
|
# #
|
|
36
33
|
# # A server that returns the time in seconds since 1970.
|
|
37
|
-
# #
|
|
34
|
+
# #
|
|
38
35
|
# class TimeServer < GServer
|
|
39
36
|
# def initialize(port=10001, *args)
|
|
40
37
|
# super(port, *args)
|
|
41
38
|
# end
|
|
42
39
|
# def serve(io)
|
|
43
|
-
# io.puts(Time.now.
|
|
40
|
+
# io.puts(Time.now.to_s)
|
|
44
41
|
# end
|
|
45
42
|
# end
|
|
46
43
|
#
|
|
47
44
|
# # Run the server with logging enabled (it's a separate thread).
|
|
48
45
|
# server = TimeServer.new
|
|
49
46
|
# server.audit = true # Turn logging on.
|
|
50
|
-
# server.start
|
|
47
|
+
# server.start
|
|
51
48
|
#
|
|
52
49
|
# # *** Now point your browser to http://localhost:10001 to see it working ***
|
|
53
50
|
#
|
|
54
|
-
# # See if it's still running.
|
|
51
|
+
# # See if it's still running.
|
|
55
52
|
# GServer.in_service?(10001) # -> true
|
|
56
53
|
# server.stopped? # -> false
|
|
57
54
|
#
|
|
58
55
|
# # Shut the server down gracefully.
|
|
59
56
|
# server.shutdown
|
|
60
|
-
#
|
|
57
|
+
#
|
|
61
58
|
# # Alternatively, stop it immediately.
|
|
62
59
|
# GServer.stop(10001)
|
|
63
60
|
# # or, of course, "server.stop".
|
|
@@ -73,14 +70,14 @@ require "thread"
|
|
|
73
70
|
# other methods as well if you wish, perhaps to collect statistics, or emit
|
|
74
71
|
# more detailed logging.
|
|
75
72
|
#
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
#
|
|
79
|
-
#
|
|
73
|
+
# * #connecting
|
|
74
|
+
# * #disconnecting
|
|
75
|
+
# * #starting
|
|
76
|
+
# * #stopping
|
|
80
77
|
#
|
|
81
|
-
# The above methods are only called if auditing is enabled
|
|
78
|
+
# The above methods are only called if auditing is enabled, via #audit=.
|
|
82
79
|
#
|
|
83
|
-
# You can also override
|
|
80
|
+
# You can also override #log and #error if, for example, you wish to use a
|
|
84
81
|
# more sophisticated logging system.
|
|
85
82
|
#
|
|
86
83
|
class GServer
|
|
@@ -93,17 +90,28 @@ class GServer
|
|
|
93
90
|
@@services = {} # Hash of opened ports, i.e. services
|
|
94
91
|
@@servicesMutex = Mutex.new
|
|
95
92
|
|
|
93
|
+
# Stop the server running on the given port, bound to the given host
|
|
94
|
+
#
|
|
95
|
+
# +port+:: port, as a FixNum, of the server to stop
|
|
96
|
+
# +host+:: host on which to find the server to stop
|
|
96
97
|
def GServer.stop(port, host = DEFAULT_HOST)
|
|
97
98
|
@@servicesMutex.synchronize {
|
|
98
99
|
@@services[host][port].stop
|
|
99
100
|
}
|
|
100
101
|
end
|
|
101
102
|
|
|
103
|
+
# Check if a server is running on the given port and host
|
|
104
|
+
#
|
|
105
|
+
# +port+:: port, as a FixNum, of the server to check
|
|
106
|
+
# +host+:: host on which to find the server to check
|
|
107
|
+
#
|
|
108
|
+
# Returns true if a server is running on that port and host.
|
|
102
109
|
def GServer.in_service?(port, host = DEFAULT_HOST)
|
|
103
110
|
@@services.has_key?(host) and
|
|
104
111
|
@@services[host].has_key?(port)
|
|
105
112
|
end
|
|
106
113
|
|
|
114
|
+
# Stop the server
|
|
107
115
|
def stop
|
|
108
116
|
@connectionsMutex.synchronize {
|
|
109
117
|
if @tcpServerThread
|
|
@@ -112,25 +120,45 @@ class GServer
|
|
|
112
120
|
}
|
|
113
121
|
end
|
|
114
122
|
|
|
123
|
+
# Returns true if the server has stopped.
|
|
115
124
|
def stopped?
|
|
116
125
|
@tcpServerThread == nil
|
|
117
126
|
end
|
|
118
127
|
|
|
128
|
+
# Schedule a shutdown for the server
|
|
119
129
|
def shutdown
|
|
120
130
|
@shutdown = true
|
|
121
131
|
end
|
|
122
132
|
|
|
133
|
+
# Return the current number of connected clients
|
|
123
134
|
def connections
|
|
124
135
|
@connections.size
|
|
125
136
|
end
|
|
126
137
|
|
|
138
|
+
# Join with the server thread
|
|
127
139
|
def join
|
|
128
140
|
@tcpServerThread.join if @tcpServerThread
|
|
129
141
|
end
|
|
130
142
|
|
|
131
|
-
|
|
132
|
-
|
|
143
|
+
# Port on which to listen, as a FixNum
|
|
144
|
+
attr_reader :port
|
|
145
|
+
# Host on which to bind, as a String
|
|
146
|
+
attr_reader :host
|
|
147
|
+
# Maximum number of connections to accept at at ime, as a FixNum
|
|
148
|
+
attr_reader :maxConnections
|
|
149
|
+
# IO Device on which log messages should be written
|
|
150
|
+
attr_accessor :stdlog
|
|
151
|
+
# Set to true to cause the callbacks #connecting, #disconnecting, #starting,
|
|
152
|
+
# and #stopping to be called during the server's lifecycle
|
|
153
|
+
attr_accessor :audit
|
|
154
|
+
# Set to true to show more detailed logging
|
|
155
|
+
attr_accessor :debug
|
|
133
156
|
|
|
157
|
+
# Called when a client connects, if auditing is enabled.
|
|
158
|
+
#
|
|
159
|
+
# +client+:: a TCPSocket instances representing the client that connected
|
|
160
|
+
#
|
|
161
|
+
# Return true to allow this client to connect, false to prevent it.
|
|
134
162
|
def connecting(client)
|
|
135
163
|
addr = client.peeraddr
|
|
136
164
|
log("#{self.class.to_s} #{@host}:#{@port} client:#{addr[1]} " +
|
|
@@ -138,6 +166,10 @@ class GServer
|
|
|
138
166
|
true
|
|
139
167
|
end
|
|
140
168
|
|
|
169
|
+
|
|
170
|
+
# Called when a client disconnects, if audition is enabled.
|
|
171
|
+
#
|
|
172
|
+
# +clientPort+:: the port of the client that is connecting
|
|
141
173
|
def disconnecting(clientPort)
|
|
142
174
|
log("#{self.class.to_s} #{@host}:#{@port} " +
|
|
143
175
|
"client:#{clientPort} disconnect")
|
|
@@ -145,20 +177,30 @@ class GServer
|
|
|
145
177
|
|
|
146
178
|
protected :connecting, :disconnecting
|
|
147
179
|
|
|
180
|
+
# Called when the server is starting up, if auditing is enabled.
|
|
148
181
|
def starting()
|
|
149
182
|
log("#{self.class.to_s} #{@host}:#{@port} start")
|
|
150
183
|
end
|
|
151
184
|
|
|
185
|
+
# Called when the server is shutting down, if auditing is enabled.
|
|
152
186
|
def stopping()
|
|
153
187
|
log("#{self.class.to_s} #{@host}:#{@port} stop")
|
|
154
188
|
end
|
|
155
189
|
|
|
156
190
|
protected :starting, :stopping
|
|
157
191
|
|
|
192
|
+
# Called if #debug is true whenever an unhandled exception is raised.
|
|
193
|
+
# This implementation simply logs the backtrace.
|
|
194
|
+
#
|
|
195
|
+
# +detail+:: The Exception that was caught
|
|
158
196
|
def error(detail)
|
|
159
197
|
log(detail.backtrace.join("\n"))
|
|
160
198
|
end
|
|
161
199
|
|
|
200
|
+
# Log a message to #stdlog, if it's defined. This implementation
|
|
201
|
+
# outputs the timestamp and message to the log.
|
|
202
|
+
#
|
|
203
|
+
# +msg+:: the message to log
|
|
162
204
|
def log(msg)
|
|
163
205
|
if @stdlog
|
|
164
206
|
@stdlog.puts("[#{Time.new.ctime}] %s" % msg)
|
|
@@ -168,6 +210,15 @@ class GServer
|
|
|
168
210
|
|
|
169
211
|
protected :error, :log
|
|
170
212
|
|
|
213
|
+
# Create a new server
|
|
214
|
+
#
|
|
215
|
+
# +port+:: the port, as a FixNum, on which to listen.
|
|
216
|
+
# +host+:: the host to bind to
|
|
217
|
+
# +maxConnections+:: The maximum number of simultaneous connections to
|
|
218
|
+
# accept
|
|
219
|
+
# +stdlog+:: IO device on which to log messages
|
|
220
|
+
# +audit+:: if true, lifecycle callbacks will be called. See #audit
|
|
221
|
+
# +debug+:: if true, error messages are logged. See #debug
|
|
171
222
|
def initialize(port, host = DEFAULT_HOST, maxConnections = 4,
|
|
172
223
|
stdlog = $stderr, audit = false, debug = false)
|
|
173
224
|
@tcpServerThread = nil
|
|
@@ -182,8 +233,13 @@ class GServer
|
|
|
182
233
|
@debug = debug
|
|
183
234
|
end
|
|
184
235
|
|
|
236
|
+
# Start the server if it isn't already running
|
|
237
|
+
#
|
|
238
|
+
# +maxConnections+::
|
|
239
|
+
# override +maxConnections+ given to the constructor. A negative
|
|
240
|
+
# value indicates that the value from the constructor should be used.
|
|
185
241
|
def start(maxConnections = -1)
|
|
186
|
-
raise "running" if !stopped?
|
|
242
|
+
raise "server is already running" if !stopped?
|
|
187
243
|
@shutdown = false
|
|
188
244
|
@maxConnections = maxConnections if maxConnections > 0
|
|
189
245
|
@@servicesMutex.synchronize {
|
|
@@ -205,7 +261,8 @@ class GServer
|
|
|
205
261
|
end
|
|
206
262
|
}
|
|
207
263
|
client = @tcpServer.accept
|
|
208
|
-
|
|
264
|
+
Thread.new(client) { |myClient|
|
|
265
|
+
@connections << Thread.current
|
|
209
266
|
begin
|
|
210
267
|
myPort = myClient.peeraddr[1]
|
|
211
268
|
serve(myClient) if !@audit or connecting(myClient)
|
data/rubysl-gserver.gemspec
CHANGED
|
@@ -16,11 +16,10 @@ Gem::Specification.new do |spec|
|
|
|
16
16
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
17
17
|
spec.require_paths = ["lib"]
|
|
18
18
|
|
|
19
|
-
spec.add_runtime_dependency "rubysl-socket", "~>
|
|
20
|
-
spec.add_runtime_dependency "rubysl-thread", "~>
|
|
19
|
+
spec.add_runtime_dependency "rubysl-socket", "~> 2.0"
|
|
20
|
+
spec.add_runtime_dependency "rubysl-thread", "~> 2.0"
|
|
21
21
|
|
|
22
22
|
spec.add_development_dependency "bundler", "~> 1.3"
|
|
23
23
|
spec.add_development_dependency "rake", "~> 10.0"
|
|
24
24
|
spec.add_development_dependency "mspec", "~> 1.5"
|
|
25
|
-
spec.add_development_dependency "rubysl-prettyprint", "~> 1.0"
|
|
26
25
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubysl-gserver
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brian Shirai
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2013-
|
|
11
|
+
date: 2013-09-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rubysl-socket
|
|
@@ -16,28 +16,28 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ~>
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
19
|
+
version: '2.0'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ~>
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
26
|
+
version: '2.0'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: rubysl-thread
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - ~>
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
33
|
+
version: '2.0'
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - ~>
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
40
|
+
version: '2.0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: bundler
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -80,20 +80,6 @@ dependencies:
|
|
|
80
80
|
- - ~>
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '1.5'
|
|
83
|
-
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: rubysl-prettyprint
|
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
|
86
|
-
requirements:
|
|
87
|
-
- - ~>
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '1.0'
|
|
90
|
-
type: :development
|
|
91
|
-
prerelease: false
|
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
-
requirements:
|
|
94
|
-
- - ~>
|
|
95
|
-
- !ruby/object:Gem::Version
|
|
96
|
-
version: '1.0'
|
|
97
83
|
description: Ruby standard library gserver.
|
|
98
84
|
email:
|
|
99
85
|
- brixen@gmail.com
|