package Ġde . r ki . cor on aw arn app . di agnosis keys . download Ċ Ċ import Ġandroidx . annotation . Visible ForTesting Ċ import Ġdagger . Re usable Ċ import Ġde . r ki . cor on aw arn app . app config . AppConfig Provider Ċ import Ġde . r ki . cor on aw arn app . app config . Key Download Config Ċ import Ġde . r ki . cor on aw arn app . di agnosis keys . server . Di agnosis Key Server Ċ import Ġde . r ki . cor on aw arn app . di agnosis keys . server . Location Code Ċ import Ġde . r ki . cor on aw arn app . di agnosis keys . storage . Cached Key Ċ import Ġde . r ki . cor on aw arn app . di agnosis keys . storage . Cached Key Info . Type Ċ import Ġde . r ki . cor on aw arn app . di agnosis keys . storage . Key Cache Repository Ċ import Ġde . r ki . cor on aw arn app . di agnosis keys . storage . pkg DateTime Ċ import Ġde . r ki . cor on aw arn app . exception . http . C wa ServerError Ċ import Ġde . r ki . cor on aw arn app . exception . http . C wa Unknown Host Exception Ċ import Ġde . r ki . cor on aw arn app . exception . http . Network Connect TimeoutException Ċ import Ġde . r ki . cor on aw arn app . storage . Device Storage Ċ import Ġde . r ki . cor on aw arn app . util . Time And Date Extensions . to LocalDate Utc Ċ import Ġde . r ki . cor on aw arn app . util . TimeStamp er Ċ import Ġde . r ki . cor on aw arn app . util . coroutine . Dispatcher Provider Ċ import Ġkotlinx . coroutines . Coroutine Scope Ċ import Ġkotlinx . coroutines . Deferred Ċ import Ġkotlinx . coroutines . async Ċ import Ġkotlinx . coroutines . await All Ċ import Ġkotlinx . coroutines . with Context Ċ import Ġorg . joda . time . DateTime Zone Ċ import Ġorg . joda . time . Instant Ċ import Ġorg . joda . time . LocalDate Ċ import Ġorg . joda . time . Local Time Ċ import Ġtim ber . log . Tim ber Ċ import Ġjava . io . IOException Ċ import Ġjavax . inject . Inject Ċ Ċ @ Re usable Ċ class ĠHour Package Sync Tool Ġ@ Inject Ġconstructor ( ĊĠĠĠ Ġdevice Storage : ĠDevice Storage , ĊĠĠĠ Ġprivate Ġval Ġkey Server : ĠDi agnosis Key Server , ĊĠĠĠ Ġprivate Ġval Ġkey Cache : ĠKey Cache Repository , ĊĠĠĠ Ġprivate Ġval Ġdownload Tool : ĠKey Download Tool , ĊĠĠĠ Ġprivate Ġval Ġtime Stamp er : ĠTime Stamp er , ĊĠĠĠ Ġprivate Ġval Ġconfig Provider : ĠApp Config Provider , ĊĠĠĠ Ġprivate Ġval Ġdispatcher Provider : ĠDispatcher Provider Ċ ) Ġ: ĠBase Key Package Sync Tool ( ĊĠĠĠ Ġkey Cache Ġ= Ġkey Cache , ĊĠĠĠ Ġdevice Storage Ġ= Ġdevice Storage , ĊĠĠĠ Ġtag Ġ= ĠTAG Ċ ) Ġ{ ĊĊĠĠĠ Ġinternal Ġsuspend Ġfun Ġsync Missing Hour Packages ( ĊĠĠĠĠĠĠĠ Ġtarget Locations : ĠList < Location Code >, ĊĠĠĠĠĠĠĠ Ġforce Index Lookup : ĠBoolean ĊĠĠĠ Ġ): ĠSync Result Ġ{ ĊĠĠĠĠĠĠĠ ĠTim ber . tag ( TAG ). v (" sync Missing Hours ( target Locations =% s )", Ġtarget Locations ) ĊĊĠĠĠĠĠĠĠ Ġval Ġdownload Config : ĠKey Download Config Ġ= Ġconfig Provider . get AppConfig () ĊĠĠĠĠĠĠĠ Ġval Ġkeys W ere Rev oked Ġ= Ġre voke Cached Keys ( download Config . rev oked Hour Packages ) ĊĊĠĠĠĠĠĠĠ Ġval Ġmissing Hours Ġ= Ġtarget Locations . map NotNull Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdetermine Missing Hours ( it , Ġforce Index Lookup Ġ|| Ġkeys W ere Rev oked ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠC wa ServerError ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . tag ( TAG ). i (" missing Ġhours Ġsync Ġfailed Ġdue Ġto Ġnetwork Ġproblems ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠSync Result ( successful Ġ= Ġfalse , Ġnew Packages Ġ= Ġempty List ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ( missing Hours . isEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . tag ( TAG ). i (" There Ġwere Ġno Ġmissing Ġhours .") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠSync Result ( successful Ġ= Ġtrue , Ġnew Packages Ġ= Ġempty List ()) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ ĠTim ber . tag ( TAG ). d (" Downloading Ġmissing Ġhours : Ġ% s ", Ġmissing Hours ) ĊĠĠĠĠĠĠĠ Ġrequire Storage Space ( missing Hours ) ĊĊĠĠĠĠĠĠĠ Ġval Ġhour Downloads Ġ= Ġlaunch Downloads ( missing Hours , Ġdownload Config ) ĊĊĠĠĠĠĠĠĠ ĠTim ber . tag ( TAG ). d (" Waiting Ġfor Ġ% d Ġmissing Ġhour Ġdownloads .", Ġhour Downloads . size ) ĊĠĠĠĠĠĠĠ Ġval Ġdownloaded Hours Ġ= Ġhour Downloads . await All (). filter NotNull (). also Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . tag ( TAG ). v (" Downloaded Ġkey file : Ġ% s ", Ġit . join ToString ("\ n ")) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ ĠTim ber . tag ( TAG ). i (" Download Ġsuccess : Ġ${ downloaded Hours . size }/${ hour Downloads . size }") ĊĊĠĠĠĠĠĠĠ Ġreturn ĠSync Result ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġsuccessful Ġ= Ġhour Downloads . size Ġ== Ġdownloaded Hours . size , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġnew Packages Ġ= Ġdownloaded Hours ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Visible ForTesting ( otherwise Ġ= ĠVis ible ForTesting . PRIVATE ) ĊĠĠĠ Ġinternal Ġsuspend Ġfun Ġlaunch Downloads ( ĊĠĠĠĠĠĠĠ Ġmissing Hours : ĠCollection < Location Hours >, ĊĠĠĠĠĠĠĠ Ġdownload Config : ĠKey Download Config ĊĠĠĠ Ġ): ĠCollection < Deferred < Cached Key ? >> Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġlauncher : ĠCor outine Scope .( Location Hours , ĠLocalDate , ĠLocal Time ) Ġ-> ĠDeferred < Cached Key ?> Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ{ Ġlocation Data , Ġtarget Day , Ġtarget Hour Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġasync Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcached Key Ġ= Ġkey Cache . create Cache Entry ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlocation Ġ= Ġlocation Data . location , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġday Identifier Ġ= Ġtarget Day , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhour Identifier Ġ= Ġtarget Hour , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtype Ġ= ĠType . LOCATION _ HOUR ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdownload Tool . download Key File ( cached Key , Ġdownload Config ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠWe Ġcan 't Ġthrow Ġotherwise Ġit Ġcancel s Ġthe Ġother Ġdownloads Ġtoo Ġ( await All ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġdownloads Ġ= Ġmissing Hours ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. flatMap Ġ{ Ġlocation Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlocation . hour Data . map Ġ{ ĠTrip le ( location , Ġit . key , Ġit . value ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. flatMap Ġ{ Ġ( location , Ġday , Ġhours ) Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhours . map Ġ{ ĠTrip le ( location , Ġday , Ġit ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ ĠTim ber . tag ( TAG ). d (" Launch ing Ġ% d Ġdownloads .", Ġdownloads . size ) ĊĊĠĠĠĠĠĠĠ Ġreturn Ġdownloads . map Ġ{ Ġ( location , Ġday , Ġmissing Hour ) Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwith Context ( context Ġ= Ġdispatcher Provider . IO ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlauncher ( location , Ġday , Ġmissing Hour ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Visible ForTesting ( otherwise Ġ= ĠVis ible ForTesting . PRIVATE ) ĊĠĠĠ Ġinternal Ġfun Ġexpect New Hour Packages ( cached Hours : ĠList < Cached Key >, Ġnow : ĠInstant ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġtoday Ġ= Ġnow . to DateTime ( DateTime Zone . UTC ) ĊĠĠĠĠĠĠĠ Ġval Ġnewest Hour Ġ= Ġcached Hours . map Ġ{ Ġit . info . pkg DateTime Ġ}. max OrNull () ĊĊĠĠĠĠĠĠĠ Ġreturn Ġtoday . minus Hours ( 1 ). hour OfDay Ġ!= Ġnewest Hour ?. hour OfDay Ġ|| Ġtoday . to LocalDate () Ġ!= Ġnewest Hour . to LocalDate () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Visible ForTesting ( otherwise Ġ= ĠVis ible ForTesting . PRIVATE ) ĊĠĠĠ Ġinternal Ġsuspend Ġfun Ġdetermine Missing Hours ( ĊĠĠĠĠĠĠĠ Ġlocation : ĠLocation Code , ĊĠĠĠĠĠĠĠ Ġforce Index Lookup : ĠBoolean ĊĠĠĠ Ġ): ĠLocation Hours ? Ġ{ ĊĠĠĠĠĠĠĠ Ġ// Ġexisting Ġor Ġchecked Ġfiles Ġ-> Ġno Ġdownload Ġneeded ĊĠĠĠĠĠĠĠ Ġval Ġcached Hours Ġ= Ġget Cached Keys ( location , ĠType . LOCATION _ HOUR ) ĊĊĠĠĠĠĠĠĠ Ġval Ġnow Ġ= Ġtime Stamp er . now UTC ĊĊĠĠĠĠĠĠĠ Ġif Ġ(! force Index Lookup Ġ&& Ġ! expect New Hour Packages ( cached Hours , Ġnow )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . tag ( TAG ). d (" We Ġdon 't Ġexpect Ġnew Ġhour Ġpackages .") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġnull ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġtoday Ġ= Ġnow . to LocalDate Utc () ĊĊĠĠĠĠĠĠĠ Ġval Ġavailable Hours Ġ= Ġrun Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġhours Today Ġ= Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġkey Server . get Hour Index ( location , Ġtoday ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠNetwork Connect TimeoutException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . tag ( TAG ). e ( e , Ġ" Failed Ġto Ġget Ġtoday 's Ġhour Ġdue Ġ- Ġnot Ġgoing Ġto Ġdelete Ġthe Ġcache .") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow Ġe ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠC wa Unknown Host Exception ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . tag ( TAG ). e ( e , Ġ" Failed Ġto Ġget Ġtoday 's Ġhour Ġindex Ġ- Ġunknown Ġhost .") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow Ġe ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠIOException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . tag ( TAG ). e ( e , Ġ" failed Ġto Ġget Ġtoday 's Ġhour Ġindex .") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġempty List () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ ĠLocation Hours ( location , Ġmap Of ( today Ġto Ġhours Today )) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ// ĠIf Ġwe Ġhave Ġhours Ġthat Ġare Ġcovered Ġby Ġa Ġday , Ġdelete Ġthe Ġhours ĊĠĠĠĠĠĠĠ Ġval Ġcached Days Ġ= Ġget Cached Keys ( location , ĠType . LOCATION _ DAY ). map Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġit . info . day ĊĠĠĠĠĠĠĠ Ġ}. let Ġ{ ĠLocation Days ( location , Ġit ) Ġ} ĊĠĠĠĠĠĠĠ Ġval Ġstale Hours Ġ= Ġcached Hours . find St ale Data ( listOf ( cached Days , Ġavailable Hours )) ĊĠĠĠĠĠĠĠ Ġif Ġ( st ale Hours . isNotEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠTim ber . tag ( TAG ). v (" Deleting Ġstale Ġhours : Ġ% s ", Ġstale Hours ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġkey Cache . delete Info And File ( st ale Hours . map Ġ{ Ġit . info Ġ}) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ// Ġsubtract Ġkey Ġfiles Ġthat Ġare Ġnot Ġon Ġthe Ġserver Ġany Ġmore ĊĠĠĠĠĠĠĠ Ġval Ġnon St ale Hours Ġ= Ġcached Hours . minus ( st ale Hours ) ĊĊĠĠĠĠĠĠĠ Ġreturn Ġavailable Hours . to Missing Hours ( non St ale Hours ) Ġ// ĠThe Ġmissing Ġhours ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠTAG Ġ= Ġ" Hour Package Sync Tool " ĊĠĠĠ Ġ} Ċ } Ċ