rubysl-gserver 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|