!jxUdZddlZddlZddlZddlmZddlmZdZda ej e d<ej Z defdZdefd Zd ed efd Zdefd ZdefdZdejddfdZdefdZdefdZdeddfdZdefdZdZdZdZdZ dS)ua Sincronizzazione shared_db/mediatrack.db tra locale e server. - pull_from_server(): copia server→locale se server più recente (mtime) - push_to_server(): copia locale→server via SQLite backup API + file lock - start_background_sync() / stop_background_sync(): timer ogni N minuti - pull_ott_db(): copia ott.db server→locale (one-way, no merge) N)Path)loggerc<ddlm}m}||dfS)Nrget_sync_config get_db_path mediatrack)app.config_loaderrrrs 4C:\PYTHON\MyICR_Suite\launcher_src\shared_db_sync.py_get_sync_configr s7>>>>>>>> ?  kk,77 77_timerreturnc.ddlm}|dz dz S)zOPercorso del file cache che ricorda l'ultima versione del server sincronizzata.r get_app_rootlauncher_cachezshared_db_pull.json)r rrs r _pull_cache_pathrs,...... <>>, ,/D DDr ct}|r> ddl}||dS#t $rYnwxYwiS)Nrutf-8encoding)rexistsjsonloads read_text Exception)cachers r _read_pull_cacher!sp   E ||~~  KKK::eoowo??@@ @    D  Is,A AAmtimesizecddl}t}|jdd||||dddS)NrTparentsexist_ok)r r!rr)rrparentmkdir write_textdumps)r r!rrs r _write_pull_cacher*,sdKKK   E Ltd333 TZZ% > >??'RRRRRr c #$% t\}}t|dd}|st jd|dS|}t}|d|jko1|d|j ko|}|rt j ddSi}|r tj t|}tj|_d|d D}d |d D} d |d D} |d|d|d|| | d}|n.#t&$r!} t jd| Yd} ~ nd} ~ wwxYwddl} |jdd|d} | t|t| | |t5|j|j t jd|sdStj t|}|d}|d} |d} d| D}dt9| D#t;d|dD}t;d |d!D}t;d"|d#D}t;d$|d%D}d&d'gt?|z}d&d'gt?|z}d&d'gt?| z}d(|d)D}t;}d*t9|D}|d+D]ڊ%%d}t| d,st%|d-pd!"t%|d.pd!"f}||}|r|#||r't jd/t?|d0|dx}x}}|d+D]b%%d|vrV%d|vrL%d|vrB|d1d&|d2|d3tI%|d4z }c|d5D]ڊ%%#d6$$|vrtK$fd7|d+Dd} | rt| |d-pd!"t| |d.pd!"f}||$$$t%#d8pdt%#d9pdt%#d:pdt%#d;pdt%#d<pdf}||vrvtM#%fd=|D}!$|!|'d6<|d>d&|d2|d3tI|!|d4z }|d?D]f%%d4pd!}"|"rF|"|vrB|d@d&| d2|d3tI%|d4z }g|dA|(|||z|zdkr,t jdB|dC|dD|dEtSdS#t&$r"} t j*dF| Yd} ~ dSd} ~ wwxYw)Gu& Sync principale al bootstrap. Principio: server = fonte di verità. 1. Rileva se il server è cambiato dall'ultimo pull. 2. Fa uno snapshot dei record locali. 3. Sovrascrive il locale con il server (server vince). 4. Ri-applica on top i record che esistevano solo in locale (prodotti, eventi, distributori non ancora sul server). 5. Se ci sono aggiunte locali, le pusha al server. Questo garantisce che nessun lavoro locale venga perso anche se nel frattempo un altro utente ha modificato il server. server_path![sync] Server non raggiungibile: Fr r!uC[sync] pull_and_preserve_local: server invariato — nessuna azionecg|] }|d S.0cs r z+pull_and_preserve_local..]sjjjqadjjjr "PRAGMA table_info(AnagraficaMedia)cg|] }|d Sr0r2r3s r r6z+pull_and_preserve_local..^skkkqadkkkr #PRAGMA table_info(LogAggiornamenti)cg|] }|d Sr0r2r3s r r6z+pull_and_preserve_local.._sgggqadgggr PRAGMA table_info(Distributori)SELECT * FROM AnagraficaMediaSELECT * FROM LogAggiornamentiSELECT * FROM Distributori)medialogdistr media_colslog_cols distr_colsz [sync] Snapshot locale fallito: NrTr#.tmpu*[sync] Pull completato (server → locale)rBrCrDcg|] }|dk| Sid_aggiornamentor2r3s r r6z+pull_and_preserve_local..~s#III6H1H1H!1H1H1Hr ci|]\}}|| Sr2r2r4ir5s r z+pull_and_preserve_local..s4441q!444r c3&K|] }|dV dSrNr2r4rs r z*pull_and_preserve_local..s7  AaD      r z$SELECT id_media FROM AnagraficaMediac3&K|] }|dV dSrNr2rOs r rQz*pull_and_preserve_local..s7! ! AaD! ! ! ! ! ! r ASELECT id_media FROM AnagraficaMedia WHERE deleted_at IS NOT NULLc 3K|]{}|dt|dpdt|dpdt|dpdt|dpdt|dpdfV|dS)rr1r-NstrrOs r rQz*pull_and_preserve_local..s  qT3qtzr??C! OOS1__c!A$*RTooWZ[\]^[_[eceWfWf g      r zSELECT id_media_fk, id_tipo_evento_fk, COALESCE(data_evento,''), COALESCE(dettaglio_contesto,''), COALESCE(note,''),COALESCE(id_distributore_fk,'') FROM LogAggiornamentic3NK|] }|dpdV!dS)rr-NlowerrOs r rQz*pull_and_preserve_local..sJ! ! qTZR   ! ! ! ! ! ! r zSELECT nome FROM Distributori,?ci|]}t|dpdt|dpdf|dS)rr-r1rU)rZr]striprOs r rLz+pull_and_preserve_local..s   1__ " " $ $ * * , ,c!A$*"oo.C.C.E.E.K.K.M.M NPQRSPT   r zcSELECT titolo_ufficiale, distributore_nome, id_media FROM AnagraficaMedia WHERE id_media LIKE 'G_%'ci|]\}}|| Sr2r2rJs r rLz+pull_and_preserve_local..s888$!QA888r r?G_titolo_ufficialedistributore_nomez[sync] Merge: ignorati z( record MT sostituiti da G_ sul server: 'INSERT OR IGNORE INTO AnagraficaMedia ( ) VALUES ()r1r@ id_media_fkc34K|]}|dk|VdSrNr2)r4rPris r rQz*pull_and_preserve_local..s1OO11Q4;;N;NQ;N;N;N;NOOr id_tipo_evento_fk data_eventodettaglio_contestonoteid_distributore_fkc34K|]}|VdS)Nr2)r4r5colrows r rQz*pull_and_preserve_local..s+@@ACAK@@@@@@r INSERT INTO LogAggiornamenti (rAz$INSERT OR IGNORE INTO Distributori (zLUPDATE AnagraficaMedia SET is_offline_insert = 0 WHERE is_offline_insert = 1z[sync] Merge locale: +z media, + log, + distributoriz([sync] pull_and_preserve_local fallito: )+r rgetrrwarningstatrst_mtimest_sizedebugsqlite3connectrZRow row_factoryexecutefetchallclosershutilr&r' with_suffixcopy2replacer*info enumeratesetjoinlen startswithr]raaddtuplenextlistindexcommitpush_to_servererror)& sync_configlocal_dbr,stcachedserver_unchangedlocal_snapshotsnaprBrCrDertmpconlog_cols_no_idserver_media_idsserver_deleted_idsserver_log_keysserver_distr_namesph_mph_lph_dserver_g_indexmt_superseded_by_gm_idxid_mkeyg_id ins_mediains_log ins_distrmt_rowvalsnomerqrirrs& @@@r pull_and_preserve_localr3s x 0 2 2 X;??="==>> !!##  NL{LL M M M5     !## JJw  2; .  JJv  "* ,  OO      L^ _ _ _5 ??   G Gs8}}55#*; jjDLL9],^,^,g,g,i,ijjj kkDLL9^,_,_,h,h,j,jkkkggDLL9Z,[,[,d,d,f,fggg #',,/N"O"O"X"X"Z"Z"&,,/O"P"P"Y"Y"["["&,,/K"L"L"U"U"W"W","*", ""  G G GE!EEFFFFFFFF G  dT:::""6** S%%s3xx000 H"+rz222 @AAA 4oc(mm,,#L1 #J/#L1 IIXIII44 ( 3 3444  ++&LMMVVXX     !! ! ++Shjj! ! !      [[) hjj     !! ! [[!@AAJJLL! ! !    xxJ/00xxN 3 3344xxJ/00  [[Ahjj    !UU88)J"7"7888!'* 1 1Cq6Dt99''-- 1E"456<"==CCEEKKMME"567=2>>DDFFLLNN&))#..1&**4000   KE#.@*A*AEE0BEE    +,+ +Gi!'*  C1v---#a&@R2R2RWZ[\W]ewWwWw echhz>R>Ree^beee#JJQ !%(  Cc-01K000OOOOw 7OOOQUGF5);#<=CDDJJLLRRTTF5)<#=>D"EEKKMMSSUUC#1"4"4S+"F"FKC/017R88CM*+1r22C0128b99CF $*++C0128b99 C/))@@@@@@@@@@z._ensure_updated_cols_server..0s[[[![[[r r7) updated_at updated_by deleted_atz'ALTER TABLE AnagraficaMedia ADD COLUMN z TEXTN)rrrr)rcolsrqs r _ensure_updated_cols_serverr-s [[ckk*NOOXXZZ[[[= R RC$ PcPPPQQQ      sA'A++ A98A9c *+ t\}}|ddstjddSt |dd}|jstjd|jdS|stjd|dS|jd z }d }|rbtj| j z }||kr/tjd |d d | dd}|r9|dkr3tj d|dz }|r|dk3|rtjddS|  tjt!|}tj|_tjt!|d}tj|_t'| d|dD} d|dD} d|dD} d| D} d| D} ddgt/| z}ddgt/| z}ddgt/| z}d|d D}t1|}t1d!|d"D}d#|d$D}dx}x}x}}i}|d%D]++d&pd}|s!||vr ||}+d'|kr ||+d'<E+fd(| D}|d)d| d*|d+t7|}|j}||+d'<|||<|dz }d,|d-D}d.| D} dd/| D}!|d D]++d0|vrN+d0|vr|d1d| d*|d+t7+|dz }Z|+d0}"d2+vr+d2nd3}#d2|"vr|"d2nd3}$|#rL|$r|#|$krD+fd4| D+d0gz}|d5|!d6t7||dz }|d7D]++d8**|vr|**+d9}%t!|%pdt!+d:pdt!+d;pdt!+d<pdt!+d=pdt!*pdf}&|&|vrQ*+fd>| D}|d?d| d*|d+t7||dz }||r|D]\}'}|d@||'f|D]\}'}|dA||'f|tjdBt/|dC||z|z|zdkrPtjdD|dE|dF|dG|dH | }(tA|(j |(j!ntjdI |"|"| ddS#|"|"wxYw#| dwxYw#tF$r"})tj$dJ|)Yd3})~)dSd3})~)wwxYw)Ku Push incrementale: invia al server solo i record non ancora presenti. Non sovrascrive mai record esistenti — server e' fonte di verita'. Logica: - AnagraficaMedia: push per id_media non presente su server - Distributori: push per nome non presente su server (senza id locale, server assegna nuovo id); rimappa FK in locale se id differisce - LogAggiornamenti: push per chiave contenuto (con id_distributore_fk rimappato) push_enabledTz.[sync] Push disabilitato (push_enabled: false)Fr,r-r.z[sync] DB locale non trovato: zmediatrack.lock<z[sync] Lock stale rilevato (z.0fus) — rimosso missing_okr r1u7[sync] Push annullato — lock non rilasciato entro 10s>@timeoutcg|] }|d Sr0r2r3s r r6z"push_to_server..qs#u#u#uQAaD#u#u#ur r7cg|] }|d Sr0r2r3s r r6z"push_to_server..rs#v#v#vQAaD#v#v#vr r9cg|] }|d Sr0r2r3s r r6z"push_to_server..ss#r#r#rQAaD#r#r#rr r;cg|] }|dk| SrGr2r3s r r6z"push_to_server..ts##U#U#U!QBT=T=TA=T=T=Tr cg|] }|dk| S)id_distributorer2r3s r r6z"push_to_server..us##T#T#T!QBS=S=SA=S=S=Sr r^r_c i|] }|d| Sid_mediar2rOs r rLz"push_to_server..|s.%%%jM1%%%r r<c 3"K|]}t|dpdt|dpdt|dpdt|dpdt|dpdt|dpdfVdS)rr-r1rUrVrWrXNrYrOs r rQz!push_to_server..s & &1__c!A$*"oos1Q4:21__c!A$*"oos1Q4:2H & & & & & &r zSELECT id_media_fk, id_tipo_evento_fk, COALESCE(data_evento,''), COALESCE(dettaglio_contesto,''), COALESCE(note,''), COALESCE(id_distributore_fk,'') FROM LogAggiornamenticTi|]%}|dpd|d&S)rr-r1r\rOs r rLz"push_to_server..sB(((qTZR&&((!A$(((r z.SELECT nome, id_distributore FROM Distributorir>rrc g|] }| Sr2r2r4r5rrs r r6z"push_to_server..sAAA1AAAAr zINSERT INTO Distributori (rgrhch|] }|d S)rr2rOs r rz!push_to_server..s)&&&AaD&&&r rScg|]}|dv| S))ris_offline_insertr2r3s r r6z"push_to_server..s#!f!f!f1De;e;e!;e;e;er cg|]}|dS)z=?r2r3s r r6z"push_to_server..s"D"D"Da888"D"D"Dr rrfrNc g|] }| Sr2r2rs r r6z"push_to_server..s#C#C#CqCF#C#C#Cr zUPDATE AnagraficaMedia SET z WHERE id_media = ?r=rorirkrlrmrnc0g|]}|dkrn|S)ror2)r4r5 id_distr_fkrrs r r6z"push_to_server..s<    !,-0D+D+DKK#a&   r rszOUPDATE LogAggiornamenti SET id_distributore_fk = ? WHERE id_distributore_fk = ?zEUPDATE Distributori SET id_distributore = ? WHERE id_distributore = ?z[sync] Push: rimappati z id distributori in localezync] Push incrementale: +z media nuovi, ~z media aggiornati, +rtruz-[sync] Push: nessuna novita' da sincronizzarez"[sync] Push incrementale fallito: )%r rvrr{rr&rrwtimerxryunlinksleeptouchr|r}rZr~rrrrrrrkeysr]r lastrowidritemsrr*rzrrr),rrr, lock_fileLOCK_STALE_SECONDSlock_agewaited local_con server_conrBrCrDrdistr_cols_no_idrrrserver_media_rowsrrserver_distr_by_nomer upd_mediarrid_remapr server_idrcurnew_idrmedia_upd_colsph_updsrv local_updsrv_updrirold_idrrrrrs, @@r rr9s J 0 2 2 X~t44  LI J J J5;??="==>> !((**  NS{?QSS T T T5    NFHFF G G G5&)::       2y{{Y^^%5%5%>>H,,,ZhZZZZ[[[  D 111   Vb[[ JqMMM aKF   Vb[[       NT U U U5b .H 66I$+KI ! [)9)94HHHJ%,[J " ' 3 3 3X ##u#u)2C2CDh2i2i2r2r2t2t#u#u#u #v#v)2C2CDi2j2j2s2s2u2u#v#v#v#r#r)2C2CDe2f2f2o2o2q2q#r#r#r #U#Ux#U#U#U#T#Tz#T#T#T xxJ 788xxN(;(; ;<<xx,<(=(= =>>%%'//0OPPYY[[%%%!$''8'='='?'?#@#@ "% & &(//0 hjj & & & # #(('//0`aajjll((($ ?@? ?I?)%,,-IJJSSUU''CK-24466D! 333$8$> 01Y>>?HHS):%;<AAAA0@AAA(00fBR9S9Sff_cfff!$KK"%;A%6!785;,T2!Q &&","4"4[##hjj&&&""g!fZ!f!f!f"D"D^"D"D"DEE$,,-LMMVVXX++C:.>>>z?.@@@$"**mchhzFZFZmmfjmmm!#JJ"Q 0J@9E9S9SC $5$5Y] 7Csxxzz7Q7Q#l"3"3W[$+g+W9L9L#C#C#C#CN#C#C#Cs:FW#WD&.. Yf Y Y Y %d &NI%,,-MNNWWYY%%C"%&:";K"h..&.{&; "%m"4KK-2..C 34:;;C .4"55C 45;<<CK-2..K-2.. C/11     %3   #**hSXXn=U=Uhhaehhh!$KK 1 !!### e*2..*:*:!));=CVBBKEiEE%EE#EE,5EEE %))++B%bk2:>>>>L!PQQQ!!!  """     - - - - - !!!  """"     - - - -  =!==>>>uuuuusc;eAe+eC9eeA5d-Y1d(d-(e*d**d--ee e4e//e4c  t\}}t|dd}|r|sdSt jt |}tj|_| d }|s| dSd|D}tj dt|dd| d  D}d | d  D}t jt |d } |D]} | dd|d| f} | rcddgt|z} | dd|d| dt#| | dd|d| f } | D]} t%t'|| }| d|d|d|d|df}|scddgt|z} | dd|d| dt#| |tj dt|d| n#| wxYwddgt|z} | d| d||t+|| t|S#t,$r"}tjd|Yd}~dSd}~wwxYw) z Inserisce nel DB server i prodotti creati offline (is_offline_insert=1). Merge selettivo: non sovrascrive i dati esistenti sul server. Returns: numero di prodotti sincronizzati (0 se nessuno o errore). r,r-rz@SELECT id_media FROM AnagraficaMedia WHERE is_offline_insert = 1cg|] }|d Srr2rOs r r6z(push_offline_inserts..)s666q}666r z[sync] push_offline_inserts: z prodotti da sincronizzarec6g|]}|ddk|dS)r1rr2rOs r r6z(push_offline_inserts..-s5333Ad111Q4111r r7c6g|]}|ddk|dS)r1rHr2rOs r r6z(push_offline_inserts..2s5333Qt111aD111r r9rrzSELECT z, z( FROM AnagraficaMedia WHERE id_media = ?r_rfrgrhz, FROM LogAggiornamenti WHERE id_media_fk = ?aK SELECT 1 FROM LogAggiornamenti WHERE id_media_fk = ? AND id_tipo_evento_fk = ? AND COALESCE(data_evento,'') = COALESCE(?,'') AND COALESCE(dettaglio_contesto,'') = COALESCE(?,'') LIMIT 1 rirkrlrmrsz" prodotti sincronizzati sul serverzDUPDATE AnagraficaMedia SET is_offline_insert = 0 WHERE id_media IN (z%[sync] push_offline_inserts fallito: N)r rrvrr|r}rZr~rrrrrrrrfetchonerdictzipr_cleanup_offline_artifactsrr)rrr, local_connpending pending_idsam_colsrC server_connrrr placeholderslog_rowslog_rowrow_dictrrs r push_offline_insertsr s a 0 2 2 X;??="==>> !!## 8??+<+< 1_S]]33 !( $$ N  (**        166g666  `C 4D4D```aaa33!3!34X!Y!Y!b!b!d!d333 33*"4"45Z"["["d"d"f"f333oc+&6&6EEE / ') ) !((Zdii00ZZZK(**#'99cUS\\-A#B#BL''o$))GBTBToo`loooc &--_dii11___K(** (G#C'$:$:;;H(002! ]33 %899 ]33 %9::    xzz"'+yy#X1F'G'G #++kTYYx=P=Pkk\hkkk!'NN#,    KlK8H8Hlll m m m       K      yy#[)9)9!9::  bS_ b b b      #8,,,;  @Q@@AAAqqqqqs@AQ A/Q B6Q H$O,Q OBQ R *RR rc |jdz }|r.|dD]}|d|jdz }|r|dt jddS#t $r"}t jd|Yd}~dSd}~wwxYw) zRRimuove backup offline e log JSONL dopo sync riuscito (dati al sicuro sul server).backupszmediatrack_*.dbTrzoffline_inserts_log.jsonlz+[sync] Cleanup offline artifacts completatoz*[sync] Cleanup offline artifacts fallito: N)r&rglobrrrrrw)r backup_dirflog_filers r rr{s I_y0      *__%677 * *D))))?%@@ ??   - OOtO , , , ABBBBB IIIGAGGHHHHHHHHHIsBB C"B??Cc* ddl}ddlm}|dz dz dz dz }|sdS||d }t |d d }|d d}||z }|stj d|dS| }|rZ| j |j kr8| j |j krtj ddSddl}|jdd|d} |t'|t'| | |tjddS#t,$r"} tjd| Yd} ~ dSd} ~ wwxYw)u Copia ott.db dal server in locale se il server ha una versione più recente. Flusso one-way: server → locale (nessun merge, nessun push). rNrappmoduleslinkerz config.jsonFrrott_db_server_pathr-ott_db_local_pathzlocal_db/ott.dbz%[ott_sync] Server non raggiungibile: u4[ott_sync] ott.db già aggiornato — nessuna azioneTr#rEu5[ott_sync] Pull ott.db completato (server → locale)z [ott_sync] pull_ott_db fallito: )rr rrrrrrvrrwrxryrzr{rr&r'rrrZrrrr) rr config_pathcfgr, local_rel local_pathrrrrs r pull_ott_dbrs%  222222"lnnu,y88CmS !!## 5jj...@@AA377#7<<== gg13DEE "lnny0 !!##  NP;PP Q Q Q5           !!*bk99!!)RZ77 LO P P P5 t<<<$$V,, S%%s3xx000 J KLLLt  ;;;<<<uuuuus+4G&BG&BG&BG&& H0H  Hc>ttdS)z"Esegue push e reschedula il timer.N)r _rescheduler2r r _background_pushrsMMMMMr c@ t\}}|dddz}n#t$rd}YnwxYwt5t j|t adt_t ddddS#1swxYwYdS)z*Reschedula il timer per il prossimo ciclo.interval_minutesrXri,TN) r rvr _timer_lock threadingTimerrrdaemonstart)r_intervals r rrs)++ Q??#5q99B>  +;<<  s*- <<ABBBcJtjdtdS)z%Avvia il timer di sync in background.z[sync] Background sync avviatoN)rrrr2r r start_background_syncr)s  K0111MMMMMr ct5ttdadddn #1swxYwYtjddS)zFerma il timer di sync.Nz[sync] Background sync fermato)r!rcancelrrr2r r stop_background_syncr,s    MMOOOF K011111s #7;;)!__doc__r|r"rpathlibrlogururr rr#__annotations__Lockr!rrrfloatintr*boolrr Connectionrrr rrrrr)r,r2r r r6s 888  in E$EEEE $SUS#SSSSGGGGGT-$----`  W%7  D     UUUUUpgcggggT I I$ I I I I%T%%%%P    22222r