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
41 _moduleLogger = logging.getLogger(__name__)
42 socket.setdefaulttimeout(60) # Timeout auf 60 sec. setzen
45 class ProgressDialog(gtk.Dialog):
47 def __init__(self, title = _("Sync process"), parent = None):
48 gtk.Dialog.__init__(self, title, parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, ())
50 _moduleLogger.info("ProgressDialog, init")
52 label = gtk.Label(_("Sync process running...please wait"))
53 self.vbox.pack_start(label, True, True, 0)
54 label = gtk.Label(_("(this can take some minutes)"))
55 self.vbox.pack_start(label, True, True, 0)
57 #self.progressbar = gtk.ProgressBar()
58 #self.vbox.pack_start(self.progressbar, True, True, 0)
60 #self.set_keep_above(True)
65 #self.progressbar.pulse()
72 'syncFinished' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, )),
73 'syncBeforeStart' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, )),
76 def __init__(self, db, parentwindow, port):
77 gtk.VBox.__init__(self, homogeneous = False, spacing = 0)
79 _moduleLogger.info("Sync, init")
84 self.parentwindow = parentwindow
85 self.concernedRows = None
88 #sql = "DROP TABLE sync"
89 #self.db.speichereSQL(sql, log = False)
91 sql = "CREATE TABLE sync (id INTEGER PRIMARY KEY, syncpartner TEXT, uuid TEXT, pcdatum INTEGER)"
92 self.db.speichereSQL(sql, log = False)
96 sql = "SELECT uuid, pcdatum FROM sync WHERE syncpartner = ?"
97 rows = self.db.ladeSQL(sql, ("self", )) #Eigene Id feststellen
100 if (rows == None)or(len(rows) != 1):
101 sql = "DELETE FROM sync WHERE syncpartner = ?"
102 self.db.speichereSQL(sql, ("self", ), log = False)
108 self.sync_uuid = str(uuid.uuid4())
109 sql = "INSERT INTO sync (syncpartner, uuid, pcdatum) VALUES (?, ?, ?)"
110 self.db.speichereSQL(sql, ("self", str(self.sync_uuid), int(time.time())), log = False)
113 sync_uuid, pcdatum = rows[0]
114 self.sync_uuid = sync_uuid
118 frame = gtk.Frame(_("Local SyncServer (port ")+str(self.port)+")")
119 self.comboIP = gtk.combo_box_entry_new_text()
120 self.comboIP.append_text("") #self.get_ip_address("eth0"))
121 #self.comboIP.append_text(self.get_ip_address("eth1")) #fixme
122 #self.comboIP.append_text(self.get_ip_address("eth2"))
123 #self.comboIP.append_text(self.get_ip_address("eth3"))
125 #self.comboIP.append_text(self.get_ip_address("wlan0"))
126 #self.comboIP.append_text(self.get_ip_address("wlan1"))
130 frame.add(self.comboIP)
131 serverbutton = gtk.ToggleButton(_("Start SyncServer"))
132 serverbutton.connect("clicked", self.startServer, (None, ))
133 self.pack_start(frame, expand = False, fill = True, padding = 1)
134 self.pack_start(serverbutton, expand = False, fill = True, padding = 1)
135 self.syncServerStatusLabel = gtk.Label(_("Syncserver not running"))
136 self.pack_start(self.syncServerStatusLabel, expand = False, fill = True, padding = 1)
138 frame = gtk.Frame(_("RemoteSync-Server (Port ")+str(self.port)+")")
139 self.comboRemoteIP = gtk.combo_box_entry_new_text()
140 self.comboRemoteIP.append_text("192.168.0.?")
141 self.comboRemoteIP.append_text("192.168.1.?")
142 self.comboRemoteIP.append_text("192.168.176.?")
143 frame.add(self.comboRemoteIP)
144 syncbutton = gtk.Button(_("Connect to remote SyncServer"))
145 syncbutton.connect("clicked", self.syncButton, (None, ))
146 self.pack_start(frame, expand = False, fill = True, padding = 1)
147 self.pack_start(syncbutton, expand = False, fill = True, padding = 1)
148 self.syncStatusLabel = gtk.Label(_("no sync process (at the moment)"))
149 self.pack_start(self.syncStatusLabel, expand = False, fill = True, padding = 1)
151 #self.comboRemoteIP.set_text_column("Test")
152 self.comboRemoteIP.get_child().set_text(self.db.ladeDirekt("syncRemoteIP"))
153 self.comboIP.get_child().set_text(self.db.ladeDirekt("syncServerIP"))
156 if (self.db.ladeDirekt("startSyncServer", False) == True):
157 serverbutton.set_active(True)
159 def changeSyncStatus(self, active, title):
160 self.syncStatusLabel.set_text(title)
162 if self.progress == None:
163 self.progress = ProgressDialog(parent = self.parentwindow)
164 self.emit("syncBeforeStart", "syncBeforeStart")
166 if self.progress is not None:
168 self.progress.destroy()
170 self.emit("syncFinished", "syncFinished")
173 if self.progress is not None:
174 self.progress.pulse()
175 #if self.server is not None:
176 # self.server.pulse()
178 def getUeberblickBox(self):
179 frame = gtk.Frame(_("Query"))
184 if self.rpcserver is None:
189 while 0 < len(self.poll.poll(0)):
190 self.rpcserver.hande_request()
193 def get_ip_address(self, ifname):
194 return socket.gethostbyname(socket.gethostname())
196 # s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
197 # ip = socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, struct.pack('256s', ifname[:15]))[20:24])
200 # ip = socket.gethostbyname(socket.gethostname())
205 def getLastSyncDate(self, sync_uuid):
206 sql = "SELECT syncpartner, pcdatum FROM sync WHERE uuid = ?"
207 rows = self.db.ladeSQL(sql, (sync_uuid, ))
208 if (rows is not None)and(len(rows) == 1):
209 syncpartner, pcdatum = rows[0]
212 _moduleLogger.info("LastSyncDatum: "+str(pcdatum)+" Jetzt "+str(int(time.time())))
215 def check4commit(self, newSQL, lastdate):
216 _moduleLogger.info("check4commit 1")
217 if self.concernedRows == None:
218 _moduleLogger.info("check4commit Updatung concernedRows")
219 sql = "SELECT pcdatum, rowid FROM logtable WHERE pcdatum>? ORDER BY pcdatum DESC"
220 self.concernedRows = self.db.ladeSQL(sql, (lastdate, ))
222 if (self.concernedRows is not None)and(len(self.concernedRows)>0):
223 #_moduleLogger.info("check4commit 2")
224 id1, pcdatum, sql, param, host, rowid = newSQL
227 for x in self.concernedRows:
228 #_moduleLogger.info("check4commit 3")
231 _moduleLogger.info("newer sync entry, ignoring old one")
232 #_moduleLogger.info("check4commit 9.1")
235 #_moduleLogger.info("check4commit 9.2")
238 #_moduleLogger.info("check4commit 9.3")
241 def writeSQLTupel(self, newSQLs, lastdate):
245 self.concernedRows = None
247 _moduleLogger.info("writeSQLTupel got "+str(len(newSQLs))+" sql tupels")
248 for newSQL in newSQLs:
250 #print "SQL1: ", newSQL[1]
251 #print "SQL2: ", newSQL[2]
252 #print "SQL3: ", newSQL[3]
253 #print "Param:", string.split(newSQL[3], " <<Tren-ner>> ")
255 if (newSQL[3] != ""):
256 param = string.split(newSQL[3], " <<Tren-ner>> ")
263 if (newSQL[5] is not None)and(len(newSQL[5])>0):
264 commitSQL = self.check4commit(newSQL, lastdate)
267 self.db.speichereSQL(newSQL[2], param, commit = False, pcdatum = newSQL[1], rowid = newSQL[5])
269 _moduleLogger.error("writeSQLTupel: Error")
272 if (pausenzaehler % 10) == 0:
274 while gtk.events_pending():
277 _moduleLogger.info("Alle SQLs an sqlite geschickt, commiting now")
279 _moduleLogger.info("Alle SQLs commited")
281 def doSync(self, sync_uuid, pcdatum, newSQLs, pcdatumjetzt):
282 #print uuid, pcdatum, newSQLs
283 #_moduleLogger.info("doSync 0")
284 self.changeSyncStatus(True, _("sync process running"))
286 #_moduleLogger.info("doSync 1")
288 while gtk.events_pending():
289 gtk.main_iteration();
290 diff = abs(time.time() - pcdatumjetzt)
294 _moduleLogger.info("doSync read sqls")
295 sql = "SELECT * FROM logtable WHERE pcdatum>?"
296 rows = self.db.ladeSQL(sql, (pcdatum, ))
297 _moduleLogger.info("doSync read sqls")
298 self.writeSQLTupel(newSQLs, pcdatum)
299 _moduleLogger.info("doSync wrote "+str(len(newSQLs))+" sqls")
300 _moduleLogger.info("doSync sending "+str(len(rows))+" sqls")
303 def getRemoteSyncUUID(self):
304 return self.sync_uuid
306 @gtk_toolbox.log_exception(_moduleLogger)
307 def startServer(self, widget, data = None):
309 self.db.speichereDirekt("syncServerIP", self.comboIP.get_child().get_text())
311 if (widget.get_active() == True):
312 _moduleLogger.info("Starting Server")
315 ip = self.comboIP.get_child().get_text()
316 self.rpcserver = SimpleXMLRPCServer((ip, self.port), allow_none = True)
317 self.rpcserver.register_function(pow)
318 self.rpcserver.register_function(self.getLastSyncDate)
319 self.rpcserver.register_function(self.doSync)
320 self.rpcserver.register_function(self.getRemoteSyncUUID)
321 self.rpcserver.register_function(self.doSaveFinalTime)
322 self.rpcserver.register_function(self.pulse)
323 self.poll = select.poll()
324 self.poll.register(self.rpcserver.fileno())
325 gobject.timeout_add(1000, self.handleRPC)
326 self.syncServerStatusLabel.set_text(_("Syncserver running..."))
329 self.db.speichereDirekt("startSyncServer", True)
332 s = str(sys.exc_info())
333 _moduleLogger.error("libsync: could not start server. Error: "+s)
334 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
335 mbox.set_modal(False)
336 response = mbox.run()
339 widget.set_active(False)
341 _moduleLogger.info("Stopping Server")
346 self.syncServerStatusLabel.set_text(_("Syncserver not running..."))
348 self.db.speichereDirekt("startSyncServer", False)
350 def doSaveFinalTime(self, sync_uuid, pcdatum = None):
352 pcdatum = int(time.time())
353 if (time.time()>pcdatum):
354 pcdatum = int(time.time()) #größere Zeit nehmen
359 sql = "DELETE FROM sync WHERE uuid = ?"
360 self.db.speichereSQL(sql, (sync_uuid, ), log = False)
361 sql = "INSERT INTO sync (syncpartner, uuid, pcdatum) VALUES (?, ?, ?)"
362 self.db.speichereSQL(sql, ("x", str(sync_uuid), pcdatum), log = False)
364 self.changeSyncStatus(False, _("no sync process (at the moment)"))
365 return (self.sync_uuid, pcdatum)
367 @gtk_toolbox.log_exception(_moduleLogger)
368 def syncButton(self, widget, data = None):
369 _moduleLogger.info("Syncing")
370 #sql = "DELETE FROM logtable WHERE sql LIKE externeStundenplanung"
371 #self.db.speichereSQL(sql)
373 self.changeSyncStatus(True, _("sync process running"))
374 while (gtk.events_pending()):
377 self.db.speichereDirekt("syncRemoteIP", self.comboRemoteIP.get_child().get_text())
379 self.server = xmlrpclib.ServerProxy("http://"+self.comboRemoteIP.get_child().get_text()+":"+str(self.port), allow_none = True)
380 #lastDate = server.getLastSyncDate(str(self.sync_uuid))
381 server_sync_uuid = self.server.getRemoteSyncUUID()
382 lastDate = self.getLastSyncDate(str(server_sync_uuid))
384 #print ("LastSyncDate: "+str(lastDate)+" Now: "+str(int(time.time())))
386 sql = "SELECT * FROM logtable WHERE pcdatum>?"
387 rows = self.db.ladeSQL(sql, (lastDate, ))
389 _moduleLogger.info("loaded concerned rows")
391 newSQLs = self.server.doSync(self.sync_uuid, lastDate, rows, time.time())
393 _moduleLogger.info("did do sync, processing sqls now")
395 self.writeSQLTupel(newSQLs, lastDate)
397 sync_uuid, finalpcdatum = self.server.doSaveFinalTime(self.sync_uuid)
398 self.doSaveFinalTime(sync_uuid, finalpcdatum)
400 self.changeSyncStatus(False, _("no sync process (at the moment)"))
402 mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("Synchronization successfully completed"))
403 response = mbox.run()
407 _moduleLogger.warning("Zeitdiff zu groß/oder anderer db-Fehler")
408 self.changeSyncStatus(False, _("no sync process (at the moment)"))
409 mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("The clocks are not synchronized between stations"))
410 response = mbox.run()
414 _moduleLogger.warning("Sync connect failed")
415 self.changeSyncStatus(False, _("no sync process (at the moment)"))
416 mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("Sync failed, reason: ")+unicode(sys.exc_info()[1][1]))
417 response = mbox.run()