manqod-server 1.257.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.
@@ -0,0 +1,61 @@
1
+ #this file is part of manqod
2
+ #manqod is distributed under the CDDL licence
3
+ #the owner of manqod is Dobai-Pataky Balint(dpblnt@gmail.com)
4
+
5
+ class Users
6
+ include Eprint
7
+ include DRbUndumped
8
+ def initialize(drbdb)
9
+ @drbdb=drbdb
10
+ @users=Hash.new
11
+ @groups=Hash.new
12
+ @usergroups=Hash.new
13
+ end
14
+ attr_reader :drbdb
15
+
16
+ def load_all
17
+ @users.clear
18
+ @groups.clear
19
+ @usergroups.clear
20
+ drbdb.admin.rows("select * from users").each{|row|
21
+ @users[row["id"].to_i]=row
22
+ }
23
+ einfo("#{@users.length} users\n")
24
+ drbdb.admin.rows("select * from groups").each{|row|
25
+ @groups[row["id"].to_i]=row
26
+ }
27
+ drbdb.admin.rows("select * from usergroups").each{|row|
28
+ @usergroups[row["id"].to_i]=row
29
+ }
30
+ self
31
+ end
32
+
33
+ def user_in_group?(user_id,group_id)
34
+ found=false
35
+ @usergroups.each_value{|ugrp|
36
+ found=true if ugrp["userid"].to_i == user_id && ugrp["groupid"].to_i == group_id
37
+ }
38
+ found
39
+ end
40
+
41
+ def get_user(user_id)
42
+ @users[user_id]
43
+ end
44
+
45
+ def each
46
+ @users.each_key{|im_key| yield im_key}
47
+ end
48
+ def auth?(nick,password)
49
+ found=false
50
+ @users.each{|key,user|
51
+ found=true if nick.to_s == user["nick"].to_s && user["passwd"].to_s == password.to_s
52
+ }
53
+ found
54
+ end
55
+
56
+
57
+ def to_s
58
+ "Users of #{drbdb}"
59
+ end
60
+ end
61
+
data/lib/DrbDB.rb ADDED
@@ -0,0 +1,274 @@
1
+ #this file is part of manqod
2
+ #manqod is distributed under the CDDL licence
3
+ #the author of manqod is Dobai-Pataky Balint(dpblnt@gmail.com)
4
+
5
+ class DrbDb
6
+ include Eprint
7
+ include DRbUndumped
8
+ include SQL
9
+ include Help
10
+ include Cron
11
+ include GtkAttributes
12
+ include EventCache
13
+ include Messaging
14
+
15
+ INIT=0
16
+ LOADING=1
17
+ SERVING=2
18
+
19
+ def initialize(connection,main_server_uri)
20
+ @state=INIT
21
+ @connection=connection
22
+ @main_server_uri=main_server_uri
23
+ @moditems=Hash.new #[moditem_id][id][fields]
24
+ @server=nil
25
+ # @relations=Hash.new
26
+ # @server=DRb::DRbServer.new(@connection['uri'],self)
27
+ end
28
+ attr_reader :uri, :moditems, :admin, :client, :cache, :connection, :images, :state
29
+ attr_accessor :server, :main_server
30
+
31
+ def init
32
+ einfo("Memcached #{Memcached::VERSION}")
33
+ @cache = Memcached.new([@connection['cache_host']],{:prefix_key=>key_name, :default_ttl => 0, :timeout => 2})
34
+ DRb.start_service(@connection["uri"],self)
35
+ @server=DRb.current_server()
36
+ @main_server=DRb::DRbObject.new_with_uri(@main_server_uri)
37
+ @uri=server.uri()
38
+ unless init_sql(@connection['sql_host'],@connection['sql_user'],@connection['sql_password'],@connection['sql_db'])
39
+ eerror("connection to sql server failed: #{@connection['sql_user']}@#{@connection['sql_host']}/#{@connection['sql_db']}")
40
+ return nil
41
+ end
42
+ update_manqod_db
43
+ begin
44
+ begin
45
+ @admin=DRb::DRbObject.new(nil,@connection['admin_uri'])
46
+ we_have_admin=@admin.alive?
47
+ rescue
48
+ ewarn("no admin?")
49
+ sleep 1
50
+ end
51
+ end until we_have_admin
52
+ begin
53
+ @state=LOADING
54
+ load_all_attributes
55
+
56
+ admin.rows("select moditems.id,modules.modname,moditems.display from moditems left join modules on modules.id = moditems.modid").each{|moditem|
57
+ begin
58
+ case moditem["modname"]
59
+ when "listing"
60
+ @moditems[moditem["id"].to_i]=DrbListModel.new(self,moditem["id"].to_i).create_skeleton unless @moditems.has_key?(moditem["id"])
61
+ @moditems[moditem["id"].to_i].update(self)
62
+ when "form"
63
+ @moditems[moditem["id"].to_i]=DrbForm.new(self,moditem["id"].to_i).create_skeleton unless @moditems.has_key?(moditem["id"])
64
+ else
65
+ ewarn("not caching #{moditem['display']}[#{moditem['modname']}]")
66
+ end
67
+ rescue =>err
68
+ ewarn("error loading moditem: #{moditem.inspect}")
69
+ eexception(err,:moditem => moditem)
70
+ end
71
+ }
72
+ @images=DrbImages.new(self).load_all
73
+ @users=Users.new(self).load_all
74
+ load_all_events
75
+ load_all_help
76
+ start_cron
77
+ @state=SERVING
78
+ rescue => err
79
+ eerror("failed to start: #{err}")
80
+ retry
81
+ end
82
+
83
+ DRb.thread.join
84
+ einfo("EXITED")
85
+ exit
86
+ end
87
+
88
+ def setup_client
89
+ if @connection['client_uri'].length>0
90
+ begin
91
+ @client=DRb::DRbObject.new(nil,@connection['client_uri'])
92
+ einfo("client is alive?(#{@client}): #{@client.alive?}")
93
+ rescue
94
+ @client=nil
95
+ einfo("no client.")
96
+ end
97
+ end
98
+ end
99
+ def name
100
+ @connection['name']
101
+ end
102
+ def key_name
103
+ @connection['key_name']
104
+ end
105
+
106
+
107
+ def moditem(mod_id)
108
+ @moditems[mod_id.to_i]
109
+ end
110
+
111
+ def reload_moditem(moditem_id)
112
+ @state=LOADING
113
+ if moditem(moditem_id).nil?
114
+ einfo("creating moditem ##{moditem_id}")
115
+ #moditem added
116
+ admin.rows("select moditems.id,modules.modname,moditems.display
117
+ from moditems
118
+ left join modules on modules.id = moditems.modid
119
+ where moditems.id='#{moditem_id}'").each{|moditem|
120
+ begin
121
+ case moditem["modname"]
122
+ when "listing"
123
+ @moditems[moditem["id"].to_i]=DrbListModel.new(self,moditem["id"].to_i).create_skeleton unless @moditems.has_key?(moditem["id"])
124
+ @moditems[moditem["id"].to_i].update(self)
125
+ when "form"
126
+ @moditems[moditem["id"].to_i]=DrbForm.new(self,moditem["id"].to_i).create_skeleton unless @moditems.has_key?(moditem["id"])
127
+ else
128
+ eerror("not caching #{moditem['display']}[#{moditem['modname']}]")
129
+ end
130
+ rescue =>err
131
+ ewarn("error loading moditem: #{moditem.inspect}")
132
+ eexception(err,:moditem => moditem)
133
+ end
134
+ }
135
+
136
+ else
137
+ einfo("reloading moditem ##{moditem_id}")
138
+ case moditem(moditem_id).mod_type
139
+ when "list"
140
+ new_model=DrbListModel.new(self,moditem_id).create_skeleton
141
+ edebug("#{new_model} created")
142
+ new_model.update(self)
143
+ unless @moditems[moditem_id.to_i].nil?
144
+ @moditems[moditem_id.to_i].clients.each{|c| new_model.subscribe(c)}
145
+ edebug("#{@moditems[moditem_id.to_i]} abandoned")
146
+ end
147
+ @moditems[moditem_id.to_i]=new_model
148
+ @moditems[moditem_id.to_i].notify_clients(nil,"structure")
149
+ when "form"
150
+ moditem(moditem_id).create_skeleton
151
+ end
152
+ end
153
+ @state=SERVING
154
+ end
155
+
156
+ def reload_users
157
+ @users.load_all
158
+ end
159
+
160
+ def reload_client_images
161
+ main_server.connected_clients.each_pair{|cc,cdb|
162
+ if cdb == client.name
163
+ einfo("sending reload images to #{cc}")
164
+ cc.rpc("DrbImages.instance.load_images")
165
+ end
166
+ }
167
+ end
168
+
169
+ def reload_client_attributes
170
+ client.load_all_attributes
171
+ main_server.connected_clients.each_pair{|cc,cdb|
172
+ if cdb == client.name
173
+ begin
174
+ einfo("sending reload attribute to #{cc}")
175
+ cc.rpc("GtkAttributeStorage.instance.load_all")
176
+ rescue => err
177
+ ewarn("cannot send reload attributes #{err}")
178
+ end
179
+ end
180
+ }
181
+ end
182
+
183
+ def reload_client_events(goid)
184
+ einfo("changed client event: #{goid}")
185
+ client.events(goid,true)
186
+ main_server.connected_clients.each_pair{|cc,cdb|
187
+ if cdb == client.name
188
+ begin
189
+ einfo("sending reload event to #{cc}")
190
+ cc.rpc("EventCache.instance.reload_events(\"#{goid}\")")
191
+ rescue => err
192
+ ewarn("cannot send reload events #{err}")
193
+ end
194
+ end
195
+ }
196
+ end
197
+
198
+ def auth?(nick,password)
199
+ r=@users.auth?(nick,password)
200
+ edebug("auth?(#{nick}):#{r}")
201
+ r
202
+ end
203
+ def sendmail(nick,subject,body)
204
+ sendmail_to_nick(nick,subject,body)
205
+ end
206
+ def user_in_group?(user_id,group_id)
207
+ @users.user_in_group?(user_id,group_id)
208
+ end
209
+
210
+ def moditems_with_base(base)
211
+ @moditems.each_value{|drblist|
212
+ yield drblist if drblist && drblist.mod_type == "list" && drblist.base == base
213
+ }
214
+ end
215
+
216
+ def changed_ids_of_base(base,ids,nick=nil)
217
+ base_moditem=nil
218
+ moditems_with_base(base){|b|
219
+ base_moditem=b
220
+ }
221
+ unless base_moditem.nil?
222
+ base_moditem.rows_changed(ids,nick)
223
+ end
224
+ end
225
+
226
+ def lock_id_of_base(base,lid)
227
+ ids=if lid.class == Array then lid else [lid] end
228
+ moditems_with_base(base){|b| ids.each{|iid| b.lock_iter(iid)}}
229
+ end
230
+
231
+ def unlock_id_of_base(base,lid)
232
+ ids=if lid.class == Array then lid else [lid] end
233
+ moditems_with_base(base){|b| ids.each{|iid| b.unlock_iter(iid)}}
234
+ end
235
+
236
+ def each_moditem(modtype = "list")
237
+ @moditems.each_value{|m|
238
+ yield m if m.mod_type == modtype
239
+ }
240
+ end
241
+
242
+ def remove_dead_clients
243
+ cnt=0
244
+ @moditems.each_value{|m| cnt+=m.remove_dead_clients if m.mod_type == "list"}
245
+ cnt
246
+ end
247
+
248
+ def alive?
249
+ true
250
+ # server.alive?
251
+ end
252
+
253
+ # def method_missing(sym,*args)
254
+ # p "#{self} missing method: #{sym}(#{args})"
255
+ # end
256
+
257
+ def report_mail(subject, variables)
258
+ @main_server.report_mail(subject,variables)
259
+ end
260
+
261
+ def exit
262
+ @server.stop_service
263
+ super
264
+ end
265
+
266
+ def serving?
267
+ @state==SERVING
268
+ end
269
+
270
+ def to_s
271
+ "[ManqodDb #{name}(#{Process.pid})]"
272
+ end
273
+ end
274
+
data/lib/Eprint.rb ADDED
@@ -0,0 +1,94 @@
1
+ #this file is part of manqod
2
+ #manqod is distributed under the CDDL licence
3
+ #the author of manqod is Dobai-Pataky Balint(dpblnt@gmail.com)
4
+
5
+ module Eprint
6
+ TERM_COLOUR={
7
+ Logger::Severity::DEBUG => 33,
8
+ Logger::Severity::INFO => 32,
9
+ Logger::Severity::WARN => 35,
10
+ Logger::Severity::ERROR => 31,
11
+ Logger::Severity::FATAL => 31,
12
+ Logger::Severity::UNKNOWN => 36
13
+ }
14
+ def eprint(subject,level=Logger::Severity::UNKNOWN)
15
+ begin
16
+ ManqodLogger.instance.log(level,"\e[1;37m#{self}\e[0m:\e[#{TERM_COLOUR[level]}m#{subject}\e[0m")
17
+ rescue => err
18
+ print("#{err}\n")
19
+ ManqodLogger.instance.set_level("ERROR")
20
+ retry
21
+ end
22
+ end
23
+
24
+ def edebug(subject)
25
+ eprint(subject,Logger::Severity::DEBUG)
26
+ end
27
+
28
+ def einfo(subject)
29
+ eprint(subject,Logger::Severity::INFO)
30
+ end
31
+
32
+ def ewarn(subject)
33
+ eprint(subject,Logger::Severity::WARN)
34
+ end
35
+
36
+ def eerror(subject)
37
+ eprint(subject,Logger::Severity::ERROR)
38
+ end
39
+ def efatal(subject)
40
+ eprint(subject,Logger::Severity::FATAL)
41
+ end
42
+
43
+ def ecode(subject)
44
+ eprint(subject,Logger::Severity::UNKNOWN)
45
+ end
46
+
47
+ def report_mail(subject, variables)
48
+ return unless ManqodLogger.instance.report_address
49
+ fork{
50
+ begin
51
+ msg="From: manqod@#{Socket.gethostbyname(Socket.gethostname).first}\nTo: #{ManqodLogger.instance.report_address}\nSubject: #{subject}\n"
52
+ variables.each_pair{|k,v| msg="#{msg}\n#{k}: #{v}\n--------------------"}
53
+
54
+ Net::SMTP.start('localhost'){ |smtp|
55
+ smtp.send_message(msg, "manqod_server", ManqodLogger.instance.report_address)
56
+ einfo("report sent: #{subject} to {ManqodLogger.instance.report_address}")
57
+ }
58
+ rescue => err
59
+ eerror("can't send error report via SMTP")
60
+ end
61
+ }
62
+ end
63
+
64
+ def eexception(ex,*args)
65
+ eerror("error: #{ex}\n#{ex.backtrace.join("\n")}")
66
+ report_mail(ex,{
67
+ 'error'=>ex.inspect,
68
+ 'backtrace'=>ex.backtrace.join("\n"),
69
+ 'class' => self.class,
70
+ 'self'=>self.inspect,
71
+ 'arguments' => args.inspect
72
+ })
73
+ end
74
+
75
+ def eeval(command,context=self)
76
+ ret=nil
77
+ begin
78
+ if context and b=context.getBinding then
79
+ ret=eval(command, b)
80
+ else
81
+ ret=eval(command)
82
+ end
83
+ rescue SyntaxError, NameError => err
84
+ eexception(err,:command=>command,:context=>context)
85
+ end
86
+ ret
87
+ end
88
+
89
+ def getBinding
90
+ binding
91
+ end
92
+
93
+ end
94
+
data/lib/HeartBeat.rb ADDED
@@ -0,0 +1,54 @@
1
+ #this file is part of manqod
2
+ #manqod is distributed under the CDDL licence
3
+ #the author of manqod is Dobai-Pataky Balint(dpblnt@gmail.com)
4
+
5
+ module HeartBeat
6
+ def init_HeartBeat
7
+ @headerbeat_thread=Thread.new{
8
+ lalive_clients=-1
9
+ lalive_client_lists=-1
10
+ loop do
11
+ begin
12
+ sleep 10
13
+ to_remove=Array.new
14
+ alive_clients=0
15
+ @connected_clients.each_pair{|cc,db|
16
+ begin
17
+ cc.alive?
18
+ alive_clients+=1
19
+ rescue
20
+ to_remove.push(cc)
21
+ end
22
+ }
23
+ to_remove.each{|dead|
24
+ ewarn("removed dead client: #{dead.inspect}")
25
+ @connected_clients.delete(dead)
26
+ }
27
+
28
+ alive_client_lists=0
29
+ @dbs.each_value{|db|
30
+ next unless db.serving?
31
+ #keep the conenction to the cache alive
32
+ db.cache.set("alive",Time.new)
33
+ #check for alive client list subscriptions
34
+ alive_client_lists+=db.remove_dead_clients
35
+ }
36
+ einfo("#{alive_clients} clients #{alive_client_lists} subscriptions alive") unless alive_clients==lalive_clients && alive_client_lists==lalive_client_lists
37
+
38
+ lalive_clients=alive_clients
39
+ lalive_client_lists=alive_client_lists
40
+ rescue ECONNREFUSED => err
41
+ eerror("HeartBeat: #{err}")
42
+ rescue =>err
43
+ eerror("HeartBeat error: #{err}\n#{err.backtrace.join("\n")}")
44
+ end
45
+ end
46
+ }
47
+ einfo("HeartBeat started")
48
+ end
49
+ def stop_HeartBeat
50
+ @heartbeat_thread.kill
51
+ einfo("HeartBeat stopped")
52
+ end
53
+ end
54
+
@@ -0,0 +1,27 @@
1
+ #this file is part of manqod
2
+ #manqod is distributed under the CDDL licence
3
+ #the author of manqod is Dobai-Pataky Balint(dpblnt@gmail.com)
4
+
5
+ class ManqodLogger < Logger::Application
6
+ include Singleton
7
+
8
+ LEVEL_MAP={
9
+ "DEBUG" => Logger::Severity::DEBUG,
10
+ "INFO" => Logger::Severity::INFO,
11
+ "WARN" => Logger::Severity::WARN,
12
+ "ERROR" => Logger::Severity::ERROR,
13
+ "FATAL" => Logger::Severity::FATAL,
14
+ "UNKNOWN" => Logger::Severity::UNKNOWN
15
+ }
16
+
17
+ @report_address=nil
18
+ attr_reader :report_address
19
+
20
+ def set_level(llevel)
21
+ self.level=LEVEL_MAP[llevel]
22
+ end
23
+ def set_report_address(ra)
24
+ @report_address=ra
25
+ end
26
+ end
27
+
@@ -0,0 +1,167 @@
1
+ #this file is part of manqod
2
+ #manqod is distributed under the CDDL licence
3
+ #the author of manqod is Dobai-Pataky Balint(dpblnt@gmail.com)
4
+
5
+ class ManqodServer
6
+ include Eprint
7
+ include DRb
8
+ include DRbUndumped
9
+ include HeartBeat
10
+ include DBSetup
11
+ def initialize(opts)
12
+ @starting_up=true
13
+ @uri=opts[:bind]
14
+ @logdev=opts[:log]
15
+ @log_level=opts[:debug]
16
+ @report_address=opts[:report]
17
+ @path=opts[:path]
18
+ @connections_conf=File::expand_path(File.join(File.join(@path,"etc"),"connections.conf"))
19
+ @conns=Hash.new
20
+ @dbs=Hash.new
21
+ @connected_clients=Hash.new
22
+ end
23
+ attr_reader :dbs, :connected_clients, :uri
24
+ attr_reader :starting_up
25
+
26
+ def init
27
+ ManqodLogger.instance.set_log(@logdev) if @logdev
28
+ einfo("setting log level to #{@log_level}")
29
+ ManqodLogger.instance.set_level(@log_level) if @log_level
30
+ ManqodLogger.instance.set_report_address(@report_address) if @report_address
31
+ load_conns
32
+ begin
33
+ DRb.start_service(@uri,self)
34
+ rescue =>err
35
+ eerror("starting main server failed: #{err}")
36
+ return false
37
+ end
38
+ @conns.sort{|a,b| a[1]["auto_load_order"] <=> b[1]["auto_load_order"]}.each{|conn|
39
+ load_conn(conn[0]) if conn[1]["auto_load"]
40
+ }
41
+ setup_clients
42
+ init_HeartBeat
43
+ @starting_up=false
44
+ eprint("serving")
45
+ DRb.thread.join
46
+ einfo("graceful shutdown")
47
+ end
48
+
49
+ def setup_clients
50
+ #wait for all clients to start up
51
+ begin
52
+ begin
53
+ found=false
54
+ @dbs.each_value{|drbdb|
55
+ unless drbdb.serving?
56
+ found = true
57
+ sleep 1
58
+ end
59
+ }
60
+ end while found
61
+ @dbs.each_pair{|conn_name,drbdb| drbdb.setup_client unless drbdb.client and drbdb.client.alive?}
62
+ rescue
63
+ end
64
+ end
65
+
66
+ def conn(conn_name)
67
+ @conns[conn_name]
68
+ end
69
+
70
+ def conn_list
71
+ @conns.each_pair{|conn_name,conn|
72
+ yield conn_name,conn
73
+ }
74
+ end
75
+
76
+ def default_connection
77
+ dc=nil
78
+ @conns.each_pair{|cn,c| dc=c if c.has_key?("client_default") && c["client_default"]}
79
+ dc
80
+ end
81
+
82
+ def reload_conn(conn_name)
83
+ if @conns.has_key?(conn_name)
84
+ free_conn(conn_name) if @dbs.has_key?(conn_name)
85
+ load_conn(conn_name)
86
+ setup_clients
87
+ end
88
+ end
89
+
90
+ def load_conn(conn_name)
91
+ if @conns.has_key?(conn_name)
92
+ begin
93
+ @conns[conn_name]["key_name"]=conn_name
94
+ @conns[conn_name]['pid']=fork{
95
+ th=DrbDb.new(@conns[conn_name],@uri)
96
+ th.init
97
+ }
98
+ Process.detach(@conns[conn_name]['pid'])
99
+ edebug("forked \"#{conn_name}\" [#{@conns[conn_name]['uri']}](#{@conns[conn_name]['pid']})")
100
+
101
+ begin
102
+ sleep 1
103
+ @dbs[conn_name]=DRb::DRbObject.new_with_uri(@conns[conn_name]['uri'])
104
+ # @dbs[conn_name].alive?
105
+ @dbs[conn_name].state
106
+ @dbs[conn_name].setup_client
107
+ rescue => err
108
+ #check if pid is alive
109
+ begin
110
+ Process::kill(0,@conns[conn_name]['pid'])
111
+ rescue Errno::ESRCH
112
+ raise("Process with pid #{@conns[conn_name]['pid']} is dead")
113
+ end
114
+ ewarn("waiting for startup of #{conn_name} (#{err})")
115
+ retry
116
+ end while @dbs[conn_name].state != DrbDb::SERVING
117
+ rescue =>err
118
+ eerror("error starting connection:#{conn_name} #{err}, retrying")
119
+ sleep 1
120
+ retry
121
+ end
122
+ end
123
+ end
124
+
125
+ def free_conn(conn_name)
126
+ if @dbs.has_key?(conn_name)
127
+ @dbs[conn_name].exit
128
+ @dbs.delete(conn_name)
129
+ einfo("#{conn_name} freed.")
130
+ end
131
+ end
132
+
133
+ def stop
134
+ @dbs.each_key{|dbn|
135
+ begin
136
+ free_conn(dbn)
137
+ rescue =>err
138
+ eerror("cannot stop #{dbn}:#{err}")
139
+ end
140
+ }
141
+ current_server.stop_service
142
+ einfo("server halted")
143
+ exit
144
+ end
145
+
146
+ def register_client(client,db)
147
+ @connected_clients[client]=db unless @connected_clients.has_key?(client)
148
+ einfo("#{client} registered to [#{db}]")
149
+ end
150
+ def unregister_client(client)
151
+ @connected_clients.delete(client)
152
+ einfo("#{client} unregistered")
153
+ end
154
+
155
+ def alive?
156
+ true
157
+ end
158
+
159
+ def to_s
160
+ "ManqodServer"
161
+ end
162
+
163
+ # def method_missing(sym,*args)
164
+ # p "#{self} missing method: #{sym}(#{args})"
165
+ # end
166
+ end
167
+