package Ġfr . ac in q . phoenix . managers Ċ Ċ import Ġfr . ac in q . lightning . blockchain . elect rum . Elect rum Client Ċ import Ġfr . ac in q . lightning . blockchain . elect rum . Header Subscription Response Ċ import Ġfr . ac in q . lightning . io . Tcp Socket Ċ import Ġfr . ac in q . lightning . utils . Server Address Ċ import Ġfr . ac in q . lightning . utils . current Timestamp Millis Ċ import Ġfr . ac in q . phoenix . Ph o enix Business Ċ import Ġfr . ac in q . phoenix . data .* Ċ import Ġfr . ac in q . phoenix . db . Sqlite App Db Ċ import Ġio . ktor . client .* Ċ import Ġio . ktor . client . request .* Ċ import Ġio . ktor . utils . io . char sets .* Ċ import Ġio . ktor . utils . io . core .* Ċ import Ġkotlinx . coroutines .* Ċ import Ġkotlinx . coroutines . flow .* Ċ import Ġkotlinx . datetime . Clock Ċ import Ġorg . kode in . log . LoggerFactory Ċ import Ġorg . kode in . log . new Logger Ċ import Ġkotlin . math . max Ċ import Ġkotlin . time .* Ċ Ċ @ Opt In ( Experimental Cor outines Api :: class , ĠExperimental Time :: class , ĠExperimental Std lib Api :: class ) Ċ class ĠApp Configuration Manager ( ĊĠĠĠ Ġprivate Ġval Ġapp Db : ĠSql ite App Db , ĊĠĠĠ Ġprivate Ġval ĠhttpClient : ĠHttpClient , ĊĠĠĠ Ġprivate Ġval Ġelect rum Client : ĠElect rum Client , ĊĠĠĠ Ġprivate Ġval Ġchain : ĠChain , ĊĠĠĠ Ġlogger Factory : ĠLoggerFactory Ċ ) Ġ: ĠCor outine Scope Ġby ĠMain Scope () Ġ{ ĊĊĠĠĠ Ġconstructor ( business : ĠP ho enix Business ): Ġthis ( ĊĠĠĠĠĠĠĠ Ġlogger Factory Ġ= Ġbusiness . logger Factory , ĊĠĠĠĠĠĠĠ Ġchain Ġ= Ġbusiness . chain , ĊĠĠĠĠĠĠĠ Ġapp Db Ġ= Ġbusiness . app Db , ĊĠĠĠĠĠĠĠ ĠhttpClient Ġ= Ġbusiness . httpClient , ĊĠĠĠĠĠĠĠ Ġelect rum Client Ġ= Ġbusiness . elect rum Client ĊĠĠĠ Ġ) ĊĊĠĠĠ Ġprivate Ġval Ġlogger Ġ= Ġnew Logger ( logger Factory ) ĊĊĠĠĠ Ġinit Ġ{ ĊĠĠĠĠĠĠĠ Ġinit Wallet Context () ĊĠĠĠĠĠĠĠ Ġwatch Elect rum Messages () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ// ĠCalled Ġfrom ĠApp Connections Daemon ĊĠĠĠ Ġinternal Ġfun Ġenable Network Access () Ġ{ ĊĠĠĠĠĠĠĠ Ġstart Wallet Context Loop () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ// ĠCalled Ġfrom ĠApp Connections Daemon ĊĠĠĠ Ġinternal Ġfun Ġdisable Network Access () Ġ{ ĊĠĠĠĠĠĠĠ Ġstop Wallet Context Loop () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġval Ġcurrent Wallet Context Version Ġ= ĠWallet Context . Version . V 0 ĊĊĠĠĠ Ġprivate Ġval Ġ_ wallet Context Initialized Ġ= ĠMutable State Flow < Boolean >( false ) ĊĊĠĠĠ Ġprivate Ġval Ġ_ chain Context Ġ= ĠMutable State Flow < Wallet Context . V 0 . Chain Context ? >( null ) ĊĠĠĠ Ġval Ġchain Context : ĠState Flow < Wallet Context . V 0 . Chain Context ?> Ġ= Ġ_ chain Context ĊĊĠĠĠ Ġprivate Ġfun Ġinit Wallet Context () Ġ= Ġlaunch Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġ( timestamp , Ġlocal Context ) Ġ= Ġapp Db . get Wallet Context OrNull ( current Wallet Context Version ) ĊĊĠĠĠĠĠĠĠ Ġval Ġfresh ness Ġ= Ġ( Clock . System . now (). to Epoch Milliseconds () Ġ- Ġtimestamp ). milliseconds ĊĠĠĠĠĠĠĠ Ġlogger . info Ġ{ Ġ" local Ġcontext Ġwas Ġupdated Ġ$ fresh ness Ġago " Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġtimeout Ġ= Ġif Ġ( fresh ness Ġ< Ġ 4 8 . hours ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠ 2 . seconds ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmax ( fresh ness . in Days . toInt (), Ġ 5 ) Ġ* Ġ 2 . seconds ĊĠĠĠĠĠĠĠ Ġ} Ġ// Ġmax = 1 0 s ĊĊĠĠĠĠĠĠĠ Ġ// ĠTODO Ġare Ġwe Ġusing ĠTOR ? Ġ-> Ġincrease Ġtimeout ĊĊĠĠĠĠĠĠĠ Ġval Ġwallet Context Ġ= Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwith Timeout ( timeout ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfetch And Store Wallet Context () Ġ?: Ġlocal Context ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( t : ĠTimeout Cancellation Exception ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . warning Ġ{ Ġ" unable Ġto Ġrefresh Ġcontext Ġfrom Ġremote , Ġusing Ġlocal Ġfallback " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlocal Context ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ_ chain Context . value Ġ= Ġwallet Context ?. export ( chain ) ĊĠĠĠĠĠĠĠ Ġlogger . info Ġ{ Ġ" chain Context =$ chain Context " Ġ} ĊĊĠĠĠĠĠĠĠ Ġ_ wallet Context Initialized . value Ġ= Ġtrue ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġvar Ġupdate Wallet Context Job : ĠJob ? Ġ= Ġnull ĊĠĠĠ Ġprivate Ġfun Ġstart Wallet Context Loop () Ġ{ ĊĠĠĠĠĠĠĠ Ġlaunch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġsuspend Ġuntil Ġ` init Wallet Context ()` Ġis Ġcomplete ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ_ wallet Context Initialized . filter Ġ{ Ġit Ġ== Ġtrue Ġ}. first () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġupdate Wallet Context Job Ġ= Ġupdate Wallet Context Loop () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġstop Wallet Context Loop () Ġ{ ĊĠĠĠĠĠĠĠ Ġlaunch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġsuspend Ġuntil Ġ` init Wallet Context ()` Ġis Ġcomplete ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ_ wallet Context Initialized . filter Ġ{ Ġit Ġ== Ġtrue Ġ}. first () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġupdate Wallet Context Job ?. cancel And Join () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Opt In ( Experimental Time :: class ) ĊĠĠĠ Ġprivate Ġfun Ġupdate Wallet Context Loop () Ġ= Ġlaunch Ġ{ ĊĠĠĠĠĠĠĠ Ġvar Ġpause Ġ= Ġ 0 . 5 . seconds ĊĠĠĠĠĠĠĠ Ġwhile Ġ( isActive ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġpause Ġ= Ġ( pause Ġ* Ġ 2 ). coerce At Most ( 5 . minutes ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfetch And Store Wallet Context ()?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġchain Context Ġ= Ġit . export ( chain ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ_ chain Context . value Ġ= Ġchain Context ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġpause Ġ= Ġ 6 0 . minutes ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdelay ( pause ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġsuspend Ġfun Ġfetch And Store Wallet Context (): ĠWallet Context . V 0 ? Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġraw Data Ġ= ĠhttpClient . get < String >(" https :// ac in q . co / phoenix / wallet context . json ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġapp Db . set Wallet Context ( current Wallet Context Version , Ġraw Data ) ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( t : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . error ( t ) Ġ{ Ġ"${ t . message }" Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġnull ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġval Ġpublic Suffix List Key Ġ= Ġ" public Suffix List " ĊĠĠĠ Ġprivate Ġval Ġpublic Suffix List Default Refresh Ġ= Ġ 3 0 . days ĊĊĠĠĠ Ġpublic Ġsuspend Ġfun Ġfetch Public Suffix List ( ĊĠĠĠĠĠĠĠ Ġrefresh If Ol der Than : ĠDuration Ġ= Ġpublic Suffix List Default Refresh ĊĠĠĠ Ġ): ĠPair < String , ĠLong >? Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġdatabase Row Ġ= Ġapp Db . getValue ( public Suffix List Key ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠString ( bytes Ġ= Ġit , Ġcharset Ġ= ĠChar sets . UTF _ 8 ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ( database Row Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġelapsed Ġ= Ġcurrent Timestamp Millis () Ġ- Ġdatabase Row . second ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( elapsed . milliseconds Ġ<= Ġrefresh If Ol der Than ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġdatabase Row ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġlatest List : ĠString Ġ= Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠhttpClient . get (" https :// ac in q . co / phoenix / public _ suffix _ list . dat ") ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( err : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . warning Ġ{ Ġ" Error Ġfetching Ġpublic _ suffix _ list . dat : Ġ$ err " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġdatabase Row ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġlatest List Data Ġ= Ġlatest List . toByteArray ( charset Ġ= ĠChar sets . UTF _ 8 ) ĊĠĠĠĠĠĠĠ Ġval Ġrefresh Timestamp Ġ= Ġapp Db . setValue ( latest List Data , Ġpublic Suffix List Key ) ĊĠĠĠĠĠĠĠ Ġreturn ĠPair ( latest List , Ġrefresh Timestamp ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġpublic Ġsuspend Ġfun Ġprefetch Public Suffix List ( ĊĠĠĠĠĠĠĠ Ġrefresh If Ol der Than : ĠDuration Ġ= Ġpublic Suffix List Default Refresh ĊĠĠĠ Ġ): ĠDeferred < Pair < String , ĠLong > ?> Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġasync Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfetch Public Suffix List ( refresh If Ol der Than ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/* ĠThe Ġflow Ġcontaining Ġthe Ġconfiguration Ġto Ġuse Ġfor ĠElect rum . ĊĠĠĠĠ Ġ* ĠIf Ġnull , Ġwe Ġdo Ġnot Ġknow Ġwhat Ġconf Ġto Ġuse . ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġprivate Ġval Ġ_ elect rum Config Ġby Ġlazy Ġ{ ĠMutable State Flow < Elect rum Config ? >( null ) Ġ} ĊĠĠĠ Ġfun Ġelect rum Config (): ĠState Flow < Elect rum Config ?> Ġ= Ġ_ elect rum Config ĊĊĠĠĠ Ġfun Ġelect rum Server Address (): ĠServer Address ? Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġ_ elect rum Config . value ?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( it ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠElect rum Config . Custom Ġ-> Ġit . server ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠElect rum Config . Random Ġ-> Ġrandom Elect rum Server () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĠUse Ġthis Ġmethod Ġto Ġset Ġa Ġserver Ġto Ġconnect Ġto . ĠIf Ġnull , Ġwill Ġconnect Ġto Ġa Ġrandom Ġserver . Ġ*/ ĊĠĠĠ Ġfun Ġupdate Elect rum Config ( server : ĠServer Address ?) Ġ{ ĊĠĠĠĠĠĠĠ Ġ_ elect rum Config . value Ġ= Ġserver ?. let Ġ{ ĠElect rum Config . Custom ( it ) Ġ} Ġ?: ĠElect rum Config . Random ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġrandom Elect rum Server () Ġ= Ġwhen Ġ( chain ) Ġ{ ĊĠĠĠĠĠĠĠ ĠChain . Main net Ġ-> Ġelect rum Main net Configurations . random () ĊĠĠĠĠĠĠĠ ĠChain . Test net Ġ-> Ġelect rum Test net Configurations . random () ĊĠĠĠĠĠĠĠ ĠChain . Reg test Ġ-> Ġplatform Elect rum Reg test Conf () ĊĠĠĠ Ġ}. let Ġ{ ĊĠĠĠĠĠĠĠ ĠServer Address ( it . host , Ġit . ssl Port , ĠTcp Socket . TLS . UN SAFE _ CER TIF IC ATES ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĠThe Ġflow Ġcontaining Ġthe Ġelect rum Ġheader Ġresponses Ġmessages . Ġ*/ ĊĠĠĠ Ġprivate Ġval Ġ_ elect rum Messages Ġby Ġlazy Ġ{ ĠMutable State Flow < Header Subscription Response ? >( null ) Ġ} ĊĠĠĠ Ġfun Ġelect rum Messages (): ĠState Flow < Header Subscription Response ?> Ġ= Ġ_ elect rum Messages ĊĊĠĠĠ Ġprivate Ġfun Ġwatch Elect rum Messages () Ġ= Ġlaunch Ġ{ ĊĠĠĠĠĠĠĠ Ġelect rum Client . open Notifications Subscription (). consume As Flow (). filter Is Instance < Header Subscription Response >() ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. collect Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ_ elect rum Messages . value Ġ= Ġit ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ// ĠTor Ġconfiguration ĊĠĠĠ Ġprivate Ġval Ġis Tor Enabled Ġ= ĠMutable State Flow ( false ) ĊĠĠĠ Ġfun Ġsubscribe To Is Tor Enabled (): ĠState Flow < Boolean > Ġ= Ġis Tor Enabled ĊĠĠĠ Ġfun Ġupdate Tor Usage ( enabled : ĠBoolean ): ĠUnit Ġ{ ĊĠĠĠĠĠĠĠ Ġis Tor Enabled . value Ġ= Ġenabled ĊĠĠĠ Ġ} Ċ } Ċ