1d786dcbc296528e2c1b97fc56f6087d4801ede4
[multilist] / src / multilistclasses / libsync.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 import gobject
5 import time
6 import string
7 from SimpleXMLRPCServer import SimpleXMLRPCServer 
8 import random
9 import socket 
10 socket.setdefaulttimeout(60) # Timeout auf 60 sec. setzen 
11 import xmlrpclib 
12 import select
13 #import fcntl
14 import struct
15 import gtk
16 import uuid
17 import sys
18 import logging
19
20 import libspeichern 
21  
22  
23 class ProgressDialog(gtk.Dialog):
24         
25         def pulse(self):
26                 #self.progressbar.pulse()
27                 pass
28         
29         def __init__(self,title="Sync process", parent=None):
30                 gtk.Dialog.__init__(self,title,parent,gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,())
31                 
32                 logging.info("ProgressDialog, init")
33                 
34                 label=gtk.Label("Sync process running...please wait")
35                 self.vbox.pack_start(label, True, True, 0)
36                 label=gtk.Label("(this can take some minutes)")
37                 self.vbox.pack_start(label, True, True, 0)
38                 
39                 #self.progressbar=gtk.ProgressBar()
40                 #self.vbox.pack_start(self.progressbar, True, True, 0)
41                 
42                 #self.set_keep_above(True)
43                 self.vbox.show_all()
44                 self.show()
45  
46 class Sync(gtk.VBox): 
47         
48         __gsignals__ = {
49                 'syncFinished' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_STRING,)),
50                 'syncBeforeStart' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,(gobject.TYPE_STRING,)),
51         }
52         
53         def changeSyncStatus(self,active,title):
54                 self.syncStatusLabel.set_text(title)
55                 if active==True:
56                         if self.progress==None:
57                                 self.progress=ProgressDialog(parent=self.parentwindow)
58                                 
59                 else:
60                         if self.progress!=None:
61                                 self.progress.hide()            
62                                 self.progress.destroy()
63                                 self.progress=None
64         
65         def pulse(self):
66                 if self.progress!=None:
67                         self.progress.pulse()
68                 #if self.server!=None:
69                 #       self.server.pulse()
70                 
71         
72         def getUeberblickBox(self):
73                 frame=gtk.Frame("Abfrage")
74                 return frame
75                         
76         def handleRPC(self):
77                 try:
78                         if (self.rpcserver==None): return False
79                 except:
80                         return False
81                         
82                 while (len(self.poll.poll(0))>0):
83                         self.rpcserver.handle_request()
84                 return True
85
86         def get_ip_address(self,ifname):
87                 return socket.gethostbyname(socket.gethostname())
88                 #try:
89                 #       s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
90                 #       ip=socket.inet_ntoa(fcntl.ioctl(s.fileno(),0x8915,struct.pack('256s', ifname[:15]))[20:24])
91                 #       s.close()
92                 #except:
93                 #       ip=socket.gethostbyname(socket.gethostname())
94                 #       s.close()
95                 
96                 #return ip FixME
97                 
98         def getLastSyncDate(self,sync_uuid):
99                 sql="SELECT syncpartner,pcdatum FROM sync WHERE uuid=?"
100                 rows=self.db.ladeSQL(sql,(sync_uuid,))
101                 if (rows!=None)and(len(rows)==1): 
102                         syncpartner,pcdatum = rows[0]
103                 else:
104                         pcdatum=-1
105                 logging.info("LastSyncDatum: "+str(pcdatum)+" Jetzt "+str(int(time.time())))
106                 return pcdatum
107                 
108         
109         def writeSQLTupel(self,newSQLs):
110                 if (newSQLs==None):
111                          return
112                 pausenzaehler=0
113                 for newSQL in newSQLs:
114                         #print ""
115                         #print "SQL1: ",newSQL[1]
116                         #print "SQL2: ",newSQL[2]
117                         #print "SQL3: ",newSQL[3]
118                         #print "Param:",string.split(newSQL[3]," <<Tren-ner>> ")
119                         #print ""
120                         if (newSQL[3]!=""):
121                                 param=string.split(newSQL[3]," <<Tren-ner>> ")
122                         else:
123                                 param=None
124                 
125                         if (len(newSQL)>2):
126                                 commitSQL=True
127                                 
128                                 if (newSQL[5]!=None)and(len(newSQL[5])>0):
129                                         sql="SELECT * FROM logtable WHERE rowid=? ORDER BY pcdatum DESC"
130                                         rows=self.db.ladeSQL(sql,(newSQL[5],))
131                                         if (rows!=None)and(len(rows)>0):
132                                                 if (rows[0][1]>newSQL[1])and(len(rows[0][5])>0):
133                                                         logging.info("newer sync entry, ignoring old one")
134                                                         print "newer sync entry, ignoring old one"
135                                                         commitSQL=False
136                                         
137                                 if (commitSQL==True):
138                                         self.db.speichereSQL(newSQL[2],param,commit=False,pcdatum=newSQL[1],rowid=newSQL[5])
139                         else: 
140                                 logging.error("writeSQLTupel: Error")
141                                 
142                         pausenzaehler+=1
143                         if (pausenzaehler % 10)==0:
144                                 self.pulse()
145                                 while (gtk.events_pending()):
146                                         gtk.main_iteration();
147                                 
148                 logging.info("Alle SQLs an sqlite geschickt, commiting now")
149                 self.db.commitSQL()
150                 logging.info("Alle SQLs commited")
151                 
152         
153         def doSync(self,sync_uuid,pcdatum,newSQLs,pcdatumjetzt):
154                 #print uuid,pcdatum,newSQLs
155                 self.changeSyncStatus(True,"sync process running")
156                 self.pulse()
157                 
158                 while (gtk.events_pending()):
159                         gtk.main_iteration();
160                 diff=time.time()-pcdatumjetzt
161                 if diff<0:
162                         diff=diff*(-1)
163                 if diff>30:
164                         return -1
165                 
166                 sql="SELECT * FROM logtable WHERE pcdatum>?"
167                 rows=self.db.ladeSQL(sql,(pcdatum,))
168                 logging.info("doSync read sqls")
169                 self.writeSQLTupel(newSQLs)
170                 logging.info("doSync wrote "+str(len(newSQLs))+" sqls")
171                 i=0
172                 return rows
173                 
174         def getRemoteSyncUUID(self):
175                 return self.sync_uuid
176         
177         
178         def startServer(self, widget, data=None):
179                 #Starte RPCServer
180                 self.db.speichereDirekt("syncServerIP",self.comboIP.get_child().get_text())
181                 
182                 if (widget.get_active()==True):
183                         logging.info("Starting Server")
184                         
185                         try:
186                                 ip=self.comboIP.get_child().get_text()
187                                 self.rpcserver = SimpleXMLRPCServer((ip, self.port),allow_none=True) 
188                                 self.rpcserver.register_function(pow)
189                                 self.rpcserver.register_function(self.getLastSyncDate)
190                                 self.rpcserver.register_function(self.doSync)
191                                 self.rpcserver.register_function(self.getRemoteSyncUUID)
192                                 self.rpcserver.register_function(self.doSaveFinalTime)
193                                 self.rpcserver.register_function(self.pulse)
194                                 self.poll=select.poll()
195                                 self.poll.register(self.rpcserver.fileno())
196                                 gobject.timeout_add(1000, self.handleRPC)
197                                 self.syncServerStatusLabel.set_text("Syncserver running...")
198                         
199                                 #save
200                                 self.db.speichereDirekt("startSyncServer",True)
201                         except:
202                                 s=str(sys.exc_info())
203                                 logging.error("libsync: could not start server. Error: "+s)
204                                 mbox=gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_ERROR,gtk.BUTTONS_OK,"Konnte Sync-Server nicht starten. Bitte IP und Port überprüfen.") #gtk.DIALOG_MODAL
205                                 mbox.set_modal(False)
206                                 response=mbox.run() 
207                                 mbox.hide() 
208                                 mbox.destroy() 
209                                 widget.set_active(False)
210                                 
211                 else:
212                         logging.info("Stopping Server")
213                         try:
214                                 del self.rpcserver      
215                         except:
216                                 pass
217                         self.syncServerStatusLabel.set_text("Syncserver not running...")
218                         #save
219                         self.db.speichereDirekt("startSyncServer",False)
220                 
221         def doSaveFinalTime(self,sync_uuid,pcdatum=None):
222                 if (pcdatum==None): pcdatum=int(time.time())
223                 if (time.time()>pcdatum):
224                         pcdatum=int(time.time()) #größere Zeit nehmen
225                         
226                 self.pulse()
227                 
228                 #fime save time+uuid
229                 sql="DELETE FROM sync WHERE uuid=?"
230                 self.db.speichereSQL(sql,(sync_uuid,),log=False)
231                 sql="INSERT INTO sync (syncpartner,uuid,pcdatum) VALUES (?,?,?)"
232                 self.db.speichereSQL(sql,("x",str(sync_uuid),pcdatum),log=False)
233                 self.emit("syncFinished","syncFinished")
234                 self.pulse()
235                 self.changeSyncStatus(False,"no sync process (at the moment)")
236                 return (self.sync_uuid,pcdatum)
237                 
238         
239         def syncButton(self, widget, data=None):
240                 logging.info("Syncing")
241                 #sql="DELETE FROM logtable WHERE sql LIKE externeStundenplanung"
242                 #self.db.speichereSQL(sql)
243                 
244                 self.changeSyncStatus(True,"sync process running")
245                 while (gtk.events_pending()):
246                         gtk.main_iteration();
247                 self.emit("syncBeforeStart","syncBeforeStart")
248
249                 self.db.speichereDirekt("syncRemoteIP",self.comboRemoteIP.get_child().get_text())
250                 try:
251                         self.server = xmlrpclib.ServerProxy("http://"+self.comboRemoteIP.get_child().get_text()+":"+str(self.port),allow_none=True) 
252                         #lastDate=server.getLastSyncDate(str(self.sync_uuid))
253                         server_sync_uuid=self.server.getRemoteSyncUUID()
254                         lastDate=self.getLastSyncDate(str(server_sync_uuid))
255                         
256                         print ("LastSyncDate: "+str(lastDate)+" Now: "+str(int(time.time())))
257                 
258                         sql="SELECT * FROM logtable WHERE pcdatum>?"
259                         rows=self.db.ladeSQL(sql,(lastDate,))
260                 
261                         newSQLs=self.server.doSync(self.sync_uuid,lastDate,rows,time.time())
262                 
263                         logging.info("did do sync, processing sqls now")
264                         if newSQLs!=-1:
265                                 self.writeSQLTupel(newSQLs)
266         
267                                 sync_uuid, finalpcdatum=self.server.doSaveFinalTime(self.sync_uuid)
268                                 self.doSaveFinalTime(sync_uuid, finalpcdatum)
269                         
270                                 self.changeSyncStatus(False,"no sync process (at the moment)")
271                                 
272                                 mbox =  gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_INFO,gtk.BUTTONS_OK,"Synchronisation erfolgreich beendet") 
273                                 response = mbox.run() 
274                                 mbox.hide() 
275                                 mbox.destroy() 
276                         else:
277                                 logging.warning("Zeitdiff zu groß/oder anderer db-Fehler")
278                                 self.changeSyncStatus(False,"no sync process (at the moment)")
279                                 mbox =  gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_INFO,gtk.BUTTONS_OK,"Zeit differiert zu viel zwischen den Systemen") 
280                                 response = mbox.run() 
281                                 mbox.hide() 
282                                 mbox.destroy() 
283                                 self.emit("syncFinished","syncFinished")
284                         
285                 except:
286                                 logging.warning("Sync connect failed")
287                                 self.changeSyncStatus(False,"no sync process (at the moment)")
288                                 mbox =  gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_INFO,gtk.BUTTONS_OK,"Sync gescheitert. Fehler:"+str(sys.exc_info()))
289                                 response = mbox.run() 
290                                 mbox.hide() 
291                                 mbox.destroy() 
292                                 self.server=None
293                                 self.emit("syncFinished","syncFinished")
294                 self.server=None
295                                 
296
297                         
298         
299         def __init__(self,db,parentwindow,port):
300                 gtk.VBox.__init__(self,homogeneous=False, spacing=0)
301                 
302                 logging.info("Sync, init")
303                 self.db=db
304                 self.progress=None
305                 self.server=None
306                 self.port=int(port)
307                 self.parentwindow=parentwindow
308                 
309                 #print "Sync, 2"
310                 #sql = "DROP TABLE sync"
311                 #self.db.speichereSQL(sql,log=False)
312                 
313                 sql = "CREATE TABLE sync (id INTEGER PRIMARY KEY, syncpartner TEXT, uuid TEXT, pcdatum INTEGER)"
314                 self.db.speichereSQL(sql,log=False)
315                 
316                 #print "Sync, 3"
317                 
318                 sql="SELECT uuid,pcdatum FROM sync WHERE syncpartner=?"
319                 rows=self.db.ladeSQL(sql,("self",)) #Eigene Id feststellen
320                 
321                 #print "Sync, 3a"
322                 if (rows==None)or(len(rows)!=1):
323                         sql="DELETE FROM sync WHERE syncpartner=?"
324                         self.db.speichereSQL(sql,("self",),log=False)
325                         #uuid1=uuid()
326                         #print "Sync, 3b"
327                         
328                         #print "Sync, 3bb"
329                         self.sync_uuid=str(uuid.uuid4())
330                         sql="INSERT INTO sync (syncpartner,uuid,pcdatum) VALUES (?,?,?)"
331                         self.db.speichereSQL(sql,("self",str(self.sync_uuid),int(time.time())),log=False)
332                         #print "Sync, 3c"
333                 else:
334                         sync_uuid,pcdatum = rows[0]
335                         self.sync_uuid=sync_uuid
336                 #print "x1"
337                 
338                 
339                 
340                 #print "Sync, 4"
341
342                 
343                 frame=gtk.Frame("LokalerSync-Server (Port "+str(self.port)+")")
344                 
345                 
346                 
347                 self.comboIP=gtk.combo_box_entry_new_text()
348                 
349                 
350                 self.comboIP.append_text("") #self.get_ip_address("eth0"))
351                 #self.comboIP.append_text(self.get_ip_address("eth1")) #fixme
352                 #self.comboIP.append_text(self.get_ip_address("eth2"))
353                 #self.comboIP.append_text(self.get_ip_address("eth3"))
354                 #print "Sync, 4d"
355                 #self.comboIP.append_text(self.get_ip_address("wlan0"))
356                 #self.comboIP.append_text(self.get_ip_address("wlan1"))
357                 
358                 #print "Sync, 4e"
359                 
360                 frame.add(self.comboIP)
361                 serverbutton=gtk.ToggleButton("SyncServer starten")
362                 serverbutton.connect("clicked",self.startServer,(None,))
363                 self.pack_start(frame, expand=False, fill=True, padding=1)
364                 self.pack_start(serverbutton, expand=False, fill=True, padding=1)
365                 self.syncServerStatusLabel=gtk.Label("Syncserver not running")
366                 self.pack_start(self.syncServerStatusLabel, expand=False, fill=True, padding=1)         
367                                 
368                 frame=gtk.Frame("RemoteSync-Server (Port "+str(self.port)+")")
369                 self.comboRemoteIP=gtk.combo_box_entry_new_text()
370                 self.comboRemoteIP.append_text("192.168.0.?")
371                 self.comboRemoteIP.append_text("192.168.1.?")
372                 self.comboRemoteIP.append_text("192.168.176.?")
373                 frame.add(self.comboRemoteIP)
374                 syncbutton=gtk.Button("Verbinde zu Remote-SyncServer")
375                 syncbutton.connect("clicked",self.syncButton,(None,))
376                 self.pack_start(frame, expand=False, fill=True, padding=1)
377                 self.pack_start(syncbutton, expand=False, fill=True, padding=1)
378                 self.syncStatusLabel=gtk.Label("no sync process (at the moment)")
379                 self.pack_start(self.syncStatusLabel, expand=False, fill=True, padding=1)
380
381
382                 #self.comboRemoteIP.set_text_column("Test")
383                 self.comboRemoteIP.get_child().set_text(self.db.ladeDirekt("syncRemoteIP"))
384                 self.comboIP.get_child().set_text(self.db.ladeDirekt("syncServerIP"))
385                 
386                 #load
387                 if (self.db.ladeDirekt("startSyncServer",False)==True):
388                         serverbutton.set_active(True)
389                         
390                 #print "Sync, 9"