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 class ProgressDialog(gtk.Dialog):
43 def __init__(self, title = _("Sync process"), parent = None):
44 gtk.Dialog.__init__(self, title, parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, ())
46 logging.info("ProgressDialog, init")
48 label = gtk.Label(_("Sync process running...please wait"))
49 self.vbox.pack_start(label, True, True, 0)
50 label = gtk.Label(_("(this can take some minutes)"))
51 self.vbox.pack_start(label, True, True, 0)
63 'syncFinished' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, )),
64 'syncBeforeStart' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, )),
67 def __init__(self, db, parentwindow, port):
68 gtk.VBox.__init__(self, homogeneous = False, spacing = 0)
70 logging.info("Sync, init")
75 self.parentwindow = parentwindow
76 self.concernedRows = None
78 sql = "CREATE TABLE sync (id INTEGER PRIMARY KEY, syncpartner TEXT, uuid TEXT, pcdatum INTEGER)"
79 self.db.speichereSQL(sql, log = False)
81 sql = "SELECT uuid, pcdatum FROM sync WHERE syncpartner = ?"
82 rows = self.db.ladeSQL(sql, ("self", )) #Eigene Id feststellen
84 if (rows is None)or(len(rows)!= 1):
85 sql = "DELETE FROM sync WHERE syncpartner = ?"
86 self.db.speichereSQL(sql, ("self", ), log = False)
88 self.sync_uuid = str(uuid.uuid4())
89 sql = "INSERT INTO sync (syncpartner, uuid, pcdatum) VALUES (?, ?, ?)"
90 self.db.speichereSQL(sql, ("self", str(self.sync_uuid), int(time.time())), log = False)
92 sync_uuid, pcdatum = rows[0]
93 self.sync_uuid = sync_uuid
95 frame = gtk.Frame(_("Local SyncServer (port ")+str(self.port)+")")
97 self.comboIP = gtk.combo_box_entry_new_text()
99 self.comboIP.append_text("") #self.get_ip_address("eth0"))
101 frame.add(self.comboIP)
102 serverbutton = gtk.ToggleButton(_("Start/Stop SyncServer"))
103 serverbutton.connect("clicked", self.startServer, (None, ))
104 self.pack_start(frame, expand = False, fill = True, padding = 1)
105 self.pack_start(serverbutton, expand = False, fill = True, padding = 1)
106 self.syncServerStatusLabel = gtk.Label(_("SyncServer stopped"))
107 self.pack_start(self.syncServerStatusLabel, expand = False, fill = True, padding = 1)
109 frame = gtk.Frame(_("Remote SyncServer (port ")+str(self.port)+")")
110 self.comboRemoteIP = gtk.combo_box_entry_new_text()
111 self.comboRemoteIP.append_text("192.168.0.?")
112 self.comboRemoteIP.append_text("192.168.1.?")
113 self.comboRemoteIP.append_text("192.168.176.?")
114 frame.add(self.comboRemoteIP)
115 syncbutton = gtk.Button(_("Connect to remote SyncServer"))
116 syncbutton.connect("clicked", self.syncButton, (None, ))
117 self.pack_start(frame, expand = False, fill = True, padding = 1)
118 self.pack_start(syncbutton, expand = False, fill = True, padding = 1)
119 self.syncStatusLabel = gtk.Label(_("no sync process (at the moment)"))
120 self.pack_start(self.syncStatusLabel, expand = False, fill = True, padding = 1)
122 self.comboRemoteIP.get_child().set_text(self.db.ladeDirekt("syncRemoteIP"))
123 self.comboIP.get_child().set_text(self.db.ladeDirekt("syncServerIP"))
126 if self.db.ladeDirekt("startSyncServer", False):
127 serverbutton.set_active(True)
129 def changeSyncStatus(self, active, title):
130 self.syncStatusLabel.set_text(title)
132 if self.progress is None:
133 self.progress = ProgressDialog(parent = self.parentwindow)
134 self.emit("syncBeforeStart", "syncBeforeStart")
136 if self.progress is not None:
138 self.progress.destroy()
140 self.emit("syncFinished", "syncFinished")
143 if self.progress is not None:
144 self.progress.pulse()
146 def getUeberblickBox(self):
147 frame = gtk.Frame(_("Query"))
152 if self.rpcserver is None:
154 except StandardError:
157 while 0 < len(self.poll.poll(0)):
158 self.rpcserver.handle_request()
161 def get_ip_address(self, ifname):
162 return socket.gethostbyname(socket.gethostname())
164 def getLastSyncDate(self, sync_uuid):
165 sql = "SELECT syncpartner, pcdatum FROM sync WHERE uuid = ?"
166 rows = self.db.ladeSQL(sql, (sync_uuid, ))
167 if rows is not None and len(rows) == 1:
168 syncpartner, pcdatum = rows[0]
171 logging.info("LastSyncDatum: "+str(pcdatum)+" Jetzt "+str(int(time.time())))
174 def check4commit(self, newSQL, lastdate):
175 logging.info("check4commit 1")
176 if self.concernedRows is None:
177 logging.info("check4commit Updatung concernedRows")
178 sql = "SELECT pcdatum, rowid FROM logtable WHERE pcdatum>? ORDER BY pcdatum DESC"
179 self.concernedRows = self.db.ladeSQL(sql, (lastdate, ))
181 if self.concernedRows is not None and 0 < len(self.concernedRows):
182 id1, pcdatum, sql, param, host, rowid = newSQL
185 for x in self.concernedRows:
188 logging.info("newer sync entry, ignoring old one")
195 def writeSQLTupel(self, newSQLs, lastdate):
199 self.concernedRows = None
201 logging.info("writeSQLTupel got "+str(len(newSQLs))+" sql tupels")
202 for newSQL in newSQLs:
204 param = newSQL[3].split(" <<Tren-ner>> ")
211 if (newSQL[5]!= None)and(len(newSQL[5])>0):
212 commitSQL = self.check4commit(newSQL, lastdate)
214 if (commitSQL == True):
215 self.db.speichereSQL(newSQL[2], param, commit = False, pcdatum = newSQL[1], rowid = newSQL[5])
217 logging.error("writeSQLTupel: Error")
220 if (pausenzaehler % 10) == 0:
222 while gtk.events_pending():
225 logging.info("Alle SQLs an sqlite geschickt, commiting now")
227 logging.info("Alle SQLs commited")
229 def doSync(self, sync_uuid, pcdatum, newSQLs, pcdatumjetzt):
230 self.changeSyncStatus(True, "sync process running")
233 while gtk.events_pending():
235 diff = abs(time.time() - pcdatumjetzt)
239 logging.info("doSync read sqls")
240 sql = "SELECT * FROM logtable WHERE pcdatum>?"
241 rows = self.db.ladeSQL(sql, (pcdatum, ))
242 logging.info("doSync read sqls")
243 self.writeSQLTupel(newSQLs, pcdatum)
244 logging.info("doSync wrote "+str(len(newSQLs))+" sqls")
245 logging.info("doSync sending "+str(len(rows))+" sqls")
248 def getRemoteSyncUUID(self):
249 return self.sync_uuid
251 def startServer(self, widget, data = None):
253 self.db.speichereDirekt("syncServerIP", self.comboIP.get_child().get_text())
255 if widget.get_active():
256 logging.info("Starting Server")
259 ip = self.comboIP.get_child().get_text()
260 self.rpcserver = SimpleXMLRPCServer.SimpleXMLRPCServer((ip, self.port), allow_none = True)
261 self.rpcserver.register_function(pow)
262 self.rpcserver.register_function(self.getLastSyncDate)
263 self.rpcserver.register_function(self.doSync)
264 self.rpcserver.register_function(self.getRemoteSyncUUID)
265 self.rpcserver.register_function(self.doSaveFinalTime)
266 self.rpcserver.register_function(self.pulse)
267 self.poll = select.poll()
268 self.poll.register(self.rpcserver.fileno())
269 gobject.timeout_add(1000, self.handleRPC)
270 self.syncServerStatusLabel.set_text(_("Syncserver running..."))
273 self.db.speichereDirekt("startSyncServer", True)
275 except StandardError:
276 s = str(sys.exc_info())
277 logging.error("libsync: could not start server. Error: "+s)
278 mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("Could not start SyncServer. Check IP, port settings.")) #gtk.DIALOG_MODAL
279 mbox.set_modal(False)
280 response = mbox.run()
283 widget.set_active(False)
285 logging.info("Stopping Server")
288 except StandardError:
290 self.syncServerStatusLabel.set_text(_("SyncServer stopped"))
292 self.db.speichereDirekt("startSyncServer", False)
294 def doSaveFinalTime(self, sync_uuid, pcdatum = None):
296 pcdatum = int(time.time())
297 if pcdatum < time.time():
298 pcdatum = int(time.time()) #größere Zeit nehmen
303 sql = "DELETE FROM sync WHERE uuid = ?"
304 self.db.speichereSQL(sql, (sync_uuid, ), log = False)
305 sql = "INSERT INTO sync (syncpartner, uuid, pcdatum) VALUES (?, ?, ?)"
306 self.db.speichereSQL(sql, ("x", str(sync_uuid), pcdatum), log = False)
308 self.changeSyncStatus(False, _("no sync process (at the moment)"))
309 return (self.sync_uuid, pcdatum)
311 def syncButton(self, widget, data = None):
312 logging.info("Syncing")
314 self.changeSyncStatus(True, _("sync process running"))
315 while (gtk.events_pending()):
318 self.db.speichereDirekt("syncRemoteIP", self.comboRemoteIP.get_child().get_text())
320 self.server = xmlrpclib.ServerProxy("http://"+self.comboRemoteIP.get_child().get_text()+":"+str(self.port), allow_none = True)
321 server_sync_uuid = self.server.getRemoteSyncUUID()
322 lastDate = self.getLastSyncDate(str(server_sync_uuid))
324 sql = "SELECT * FROM logtable WHERE pcdatum>?"
325 rows = self.db.ladeSQL(sql, (lastDate, ))
327 logging.info("loaded concerned rows")
329 newSQLs = self.server.doSync(self.sync_uuid, lastDate, rows, time.time())
331 logging.info("did do sync, processing sqls now")
333 self.writeSQLTupel(newSQLs, lastDate)
335 sync_uuid, finalpcdatum = self.server.doSaveFinalTime(self.sync_uuid)
336 self.doSaveFinalTime(sync_uuid, finalpcdatum)
338 self.changeSyncStatus(False, _("no sync process (at the moment)"))
340 mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("Synchronization successfully completed"))
341 response = mbox.run()
345 logging.warning("Zeitdiff zu groß/oder anderer db-Fehler")
346 self.changeSyncStatus(False, _("no sync process (at the moment)"))
347 mbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, _("The clocks are not synchronized between stations"))
348 response = mbox.run()
351 except StandardError:
352 logging.warning("Sync connect failed")
353 self.changeSyncStatus(False, _("no sync process (at the moment)"))
354 mbox = gtk.MessageDialog(
359 _("Sync failed, reason: ")+unicode(sys.exc_info()[1][1])
361 response = mbox.run()