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/>.
22 import SimpleXMLRPCServer
29 socket.setdefaulttimeout(60) # Timeout auf 60 sec. setzen
41 _moduleLogger = logging.getLogger("sync")
44 class ProgressDialog(gtk.Dialog):
46 def __init__(self, title = _("Sync process"), parent = None):
47 gtk.Dialog.__init__(self, title, parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, ())
49 _moduleLogger.info("ProgressDialog, init")
51 label = gtk.Label(_("Sync process running...please wait"))
52 self.vbox.pack_start(label, True, True, 0)
53 label = gtk.Label(_("(this can take some minutes)"))
54 self.vbox.pack_start(label, True, True, 0)
66 'syncFinished' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, )),
67 'syncBeforeStart' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, )),
70 def __init__(self, db, parentwindow, port):
71 gtk.VBox.__init__(self, homogeneous = False, spacing = 0)
73 _moduleLogger.info("Sync, init")
78 self.parentwindow = parentwindow
79 self.concernedRows = None
81 sql = "CREATE TABLE sync (id INTEGER PRIMARY KEY, syncpartner TEXT, uuid TEXT, pcdatum INTEGER)"
82 self.db.speichereSQL(sql, log = False)
84 sql = "SELECT uuid, pcdatum FROM sync WHERE syncpartner = ?"
85 rows = self.db.ladeSQL(sql, ("self", )) #Eigene Id feststellen
87 if (rows is None)or(len(rows)!= 1):
88 sql = "DELETE FROM sync WHERE syncpartner = ?"
89 self.db.speichereSQL(sql, ("self", ), log = False)
91 self.sync_uuid = str(uuid.uuid4())
92 sql = "INSERT INTO sync (syncpartner, uuid, pcdatum) VALUES (?, ?, ?)"
93 self.db.speichereSQL(sql, ("self", str(self.sync_uuid), int(time.time())), log = False)
95 sync_uuid, pcdatum = rows[0]
96 self.sync_uuid = sync_uuid
98 frame = gtk.Frame(_("Local SyncServer (port ")+str(self.port)+")")
100 self.comboIP = gtk.combo_box_entry_new_text()
102 self.comboIP.append_text("") #self.get_ip_address("eth0"))
104 frame.add(self.comboIP)
105 serverbutton = gtk.ToggleButton(_("Start/Stop SyncServer"))
106 serverbutton.connect("clicked", self.startServer, (None, ))
107 self.pack_start(frame, expand = False, fill = True, padding = 1)
108 self.pack_start(serverbutton, expand = False, fill = True, padding = 1)
109 self.syncServerStatusLabel = gtk.Label(_("SyncServer stopped"))
110 self.pack_start(self.syncServerStatusLabel, expand = False, fill = True, padding = 1)
112 frame = gtk.Frame(_("Remote SyncServer (port ")+str(self.port)+")")
113 self.comboRemoteIP = gtk.combo_box_entry_new_text()
114 self.comboRemoteIP.append_text("192.168.0.?")
115 self.comboRemoteIP.append_text("192.168.1.?")
116 self.comboRemoteIP.append_text("192.168.176.?")
117 frame.add(self.comboRemoteIP)
118 syncbutton = gtk.Button(_("Connect to remote SyncServer"))
119 syncbutton.connect("clicked", self.syncButton, (None, ))
120 self.pack_start(frame, expand = False, fill = True, padding = 1)
121 self.pack_start(syncbutton, expand = False, fill = True, padding = 1)
122 self.syncStatusLabel = gtk.Label(_("no sync process (at the moment)"))
123 self.pack_start(self.syncStatusLabel, expand = False, fill = True, padding = 1)
125 self.comboRemoteIP.get_child().set_text(self.db.ladeDirekt("syncRemoteIP"))
126 self.comboIP.get_child().set_text(self.db.ladeDirekt("syncServerIP"))
129 if self.db.ladeDirekt("startSyncServer", False):
130 serverbutton.set_active(True)
132 def changeSyncStatus(self, active, title):
133 self.syncStatusLabel.set_text(title)
135 if self.progress is None:
136 self.progress = ProgressDialog(parent = self.parentwindow)
137 self.emit("syncBeforeStart", "syncBeforeStart")
139 if self.progress is not None:
141 self.progress.destroy()
143 self.emit("syncFinished", "syncFinished")
146 if self.progress is not None:
147 self.progress.pulse()
149 def getUeberblickBox(self):
150 frame = gtk.Frame(_("Query"))
155 if self.rpcserver is None:
157 except StandardError:
160 while 0 < len(self.poll.poll(0)):
161 self.rpcserver.handle_request()
164 def get_ip_address(self, ifname):
165 return socket.gethostbyname(socket.gethostname())
167 def getLastSyncDate(self, sync_uuid):
168 sql = "SELECT syncpartner, pcdatum FROM sync WHERE uuid = ?"
169 rows = self.db.ladeSQL(sql, (sync_uuid, ))
170 if rows is not None and len(rows) == 1:
171 syncpartner, pcdatum = rows[0]
174 _moduleLogger.info("LastSyncDatum: "+str(pcdatum)+" Jetzt "+str(int(time.time())))
177 def check4commit(self, newSQL, lastdate):
178 _moduleLogger.info("check4commit 1")
179 if self.concernedRows is None:
180 _moduleLogger.info("check4commit Updatung concernedRows")
181 sql = "SELECT pcdatum, rowid FROM logtable WHERE pcdatum>? ORDER BY pcdatum DESC"
182 self.concernedRows = self.db.ladeSQL(sql, (lastdate, ))
184 if self.concernedRows is not None and 0 < len(self.concernedRows):
185 id1, pcdatum, sql, param, host, rowid = newSQL
188 for x in self.concernedRows:
191 _moduleLogger.info("newer sync entry, ignoring old one")
198 def writeSQLTupel(self, newSQLs, lastdate):
202 self.concernedRows = None
204 _moduleLogger.info("writeSQLTupel got "+str(len(newSQLs))+" sql tupels")
205 for newSQL in newSQLs:
207 param = newSQL[3].split(" <<Tren-ner>> ")
214 if (newSQL[5]!= None)and(len(newSQL[5])>0):
215 commitSQL = self.check4commit(newSQL, lastdate)
217 if (commitSQL == True):
218 self.db.speichereSQL(newSQL[2], param, commit = False, pcdatum = newSQL[1], rowid = newSQL[5])
220 _moduleLogger.error("writeSQLTupel: Error")
223 if (pausenzaehler % 10) == 0:
225 while gtk.events_pending():
228 _moduleLogger.info("Alle SQLs an sqlite geschickt, commiting now")
230 _moduleLogger.info("Alle SQLs commited")
232 def doSync(self, sync_uuid, pcdatum, newSQLs, pcdatumjetzt):
233 self.changeSyncStatus(True, "sync process running")
236 while gtk.events_pending():
238 diff = abs(time.time() - pcdatumjetzt)
242 _moduleLogger.info("doSync read sqls")
243 sql = "SELECT * FROM logtable WHERE pcdatum>?"
244 rows = self.db.ladeSQL(sql, (pcdatum, ))
245 _moduleLogger.info("doSync read sqls")
246 self.writeSQLTupel(newSQLs, pcdatum)
247 _moduleLogger.info("doSync wrote "+str(len(newSQLs))+" sqls")
248 _moduleLogger.info("doSync sending "+str(len(rows))+" sqls")
251 def getRemoteSyncUUID(self):
252 return self.sync_uuid
254 def startServer(self, widget, data = None):
256 self.db.speichereDirekt("syncServerIP", self.comboIP.get_child().get_text())
258 if widget.get_active():
259 _moduleLogger.info("Starting Server")
262 ip = self.comboIP.get_child().get_text()
263 self.rpcserver = SimpleXMLRPCServer.SimpleXMLRPCServer((ip, self.port), allow_none = True)
264 self.rpcserver.register_function(pow)
265 self.rpcserver.register_function(self.getLastSyncDate)
266 self.rpcserver.register_function(self.doSync)
267 self.rpcserver.register_function(self.getRemoteSyncUUID)
268 self.rpcserver.register_function(self.doSaveFinalTime)
269 self.rpcserver.register_function(self.pulse)
270 self.poll = select.poll()
271 self.poll.register(self.rpcserver.fileno())
272 gobject.timeout_add(1000, self.handleRPC)
273 self.syncServerStatusLabel.set_text(_("Syncserver running..."))
276 self.db.speichereDirekt("startSyncServer", True)
278 except StandardError:
279 s = str(sys.exc_info())
280 _moduleLogger.error("libsync: could not start server. Error: "+s)
281 mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Could not start SyncServer. Check IP, port settings.")) #gtk.DIALOG_MODAL
282 mbox.set_modal(False)
283 response = mbox.run()
286 widget.set_active(False)
288 _moduleLogger.info("Stopping Server")
291 except StandardError:
293 self.syncServerStatusLabel.set_text(_("SyncServer stopped"))
295 self.db.speichereDirekt("startSyncServer", False)
297 def doSaveFinalTime(self, sync_uuid, pcdatum = None):
299 pcdatum = int(time.time())
300 if pcdatum < time.time():
301 pcdatum = int(time.time()) #größere Zeit nehmen
306 sql = "DELETE FROM sync WHERE uuid = ?"
307 self.db.speichereSQL(sql, (sync_uuid, ), log = False)
308 sql = "INSERT INTO sync (syncpartner, uuid, pcdatum) VALUES (?, ?, ?)"
309 self.db.speichereSQL(sql, ("x", str(sync_uuid), pcdatum), log = False)
311 self.changeSyncStatus(False, _("no sync process (at the moment)"))
312 return (self.sync_uuid, pcdatum)
314 def syncButton(self, widget, data = None):
315 _moduleLogger.info("Syncing")
317 self.changeSyncStatus(True, _("sync process running"))
318 while (gtk.events_pending()):
321 self.db.speichereDirekt("syncRemoteIP", self.comboRemoteIP.get_child().get_text())
323 self.server = xmlrpclib.ServerProxy("http://"+self.comboRemoteIP.get_child().get_text()+":"+str(self.port), allow_none = True)
324 server_sync_uuid = self.server.getRemoteSyncUUID()
325 lastDate = self.getLastSyncDate(str(server_sync_uuid))
327 sql = "SELECT * FROM logtable WHERE pcdatum>?"
328 rows = self.db.ladeSQL(sql, (lastDate, ))
330 _moduleLogger.info("loaded concerned rows")
332 newSQLs = self.server.doSync(self.sync_uuid, lastDate, rows, time.time())
334 _moduleLogger.info("did do sync, processing sqls now")
336 self.writeSQLTupel(newSQLs, lastDate)
338 sync_uuid, finalpcdatum = self.server.doSaveFinalTime(self.sync_uuid)
339 self.doSaveFinalTime(sync_uuid, finalpcdatum)
341 self.changeSyncStatus(False, _("no sync process (at the moment)"))
343 mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("Synchronization successfully completed"))
344 response = mbox.run()
348 _moduleLogger.warning("Zeitdiff zu groß/oder anderer db-Fehler")
349 self.changeSyncStatus(False, _("no sync process (at the moment)"))
350 mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("The clocks are not synchronized between stations"))
351 response = mbox.run()
354 except StandardError:
355 _moduleLogger.warning("Sync connect failed")
356 self.changeSyncStatus(False, _("no sync process (at the moment)"))
357 mbox = gtk.MessageDialog(
362 _("Sync failed, reason: ")+unicode(sys.exc_info()[1][1])
364 response = mbox.run()