vcs 0.1 → 0.2.148
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.
- data/Rakefile +17 -3
- data/bin/vcs +57 -34
- data/doc/jamis.rb +564 -0
- data/ruby_ex/abstract.rb +254 -0
- data/ruby_ex/abstract_node.rb +85 -0
- data/ruby_ex/algorithms/simulated_annealing.rb +140 -0
- data/ruby_ex/array_each_pair.rb +18 -0
- data/ruby_ex/ask.rb +101 -0
- data/ruby_ex/attributed_class.rb +302 -0
- data/ruby_ex/cache.rb +373 -0
- data/ruby_ex/checkout.rb +12 -0
- data/ruby_ex/choose.rb +271 -0
- data/ruby_ex/commands.rb +18 -0
- data/ruby_ex/commands/command.rb +401 -0
- data/ruby_ex/commands/datas.rb +16 -0
- data/ruby_ex/commands/datas/data.rb +33 -0
- data/ruby_ex/commands/datas/factory.rb +66 -0
- data/ruby_ex/commands/factory.rb +66 -0
- data/ruby_ex/commands/helpers.rb +67 -0
- data/ruby_ex/commands/pipe.rb +64 -0
- data/ruby_ex/commands/runners.rb +17 -0
- data/ruby_ex/commands/runners/exec.rb +49 -0
- data/ruby_ex/commands/runners/fork.rb +97 -0
- data/ruby_ex/commands/runners/runner.rb +107 -0
- data/ruby_ex/commands/seq.rb +27 -0
- data/ruby_ex/config_file.rb +96 -0
- data/ruby_ex/const_regexp.rb +59 -0
- data/ruby_ex/daemon.rb +134 -0
- data/ruby_ex/diff.rb +667 -0
- data/ruby_ex/dlogger.rb +62 -0
- data/ruby_ex/drb/dispatcher.rb +252 -0
- data/ruby_ex/drb/dispatcher_server_test.rb +29 -0
- data/ruby_ex/drb/drb_observable.rb +97 -0
- data/ruby_ex/drb/drb_observable_pool.rb +27 -0
- data/ruby_ex/drb/drb_service.rb +43 -0
- data/ruby_ex/drb/drb_undumped_attributes.rb +55 -0
- data/ruby_ex/drb/drb_undumped_indexed_object.rb +54 -0
- data/ruby_ex/drb/insecure_protected_methods.rb +103 -0
- data/ruby_ex/drb/session_client_test.rb +40 -0
- data/ruby_ex/drb/session_manager.rb +246 -0
- data/ruby_ex/drb/session_server.rb +53 -0
- data/ruby_ex/dtime.rb +143 -0
- data/ruby_ex/dumpable_proc.rb +63 -0
- data/ruby_ex/exception.rb +32 -0
- data/ruby_ex/filetype.rb +229 -0
- data/ruby_ex/fileutils_ex.rb +44 -0
- data/ruby_ex/fold.rb +58 -0
- data/ruby_ex/generate_id.rb +44 -0
- data/ruby_ex/hookable.rb +262 -0
- data/ruby_ex/hooker.rb +54 -0
- data/ruby_ex/inactive_timeout.rb +137 -0
- data/ruby_ex/indexed_node.rb +66 -0
- data/ruby_ex/io_marshal.rb +100 -0
- data/ruby_ex/ioo.rb +194 -0
- data/ruby_ex/labeled_node.rb +63 -0
- data/ruby_ex/logger_observer.rb +23 -0
- data/ruby_ex/md5sum.rb +66 -0
- data/ruby_ex/mktemp.rb +208 -0
- data/ruby_ex/module/attr_once.rb +36 -0
- data/ruby_ex/module/autoload_tree.rb +75 -0
- data/ruby_ex/module/hierarchy.rb +335 -0
- data/ruby_ex/module/instance_method_visibility.rb +73 -0
- data/ruby_ex/module_ex.rb +11 -0
- data/ruby_ex/node.rb +80 -0
- data/ruby_ex/object_monitor.rb +145 -0
- data/ruby_ex/object_monitor_activity.rb +33 -0
- data/ruby_ex/observable.rb +140 -0
- data/ruby_ex/observable_pool.rb +293 -0
- data/ruby_ex/orderedhash.rb +252 -0
- data/ruby_ex/pathname_ex.rb +152 -0
- data/ruby_ex/pp_hierarchy.rb +29 -0
- data/ruby_ex/pseudo_cache.rb +190 -0
- data/ruby_ex/queue.rb +56 -0
- data/ruby_ex/random_generators.rb +25 -0
- data/ruby_ex/random_generators/random_generator.rb +31 -0
- data/ruby_ex/random_generators/ruby.rb +23 -0
- data/ruby_ex/safe_eval.rb +348 -0
- data/ruby_ex/sendmail.rb +215 -0
- data/ruby_ex/service_manager.rb +121 -0
- data/ruby_ex/session/administrable.rb +120 -0
- data/ruby_ex/session/client.rb +153 -0
- data/ruby_ex/session/const.rb +18 -0
- data/ruby_ex/session/dispatcher.rb +184 -0
- data/ruby_ex/session/error.rb +21 -0
- data/ruby_ex/session/fetchable.rb +57 -0
- data/ruby_ex/session/fetcher.rb +62 -0
- data/ruby_ex/session/hookable.rb +26 -0
- data/ruby_ex/session/profile.rb +110 -0
- data/ruby_ex/session/server.rb +582 -0
- data/ruby_ex/session/test/administrable_test.rb +337 -0
- data/ruby_ex/session/test/basic_test.rb +523 -0
- data/ruby_ex/session/test/dispatcher_test.rb +409 -0
- data/ruby_ex/session/test/fetchable_test.rb +119 -0
- data/ruby_ex/session/test/sub_server_test.rb +188 -0
- data/ruby_ex/shuffle.rb +30 -0
- data/ruby_ex/spring.rb +136 -0
- data/ruby_ex/spring_set.rb +137 -0
- data/ruby_ex/string_ex.rb +28 -0
- data/ruby_ex/symtbl.rb +106 -0
- data/ruby_ex/synflow.rb +474 -0
- data/ruby_ex/test/unit/ui/yaml/testrunner.rb +164 -0
- data/ruby_ex/thread_mutex.rb +10 -0
- data/ruby_ex/timeout_ex.rb +81 -0
- data/ruby_ex/top_down.rb +73 -0
- data/ruby_ex/trace.rb +26 -0
- data/ruby_ex/uri/druby.rb +81 -0
- data/ruby_ex/uri/file.rb +65 -0
- data/ruby_ex/uri/ftp_ex.rb +37 -0
- data/ruby_ex/uri/http_ex.rb +43 -0
- data/ruby_ex/uri/ssh.rb +92 -0
- data/ruby_ex/uri/svn.rb +118 -0
- data/ruby_ex/uri_ex.rb +45 -0
- data/ruby_ex/verbose_object.rb +30 -0
- data/ruby_ex/version.rb +66 -0
- data/ruby_ex/yaml/basenode_ext.rb +63 -0
- data/ruby_ex/yaml/chop_header.rb +23 -0
- data/ruby_ex/yaml/transform.rb +449 -0
- data/ruby_ex/yaml/yregexpath.rb +76 -0
- data/src/changelog.rb +28 -18
- data/src/conflict.rb +20 -0
- data/src/diff.rb +18 -0
- data/src/diffstat.rb +9 -3
- data/src/last_changed_date.rb +18 -0
- data/src/mail.rb +33 -65
- data/src/message.rb +15 -9
- data/src/mycommit.rb +29 -14
- data/src/news.rb +24 -3
- data/src/status.rb +17 -0
- data/src/svn.rb +2 -2
- data/src/vcs.rb +24 -3
- metadata +124 -5
- data/lrdetools.rb +0 -12
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Copyright: Copyright (c) 2004 Nicolas Despres. All rights reserved.
|
|
2
|
+
# Author: Nicolas Despres <polrop@lrde.epita.fr>.
|
|
3
|
+
# License: Gnu General Public License.
|
|
4
|
+
|
|
5
|
+
# $LastChangedBy: ertai $
|
|
6
|
+
# $Id: hookable.rb 53 2004-12-02 22:24:03Z ertai $
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
require 'drb'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
module Session
|
|
13
|
+
|
|
14
|
+
module Hookable
|
|
15
|
+
include DRb::DRbUndumped
|
|
16
|
+
|
|
17
|
+
def hook(sid, profile, request, *args)
|
|
18
|
+
meth = "hook_#{request}"
|
|
19
|
+
if protected_methods.include?(meth)
|
|
20
|
+
send(meth.to_sym, sid, profile, *args)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end # module Hook
|
|
25
|
+
|
|
26
|
+
end # module Session
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Copyright: Copyright (c) 2004 Nicolas Despres. All rights reserved.
|
|
2
|
+
# Author: Nicolas Despres <polrop@lrde.epita.fr>.
|
|
3
|
+
# License: Gnu General Public License.
|
|
4
|
+
|
|
5
|
+
# $LastChangedBy: polrop $
|
|
6
|
+
# $Id: profile.rb 70 2004-12-07 17:44:50Z polrop $
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
require 'drb'
|
|
10
|
+
|
|
11
|
+
require 'const_regexp'
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
module Session
|
|
15
|
+
|
|
16
|
+
class Profile
|
|
17
|
+
|
|
18
|
+
attr_reader :data
|
|
19
|
+
|
|
20
|
+
def initialize(usrname, usrdesc, uri, dispatcher, *hooks)
|
|
21
|
+
@data = usrdesc.dup
|
|
22
|
+
@data[:usrname] = usrname
|
|
23
|
+
@data[:login_time] = Time.now
|
|
24
|
+
@data[:last_request_time] = Time.now
|
|
25
|
+
@data[:uri] = uri
|
|
26
|
+
uri_chunks = Profile.parse_uri(uri)
|
|
27
|
+
@data[:protocol], @data[:hostname], @data[:port] = *uri_chunks
|
|
28
|
+
@data[:hooks] = hooks
|
|
29
|
+
@data[:nb_requests] = 0
|
|
30
|
+
@data[:dispatcher] = dispatcher
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def Profile.parse_uri(uri)
|
|
34
|
+
return $1, $2, $3.to_i if uri =~ ConstRegexp::DRB_URI
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def _dump(depth)
|
|
38
|
+
data = {}
|
|
39
|
+
@data.each do |key, val|
|
|
40
|
+
begin
|
|
41
|
+
data[key] = Marshal.dump(val)
|
|
42
|
+
rescue TypeError
|
|
43
|
+
data[key] = Marshal.dump(DRbObject.new(val))
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
Marshal.dump([self.class, data])
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self._load(data)
|
|
50
|
+
klass, data = Marshal.load(data)
|
|
51
|
+
obj = klass.new(data[:usrname],
|
|
52
|
+
{},
|
|
53
|
+
data[:uri],
|
|
54
|
+
nil,
|
|
55
|
+
nil)
|
|
56
|
+
data.each do |attr, value|
|
|
57
|
+
obj[attr] = Marshal.load(value)
|
|
58
|
+
end
|
|
59
|
+
obj
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def [](key)
|
|
63
|
+
@data[key]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def []=(key, value)
|
|
67
|
+
@data[key] = value
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def to_hash
|
|
71
|
+
@data.dup
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def each
|
|
75
|
+
@data.each { |k, v| yield(k, v) }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def allowed_request?(request)
|
|
79
|
+
return true if @data[:admin]
|
|
80
|
+
@data[:allowed_requests].include?(request)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def add_request(request)
|
|
84
|
+
unless @data[:allowed_requests].include?(request)
|
|
85
|
+
@data[:allowed_requests] << request
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def allowed_hook?(hook)
|
|
90
|
+
return true if @data[:admin]
|
|
91
|
+
@data[:allowed_hooks].include?(hook)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def add_client(uri, client_class, *args)
|
|
95
|
+
@data[:dispatcher].add(uri,
|
|
96
|
+
@data[:usrname],
|
|
97
|
+
@data[:passwd],
|
|
98
|
+
client_class,
|
|
99
|
+
*args)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def del_client(uri)
|
|
103
|
+
@data[:dispatcher].del(uri)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
end # class Profile
|
|
107
|
+
|
|
108
|
+
end # class Session
|
|
109
|
+
|
|
110
|
+
|
|
@@ -0,0 +1,582 @@
|
|
|
1
|
+
# Copyright: Copyright (c) 2004 Nicolas Despres. All rights reserved.
|
|
2
|
+
# Author: Nicolas Despres <polrop@lrde.epita.fr>.
|
|
3
|
+
# License: Gnu General Public License.
|
|
4
|
+
|
|
5
|
+
# $LastChangedBy: ertai $
|
|
6
|
+
# $Id: server.rb 186 2005-04-03 00:07:45Z ertai $
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
require 'drb'
|
|
10
|
+
|
|
11
|
+
require 'generate_id'
|
|
12
|
+
require 'const_regexp'
|
|
13
|
+
require 'drb/insecure_protected_methods'
|
|
14
|
+
require 'session/profile'
|
|
15
|
+
require 'session/dispatcher'
|
|
16
|
+
require 'session/const'
|
|
17
|
+
require 'session/error'
|
|
18
|
+
require 'exception'
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
module Session
|
|
22
|
+
|
|
23
|
+
class Server
|
|
24
|
+
include DRb::DRbUndumped
|
|
25
|
+
|
|
26
|
+
#
|
|
27
|
+
# Constants
|
|
28
|
+
#
|
|
29
|
+
MIN_USR = 1
|
|
30
|
+
MIN_WIPEOUT_DELAY = 2 # seconds
|
|
31
|
+
USRDB = {
|
|
32
|
+
'root' => {
|
|
33
|
+
:passwd => 'root'.crypt(Const::SALT_KEY),
|
|
34
|
+
:admin => true,
|
|
35
|
+
:allowed_requests => [],
|
|
36
|
+
:allowed_hooks => []
|
|
37
|
+
},
|
|
38
|
+
'admin' => {
|
|
39
|
+
:passwd => 'admin'.crypt(Const::SALT_KEY),
|
|
40
|
+
:admin => true,
|
|
41
|
+
:allowed_requests => [],
|
|
42
|
+
:allowed_hooks => []
|
|
43
|
+
},
|
|
44
|
+
'guest' => {
|
|
45
|
+
:passwd => 'guest'.crypt(Const::SALT_KEY),
|
|
46
|
+
:admin => false,
|
|
47
|
+
:allowed_requests => [
|
|
48
|
+
:profile, :help, :nb_requests, :ping
|
|
49
|
+
],
|
|
50
|
+
:allowed_hooks => []
|
|
51
|
+
},
|
|
52
|
+
'anonymous' => {
|
|
53
|
+
:passwd => 'anonymous'.crypt(Const::SALT_KEY),
|
|
54
|
+
:admin => false,
|
|
55
|
+
:allowed_requests => [
|
|
56
|
+
:profile, :help, :nb_requests, :ping
|
|
57
|
+
],
|
|
58
|
+
:allowed_hooks => []
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
MAX_USR = 10
|
|
62
|
+
WIPEOUT_DELAY = 60 # seconds
|
|
63
|
+
PROFILE_CLASS = Profile
|
|
64
|
+
MAX_DISPATCHER_JOBS = 1
|
|
65
|
+
OPTS = {
|
|
66
|
+
:usrdb => USRDB,
|
|
67
|
+
:max_usr => MAX_USR,
|
|
68
|
+
:wipeout_delay => WIPEOUT_DELAY,
|
|
69
|
+
:profile_class => PROFILE_CLASS,
|
|
70
|
+
:max_dispatcher_jobs => MAX_DISPATCHER_JOBS
|
|
71
|
+
}
|
|
72
|
+
REQUEST_REGEXP = /^request_/
|
|
73
|
+
REQUESTS_DESC = { #FIXME: write description for all the request
|
|
74
|
+
'logout' => 'disconnect from the server',
|
|
75
|
+
'help' => '[requests...] return all or several request descriptions',
|
|
76
|
+
'profile' => 'return the session profile'
|
|
77
|
+
}
|
|
78
|
+
USRNAME_REGEXP = /^[A-Za-z0-9_]+$/
|
|
79
|
+
PASSWD_REGEXP = ConstRegexp::CRYPTED_STRING
|
|
80
|
+
SID_REGEXP = /^[a-f0-9]{16}$/
|
|
81
|
+
|
|
82
|
+
#
|
|
83
|
+
# Constructor
|
|
84
|
+
#
|
|
85
|
+
def initialize(opts=OPTS)
|
|
86
|
+
@nb_requests = 0
|
|
87
|
+
@opts = opts
|
|
88
|
+
@mutex = Mutex.new
|
|
89
|
+
@usrdb = check_usrdb(opts[:usrdb])
|
|
90
|
+
@max_usr = check_max_usr(opts[:max_usr])
|
|
91
|
+
@wipeout_delay = check_wipeout_delay(opts[:wipeout_delay])
|
|
92
|
+
@profile_class = opts[:profile_class]
|
|
93
|
+
@max_dispatcher_jobs = opts[:max_dispatcher_jobs]
|
|
94
|
+
@sessions = {}
|
|
95
|
+
@thread = Thread.new do
|
|
96
|
+
loop do
|
|
97
|
+
sleep_time = MIN_WIPEOUT_DELAY
|
|
98
|
+
@mutex.synchronize { sleep_time = @wipeout_delay }
|
|
99
|
+
sleep(sleep_time)
|
|
100
|
+
wipeout
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
@detached = false
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
#
|
|
107
|
+
# Requests
|
|
108
|
+
#
|
|
109
|
+
def login(usrname, passwd, uri, *hooks)
|
|
110
|
+
sid = nil
|
|
111
|
+
profile = nil
|
|
112
|
+
@mutex.synchronize do
|
|
113
|
+
check_usrname(usrname)
|
|
114
|
+
check_passwd(passwd)
|
|
115
|
+
usr = authentification(usrname, passwd)
|
|
116
|
+
if usr.nil?
|
|
117
|
+
raise(AuthError, "#{usrname}:#{passwd} authentification failed")
|
|
118
|
+
end
|
|
119
|
+
hooks.each { |hook| check_hook(hook) }
|
|
120
|
+
usr_name, usr_desc = usr
|
|
121
|
+
dispatcher = Dispatcher.new({}, @max_dispatcher_jobs, Client)
|
|
122
|
+
profile = @profile_class.new(usr_name,
|
|
123
|
+
usr_desc,
|
|
124
|
+
uri,
|
|
125
|
+
dispatcher,
|
|
126
|
+
*hooks)
|
|
127
|
+
if @sessions.size >= @max_usr and (not profile[:admin])
|
|
128
|
+
raise(FullError, "server full")
|
|
129
|
+
end
|
|
130
|
+
sid = generate_id { |id| @sessions.has_key?(id) }
|
|
131
|
+
@sessions[sid] = profile
|
|
132
|
+
end
|
|
133
|
+
call_all_hooks(sid, profile, :login)
|
|
134
|
+
sid
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def request(sid, request, *args, &block)
|
|
138
|
+
check_sid(sid)
|
|
139
|
+
profile = nil
|
|
140
|
+
req_name = nil
|
|
141
|
+
@mutex.synchronize do
|
|
142
|
+
profile = get_profile(sid)
|
|
143
|
+
req_name = check_request(request)
|
|
144
|
+
check_request_permission(profile, request)
|
|
145
|
+
@nb_requests += 1
|
|
146
|
+
profile[:nb_requests] += 1
|
|
147
|
+
end
|
|
148
|
+
ret = send(req_name.to_sym, sid, profile, *args, &block)
|
|
149
|
+
call_allowed_hooks(sid, profile, request, *args)
|
|
150
|
+
@mutex.synchronize do
|
|
151
|
+
profile[:last_request_time] = Time.now
|
|
152
|
+
@nb_requests -= 1
|
|
153
|
+
profile[:nb_requests] -= 1
|
|
154
|
+
end
|
|
155
|
+
ret
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
#
|
|
159
|
+
# Session-oriented requests
|
|
160
|
+
#
|
|
161
|
+
protected
|
|
162
|
+
def request_logout(sid, profile)
|
|
163
|
+
@mutex.synchronize { logout(sid, profile) }
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
protected
|
|
167
|
+
def request_ping(sid, profile, data)
|
|
168
|
+
data
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
protected
|
|
172
|
+
def request_help(sid, profile, *args)
|
|
173
|
+
res = {}
|
|
174
|
+
args_str = []
|
|
175
|
+
args.each { |arg| args_str << arg.to_s }
|
|
176
|
+
protected_methods.each do |meth|
|
|
177
|
+
meth_str = meth.to_s
|
|
178
|
+
next unless meth_str =~ REQUEST_REGEXP
|
|
179
|
+
m = meth_str.sub(REQUEST_REGEXP, '')
|
|
180
|
+
next if (not args_str.empty?) and (not args_str.include?(m))
|
|
181
|
+
if REQUESTS_DESC.has_key?(m)
|
|
182
|
+
res[m] = REQUESTS_DESC[m]
|
|
183
|
+
else
|
|
184
|
+
res[m] = 'no description available'
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
res
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
protected
|
|
191
|
+
def request_profile(sid, profile)
|
|
192
|
+
@mutex.synchronize { profile }
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
protected
|
|
196
|
+
def request_get_usr_profile(sid, profile, usrname)
|
|
197
|
+
@mutex.synchronize do
|
|
198
|
+
@sessions.values.each { |prof| return prof if usrname == prof[:usrname] }
|
|
199
|
+
end
|
|
200
|
+
raise(UserError, "`#{usrname}' - not logged user")
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
protected
|
|
204
|
+
def request_nb_requests(sid, profile)
|
|
205
|
+
@mutex.synchronize { profile[:nb_requests] }
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
protected
|
|
209
|
+
def request_total_nb_requests(sid, profile)
|
|
210
|
+
@mutex.synchronize { @nb_requests }
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
protected
|
|
214
|
+
def request_add_hook(sid, profile, *hooks)
|
|
215
|
+
@mutex.synchronize do
|
|
216
|
+
hooks.each do |hook|
|
|
217
|
+
check_hook(hook)
|
|
218
|
+
profile[:hooks] << hook
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
nil
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
protected
|
|
225
|
+
def request_del_hook(sid, profile, hook)
|
|
226
|
+
@mutex.synchronize { profile[:hooks].delete(hook) }
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
protected
|
|
230
|
+
def request_rsend(sid, profile, obj, meth, *args)
|
|
231
|
+
obj.send(meth, *args)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
protected
|
|
235
|
+
def request_detach(sid, profile)
|
|
236
|
+
return if @detached
|
|
237
|
+
@detached = true
|
|
238
|
+
if pid = fork # father
|
|
239
|
+
exit
|
|
240
|
+
else # son
|
|
241
|
+
Dir.chdir('/')
|
|
242
|
+
Process.setsid
|
|
243
|
+
STDIN.close
|
|
244
|
+
STDOUT.close
|
|
245
|
+
STDERR.close
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
protected
|
|
250
|
+
def request_chdir(sid, profile, dir)
|
|
251
|
+
Dir.chdir(dir)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
protected
|
|
255
|
+
def request_login_at(sid, profile, uri, *args)
|
|
256
|
+
@mutex.synchronize { profile.add_client(uri, Client, *args) }
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
protected
|
|
260
|
+
def request_request_at(sid, profile, uri, request, *args)
|
|
261
|
+
@mutex.synchronize { client_request(profile, uri, request, *args) }
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
protected
|
|
265
|
+
def request_logout_at(sid, profile, uri)
|
|
266
|
+
@mutex.synchronize { client_request(profile, uri, :logout, *args) }
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
protected
|
|
270
|
+
def request_start_sub_server(sid,
|
|
271
|
+
profile,
|
|
272
|
+
uri,
|
|
273
|
+
server_class=Server,
|
|
274
|
+
*args,
|
|
275
|
+
&block)
|
|
276
|
+
rd, wr = IO.pipe
|
|
277
|
+
if pid = fork # father
|
|
278
|
+
wr.close
|
|
279
|
+
# Process.detach(pid)
|
|
280
|
+
res_key, res_value = Marshal.load(rd)
|
|
281
|
+
rd.close
|
|
282
|
+
case res_key
|
|
283
|
+
when :uri
|
|
284
|
+
request(sid, :login_at, res_value, true)
|
|
285
|
+
return res_value
|
|
286
|
+
when :exc
|
|
287
|
+
Process.waitpid(-1)
|
|
288
|
+
raise(res_value)
|
|
289
|
+
else
|
|
290
|
+
raise(NameError, "`#{res_key}' - bad result key")
|
|
291
|
+
end
|
|
292
|
+
else # son
|
|
293
|
+
rd.close
|
|
294
|
+
begin
|
|
295
|
+
DRb.stop_service
|
|
296
|
+
srv = DRb.start_service(uri, server_class.new(*args))
|
|
297
|
+
block[srv] if block_given?
|
|
298
|
+
Marshal.dump([ :uri, srv.uri ], wr)
|
|
299
|
+
wr.close
|
|
300
|
+
srv.thread.join
|
|
301
|
+
rescue Exception => exc
|
|
302
|
+
data = exc
|
|
303
|
+
begin
|
|
304
|
+
Marshal.dump(exc)
|
|
305
|
+
rescue TypeError
|
|
306
|
+
data = exc.long_pp
|
|
307
|
+
end
|
|
308
|
+
Marshal.dump([ :exc, data ], wr)
|
|
309
|
+
wr.close
|
|
310
|
+
exit(1)
|
|
311
|
+
end
|
|
312
|
+
exit(0)
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
protected
|
|
317
|
+
def request_stop_sub_server(sid, profile, uri)
|
|
318
|
+
@mutex.synchronize { stop_sub_server(profile, uri) }
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
protected
|
|
322
|
+
def request_stop_all_sub_server(sid, profile)
|
|
323
|
+
@mutex.synchronize { stop_all_sub_server(profile) }
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
protected
|
|
327
|
+
def request_stop(sid, profile)
|
|
328
|
+
@sessions.dup.each { |id, prof| logout(id, prof) }
|
|
329
|
+
DRb.stop_service
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
protected
|
|
333
|
+
def request_pid(sid, profile)
|
|
334
|
+
Process.pid
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
#
|
|
338
|
+
# Methods
|
|
339
|
+
#
|
|
340
|
+
protected
|
|
341
|
+
def logout(sid, profile)
|
|
342
|
+
call_all_hooks(sid, profile, :logout)
|
|
343
|
+
stop_all_sub_server(profile)
|
|
344
|
+
@sessions.delete(sid)
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
protected
|
|
348
|
+
def get_profile(sid)
|
|
349
|
+
if @sessions[sid].nil?
|
|
350
|
+
raise(SessionError, "`#{sid}' - not an opened session")
|
|
351
|
+
end
|
|
352
|
+
@sessions[sid]
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
protected
|
|
356
|
+
def authentification(username, passwd)
|
|
357
|
+
@usrdb.each do |usr_name, usr_desc|
|
|
358
|
+
if usr_name == username and usr_desc[:passwd] == passwd
|
|
359
|
+
return usr_name, usr_desc
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
return nil
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
protected
|
|
366
|
+
def wipeout
|
|
367
|
+
dead = {}
|
|
368
|
+
@mutex.synchronize do
|
|
369
|
+
now = Time.now
|
|
370
|
+
@sessions.each do |sid, profile|
|
|
371
|
+
if (now - profile[:last_request_time]) > @wipeout_delay
|
|
372
|
+
dead[sid] = profile
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
dead.each { |sid, profile| request(sid, :logout) }
|
|
377
|
+
return dead
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
protected
|
|
381
|
+
def call_all_hooks(sid, profile, meth, *args)
|
|
382
|
+
hooks = []
|
|
383
|
+
unless @mutex.locked?
|
|
384
|
+
@mutex.synchronize do
|
|
385
|
+
@sessions.each { |id, prof| hooks += prof[:hooks] }
|
|
386
|
+
end
|
|
387
|
+
else
|
|
388
|
+
@sessions.each { |id, prof| hooks += prof[:hooks] }
|
|
389
|
+
end
|
|
390
|
+
hooks.each do |hook|
|
|
391
|
+
handle_dead_hook(hook, sid, profile, meth, *args)
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
protected
|
|
396
|
+
def call_allowed_hooks(sid, profile, request, *args)
|
|
397
|
+
hooks = []
|
|
398
|
+
@mutex.synchronize do
|
|
399
|
+
@sessions.each do |id, prof|
|
|
400
|
+
hooks += prof[:hooks] if prof.allowed_hook?(request)
|
|
401
|
+
end
|
|
402
|
+
end
|
|
403
|
+
hooks.each do |hook|
|
|
404
|
+
handle_dead_hook(hook, sid, profile, request, *args)
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
# overload me to handle every hook call
|
|
409
|
+
protected
|
|
410
|
+
def handle_dead_hook(hook, sid, profile, meth, *args)
|
|
411
|
+
nb_retry = 0
|
|
412
|
+
begin
|
|
413
|
+
call_hook(hook, sid.dup, profile.dup, meth, *args)
|
|
414
|
+
rescue DRb::DRbConnError
|
|
415
|
+
nb_retry += 1
|
|
416
|
+
retry if nb_retry <= 1
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
# overload me to handle every hook call
|
|
421
|
+
protected
|
|
422
|
+
def call_hook(hook, sid, profile, meth, *args)
|
|
423
|
+
hook.hook(sid, profile, meth, *args)
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
protected
|
|
427
|
+
def get_client_at(profile, uri)
|
|
428
|
+
clt = profile[:dispatcher].select_by(:uri, uri)
|
|
429
|
+
unless clt.nil? or clt.size == 1
|
|
430
|
+
raise(SessionError, "`#{uri}' - cannot opened a session at this uri")
|
|
431
|
+
end
|
|
432
|
+
clt.first
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
protected
|
|
436
|
+
def client_request(profile, uri, request, *args)
|
|
437
|
+
clt = get_client_at(profile, uri)
|
|
438
|
+
clt.send(request, *args)
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
protected
|
|
442
|
+
def stop_sub_server(profile, uri)
|
|
443
|
+
(client_request(profile, uri, :stop)) rescue DRb::DRbConnError
|
|
444
|
+
profile.del_client(uri)
|
|
445
|
+
Process.waitpid(-1)
|
|
446
|
+
$?
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
protected
|
|
450
|
+
def stop_all_sub_server(profile)
|
|
451
|
+
profile[:dispatcher].each do |uri, desc|
|
|
452
|
+
stop_sub_server(profile, uri)
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
protected
|
|
457
|
+
def check_sid(sid)
|
|
458
|
+
unless sid.is_a?(String) and sid =~ SID_REGEXP
|
|
459
|
+
raise(ParameterError, "`#{sid.inspect}' - bad session id format")
|
|
460
|
+
end
|
|
461
|
+
sid
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
protected
|
|
465
|
+
def check_usrdb(usrdb)
|
|
466
|
+
usrdb.each do |name, desc|
|
|
467
|
+
check_usrname(name)
|
|
468
|
+
check_usrdesc(desc)
|
|
469
|
+
end
|
|
470
|
+
usrdb
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
protected
|
|
474
|
+
def check_usrdesc(desc)
|
|
475
|
+
unless desc.is_a?(Hash) and desc.size >= 2
|
|
476
|
+
raise(ParameterError, "`#{desc.inspect}' - bad user description")
|
|
477
|
+
end
|
|
478
|
+
check_passwd(desc[:passwd])
|
|
479
|
+
check_admin(desc[:admin])
|
|
480
|
+
unless desc[:allowed_requests].nil?
|
|
481
|
+
check_allowed_requests(desc[:allowed_requests])
|
|
482
|
+
else
|
|
483
|
+
desc[:allowed_requests] = []
|
|
484
|
+
end
|
|
485
|
+
unless desc[:allowed_hooks].nil?
|
|
486
|
+
check_allowed_hooks(desc[:allowed_hooks])
|
|
487
|
+
else
|
|
488
|
+
desc[:allowed_hooks] = []
|
|
489
|
+
end
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
protected
|
|
493
|
+
def check_max_usr(max_usr)
|
|
494
|
+
unless max_usr.is_a?(Fixnum) and max_usr >= MIN_USR
|
|
495
|
+
raise(ParameterError, "`#{max_usr.inspect}' - bad max users number")
|
|
496
|
+
end
|
|
497
|
+
max_usr
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
protected
|
|
501
|
+
def check_wipeout_delay(wipeout_delay)
|
|
502
|
+
unless wipeout_delay.is_a?(Fixnum) and wipeout_delay >= MIN_WIPEOUT_DELAY
|
|
503
|
+
raise(ParameterError, "`#{wipeout_delay.inspect}' - bad wipeout delay")
|
|
504
|
+
end
|
|
505
|
+
@wipeout_delay = wipeout_delay
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
protected
|
|
509
|
+
def check_request(request)
|
|
510
|
+
unless request.is_a?(Symbol) and request.to_s =~ ConstRegexp::RB_METHOD
|
|
511
|
+
raise(ParameterError, "`#{request.inspect}' - bad request format")
|
|
512
|
+
end
|
|
513
|
+
req_name = 'request_' + request.to_s
|
|
514
|
+
unless self.respond_to?(req_name)
|
|
515
|
+
raise(RequestError, "`#{request.to_s}' - not a request")
|
|
516
|
+
end
|
|
517
|
+
req_name
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
protected
|
|
521
|
+
def check_request_permission(profile, request)
|
|
522
|
+
if (request != :logout) and (not profile.allowed_request?(request))
|
|
523
|
+
raise(PermissionError, "`#{request.to_s}' - request not allowed")
|
|
524
|
+
end
|
|
525
|
+
request
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
protected
|
|
529
|
+
def check_usrname(usrname)
|
|
530
|
+
unless usrname.is_a?(String) and usrname =~ USRNAME_REGEXP
|
|
531
|
+
raise(ParameterError, "`#{usrname.inspect}' - bad user name format")
|
|
532
|
+
end
|
|
533
|
+
usrname
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
protected
|
|
537
|
+
def check_passwd(passwd)
|
|
538
|
+
unless passwd.is_a?(String) and passwd =~ PASSWD_REGEXP
|
|
539
|
+
raise(ParameterError, "`#{passwd.inspect}' - bad password format")
|
|
540
|
+
end
|
|
541
|
+
passwd
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
protected
|
|
545
|
+
def check_allowed_requests(allowed_requests)
|
|
546
|
+
unless allowed_requests.is_a?(Array)
|
|
547
|
+
raise(ParameterError,
|
|
548
|
+
"`#{allowed_requests.inspect}' - bad allowed requests list format")
|
|
549
|
+
end
|
|
550
|
+
allowed_requests.each { |r| check_request(r) }
|
|
551
|
+
allowed_requests
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
protected
|
|
555
|
+
def check_allowed_hooks(allowed_hooks)
|
|
556
|
+
unless allowed_hooks.is_a?(Array)
|
|
557
|
+
raise(ParameterError,
|
|
558
|
+
"`#{allowed_hooks.inspect}' - bad allowed hooks list format")
|
|
559
|
+
end
|
|
560
|
+
allowed_hooks.each { |r| check_request(r) }
|
|
561
|
+
allowed_hooks
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
protected
|
|
565
|
+
def check_admin(admin)
|
|
566
|
+
unless admin.is_a?(TrueClass) or admin.is_a?(FalseClass)
|
|
567
|
+
raise(ParameterError, "`#{admin.inspect}' - bad admin flag")
|
|
568
|
+
end
|
|
569
|
+
admin
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
protected
|
|
573
|
+
def check_hook(hook)
|
|
574
|
+
unless hook.respond_to?(:hook)
|
|
575
|
+
raise(ParameterError, "`#{hook.inspect}' - do not respond to hook")
|
|
576
|
+
end
|
|
577
|
+
hook
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
end # class Server
|
|
581
|
+
|
|
582
|
+
end # module Session
|