2 # -*- coding: utf-8 -*-
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 from SimpleXMLRPCServer import SimpleXMLRPCServer
39 _moduleLogger = logging.getLogger(__name__)
40 socket.setdefaulttimeout(60) # Timeout auf 60 sec. setzen
43 class ProgressDialog(gtk.Dialog):
45 def __init__(self,title=_("Sync process"), parent=None):
46 gtk.Dialog.__init__(self,title,parent,gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,())
48 _moduleLogger.info("ProgressDialog, init")
50 label=gtk.Label(_("Sync process running...please wait"))
51 self.vbox.pack_start(label, True, True, 0)
52 label=gtk.Label(_("(this can take some minutes)"))
53 self.vbox.pack_start(label, True, True, 0)
55 #self.progressbar=gtk.ProgressBar()
56 #self.vbox.pack_start(self.progressbar, True, True, 0)
58 #self.set_keep_above(True)
63 #self.progressbar.pulse()
70 'syncFinished' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_STRING,)),
71 'syncBeforeStart' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_STRING,)),
74 def __init__(self,db,parentwindow,port):
75 gtk.VBox.__init__(self,homogeneous=False, spacing=0)
77 _moduleLogger.info("Sync, init")
82 self.parentwindow=parentwindow
83 self.concernedRows=None
86 #sql = "DROP TABLE sync"
87 #self.db.speichereSQL(sql,log=False)
89 sql = "CREATE TABLE sync (id INTEGER PRIMARY KEY, syncpartner TEXT, uuid TEXT, pcdatum INTEGER)"
90 self.db.speichereSQL(sql,log=False)
94 sql="SELECT uuid,pcdatum FROM sync WHERE syncpartner=?"
95 rows=self.db.ladeSQL(sql,("self",)) #Eigene Id feststellen
98 if (rows==None)or(len(rows)!=1):
99 sql="DELETE FROM sync WHERE syncpartner=?"
100 self.db.speichereSQL(sql,("self",),log=False)
106 self.sync_uuid=str(uuid.uuid4())
107 sql="INSERT INTO sync (syncpartner,uuid,pcdatum) VALUES (?,?,?)"
108 self.db.speichereSQL(sql,("self",str(self.sync_uuid),int(time.time())),log=False)
111 sync_uuid,pcdatum = rows[0]
112 self.sync_uuid=sync_uuid
116 frame=gtk.Frame(_("Local SyncServer (port ")+str(self.port)+")")
117 self.comboIP=gtk.combo_box_entry_new_text()
118 self.comboIP.append_text("") #self.get_ip_address("eth0"))
119 #self.comboIP.append_text(self.get_ip_address("eth1")) #fixme
120 #self.comboIP.append_text(self.get_ip_address("eth2"))
121 #self.comboIP.append_text(self.get_ip_address("eth3"))
123 #self.comboIP.append_text(self.get_ip_address("wlan0"))
124 #self.comboIP.append_text(self.get_ip_address("wlan1"))
128 frame.add(self.comboIP)
129 serverbutton=gtk.ToggleButton(_("Start SyncServer"))
130 serverbutton.connect("clicked",self.startServer,(None,))
131 self.pack_start(frame, expand=False, fill=True, padding=1)
132 self.pack_start(serverbutton, expand=False, fill=True, padding=1)
133 self.syncServerStatusLabel=gtk.Label(_("Syncserver not running"))
134 self.pack_start(self.syncServerStatusLabel, expand=False, fill=True, padding=1)
136 frame=gtk.Frame(_("RemoteSync-Server (Port ")+str(self.port)+")")
137 self.comboRemoteIP=gtk.combo_box_entry_new_text()
138 self.comboRemoteIP.append_text("192.168.0.?")
139 self.comboRemoteIP.append_text("192.168.1.?")
140 self.comboRemoteIP.append_text("192.168.176.?")
141 frame.add(self.comboRemoteIP)
142 syncbutton=gtk.Button(_("Connect to remote SyncServer"))
143 syncbutton.connect("clicked",self.syncButton,(None,))
144 self.pack_start(frame, expand=False, fill=True, padding=1)
145 self.pack_start(syncbutton, expand=False, fill=True, padding=1)
146 self.syncStatusLabel=gtk.Label(_("no sync process (at the moment)"))
147 self.pack_start(self.syncStatusLabel, expand=False, fill=True, padding=1)
149 #self.comboRemoteIP.set_text_column("Test")
150 self.comboRemoteIP.get_child().set_text(self.db.ladeDirekt("syncRemoteIP"))
151 self.comboIP.get_child().set_text(self.db.ladeDirekt("syncServerIP"))
154 if (self.db.ladeDirekt("startSyncServer",False)==True):
155 serverbutton.set_active(True)
157 def changeSyncStatus(self,active,title):
158 self.syncStatusLabel.set_text(title)
160 if self.progress==None:
161 self.progress=ProgressDialog(parent=self.parentwindow)
162 self.emit("syncBeforeStart","syncBeforeStart")
164 if self.progress!=None:
166 self.progress.destroy()
168 self.emit("syncFinished","syncFinished")
171 if self.progress!=None:
172 self.progress.pulse()
173 #if self.server!=None:
174 # self.server.pulse()
176 def getUeberblickBox(self):
177 frame=gtk.Frame(_("Query"))
182 if (self.rpcserver==None): return False
186 while (len(self.poll.poll(0))>0):
187 self.rpcserver.handle_request()
190 def get_ip_address(self,ifname):
191 return socket.gethostbyname(socket.gethostname())
193 # s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
194 # ip=socket.inet_ntoa(fcntl.ioctl(s.fileno(),0x8915,struct.pack('256s', ifname[:15]))[20:24])
197 # ip=socket.gethostbyname(socket.gethostname())
202 def getLastSyncDate(self,sync_uuid):
203 sql="SELECT syncpartner,pcdatum FROM sync WHERE uuid=?"
204 rows=self.db.ladeSQL(sql,(sync_uuid,))
205 if (rows!=None)and(len(rows)==1):
206 syncpartner,pcdatum = rows[0]
209 _moduleLogger.info("LastSyncDatum: "+str(pcdatum)+" Jetzt "+str(int(time.time())))
212 def check4commit(self,newSQL,lastdate):
213 _moduleLogger.info("check4commit 1")
214 if self.concernedRows==None:
215 _moduleLogger.info("check4commit Updatung concernedRows")
216 sql="SELECT pcdatum,rowid FROM logtable WHERE pcdatum>? ORDER BY pcdatum DESC"
217 self.concernedRows=self.db.ladeSQL(sql,(lastdate,))
219 if (self.concernedRows!=None)and(len(self.concernedRows)>0):
220 #_moduleLogger.info("check4commit 2")
221 id1, pcdatum,sql, param, host, rowid = newSQL
224 for x in self.concernedRows:
225 #_moduleLogger.info("check4commit 3")
228 _moduleLogger.info("newer sync entry, ignoring old one")
229 #_moduleLogger.info("check4commit 9.1")
232 #_moduleLogger.info("check4commit 9.2")
235 #_moduleLogger.info("check4commit 9.3")
238 def writeSQLTupel(self,newSQLs,lastdate):
242 self.concernedRows=None
244 _moduleLogger.info("writeSQLTupel got "+str(len(newSQLs))+" sql tupels")
245 for newSQL in newSQLs:
247 #print "SQL1: ",newSQL[1]
248 #print "SQL2: ",newSQL[2]
249 #print "SQL3: ",newSQL[3]
250 #print "Param:",string.split(newSQL[3]," <<Tren-ner>> ")
253 param=string.split(newSQL[3]," <<Tren-ner>> ")
260 if (newSQL[5]!=None)and(len(newSQL[5])>0):
261 commitSQL=self.check4commit(newSQL,lastdate)
263 if (commitSQL==True):
264 self.db.speichereSQL(newSQL[2],param,commit=False,pcdatum=newSQL[1],rowid=newSQL[5])
266 _moduleLogger.error("writeSQLTupel: Error")
269 if (pausenzaehler % 10)==0:
271 while (gtk.events_pending()):
272 gtk.main_iteration();
274 _moduleLogger.info("Alle SQLs an sqlite geschickt, commiting now")
276 _moduleLogger.info("Alle SQLs commited")
278 def doSync(self,sync_uuid,pcdatum,newSQLs,pcdatumjetzt):
279 #print uuid,pcdatum,newSQLs
280 #_moduleLogger.info("doSync 0")
281 self.changeSyncStatus(True,_("sync process running"))
283 #_moduleLogger.info("doSync 1")
285 while (gtk.events_pending()):
286 gtk.main_iteration();
287 diff=time.time()-pcdatumjetzt
293 _moduleLogger.info("doSync read sqls")
294 sql="SELECT * FROM logtable WHERE pcdatum>?"
295 rows=self.db.ladeSQL(sql,(pcdatum,))
296 _moduleLogger.info("doSync read sqls")
297 self.writeSQLTupel(newSQLs,pcdatum)
298 _moduleLogger.info("doSync wrote "+str(len(newSQLs))+" sqls")
299 _moduleLogger.info("doSync sending "+str(len(rows))+" sqls")
303 def getRemoteSyncUUID(self):
304 return self.sync_uuid
306 def startServer(self, widget, data=None):
308 self.db.speichereDirekt("syncServerIP",self.comboIP.get_child().get_text())
310 if (widget.get_active()==True):
311 _moduleLogger.info("Starting Server")
314 ip=self.comboIP.get_child().get_text()
315 self.rpcserver = SimpleXMLRPCServer((ip, self.port),allow_none=True)
316 self.rpcserver.register_function(pow)
317 self.rpcserver.register_function(self.getLastSyncDate)
318 self.rpcserver.register_function(self.doSync)
319 self.rpcserver.register_function(self.getRemoteSyncUUID)
320 self.rpcserver.register_function(self.doSaveFinalTime)
321 self.rpcserver.register_function(self.pulse)
322 self.poll=select.poll()
323 self.poll.register(self.rpcserver.fileno())
324 gobject.timeout_add(1000, self.handleRPC)
325 self.syncServerStatusLabel.set_text(_("Syncserver running..."))
328 self.db.speichereDirekt("startSyncServer",True)
331 s=str(sys.exc_info())
332 _moduleLogger.error("libsync: could not start server. Error: "+s)
333 mbox=gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_ERROR,gtk.BUTTONS_OK,_("Sync server could not start. Please check IP and port.")) #gtk.DIALOG_MODAL
334 mbox.set_modal(False)
338 widget.set_active(False)
340 _moduleLogger.info("Stopping Server")
345 self.syncServerStatusLabel.set_text(_("Syncserver not running..."))
347 self.db.speichereDirekt("startSyncServer",False)
349 def doSaveFinalTime(self,sync_uuid,pcdatum=None):
350 if (pcdatum==None): pcdatum=int(time.time())
351 if (time.time()>pcdatum):
352 pcdatum=int(time.time()) #größere Zeit nehmen
357 sql="DELETE FROM sync WHERE uuid=?"
358 self.db.speichereSQL(sql,(sync_uuid,),log=False)
359 sql="INSERT INTO sync (syncpartner,uuid,pcdatum) VALUES (?,?,?)"
360 self.db.speichereSQL(sql,("x",str(sync_uuid),pcdatum),log=False)
362 self.changeSyncStatus(False,_("no sync process (at the moment)"))
363 return (self.sync_uuid,pcdatum)
365 def syncButton(self, widget, data=None):
366 _moduleLogger.info("Syncing")
367 #sql="DELETE FROM logtable WHERE sql LIKE externeStundenplanung"
368 #self.db.speichereSQL(sql)
370 self.changeSyncStatus(True,_("sync process running"))
371 while (gtk.events_pending()):
372 gtk.main_iteration();
374 self.db.speichereDirekt("syncRemoteIP",self.comboRemoteIP.get_child().get_text())
376 self.server = xmlrpclib.ServerProxy("http://"+self.comboRemoteIP.get_child().get_text()+":"+str(self.port),allow_none=True)
377 #lastDate=server.getLastSyncDate(str(self.sync_uuid))
378 server_sync_uuid=self.server.getRemoteSyncUUID()
379 lastDate=self.getLastSyncDate(str(server_sync_uuid))
381 #print ("LastSyncDate: "+str(lastDate)+" Now: "+str(int(time.time())))
383 sql="SELECT * FROM logtable WHERE pcdatum>?"
384 rows=self.db.ladeSQL(sql,(lastDate,))
386 _moduleLogger.info("loaded concerned rows")
388 newSQLs=self.server.doSync(self.sync_uuid,lastDate,rows,time.time())
390 _moduleLogger.info("did do sync, processing sqls now")
392 self.writeSQLTupel(newSQLs,lastDate)
394 sync_uuid, finalpcdatum=self.server.doSaveFinalTime(self.sync_uuid)
395 self.doSaveFinalTime(sync_uuid, finalpcdatum)
397 self.changeSyncStatus(False,_("no sync process (at the moment)"))
399 mbox = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_INFO,gtk.BUTTONS_OK,_("Synchronization successfully completed"))
400 response = mbox.run()
404 _moduleLogger.warning("Zeitdiff zu groß/oder anderer db-Fehler")
405 self.changeSyncStatus(False,_("no sync process (at the moment)"))
406 mbox = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_INFO,gtk.BUTTONS_OK,_("The clocks are not synchronized between stations"))
407 response = mbox.run()
411 _moduleLogger.warning("Sync connect failed")
412 self.changeSyncStatus(False,_("no sync process (at the moment)"))
413 mbox = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_INFO,gtk.BUTTONS_OK,_("Sync failed, reason: ")+unicode(sys.exc_info()[1][1]))
414 response = mbox.run()