/* Ċ Ġ* ĠCopyright Ġ 2 0 2 0 ĠW illiam ĠSmith Ċ Ġ* ĠLicensed Ġunder Ġthe ĠApache ĠLicense , ĠVersion Ġ 2 . 0 Ġ( the Ġ" License "); Ġyou Ġmay Ġnot Ġuse Ġthis Ġfile Ġexcept Ġin Ġcompliance Ġwith Ġthe ĠLicense . ĠYou Ġmay Ġobtain Ġa Ġcopy Ġof Ġthe ĠLicense Ġat Ċ Ġ* Ċ Ġ* Ġhttps :// www . apache . org / licenses / LICENSE - 2 . 0 Ċ Ġ* Ċ Ġ* ĠUnless Ġrequired Ġby Ġapplicable Ġlaw Ġor Ġagreed Ġto Ġin Ġwriting , Ġsoftware Ġdistributed Ġunder Ġthe ĠLicense Ġis Ġdistributed Ġon Ġan Ġ" AS ĠIS " ĠBASIS , ĠWITHOUT ĠWARRANTIES ĠOR ĠCONDITIONS ĠOF ĠANY ĠKIND , Ġeither Ġexpress Ġor Ġimplied . Ċ Ġ* Ġ ĠSee Ġthe ĠLicense Ġfor Ġthe Ġspecific Ġlanguage Ġgoverning Ġpermissions Ġand Ġlimitations Ġunder Ġthe ĠLicense . Ċ Ġ*/ Ċ Ċ package Ġpro . w smi . room map . api Ċ Ċ import Ġcom . char les k orn . k aml . Yaml Ċ import Ġcom . github . aj alt . cli kt . core . Cli kt Command Ċ import Ġcom . github . aj alt . cli kt . parameters . options . flag Ċ import Ġcom . github . aj alt . cli kt . parameters . options . option Ċ import Ġcom . github . aj alt . cli kt . parameters . types . file Ċ import Ġpro . w smi . room map . api . config . Backend Configuration Ċ import Ġpro . w smi . room map . api . matrix . api . Public Room List Req 2 0 0 Response Ċ import Ġkotlinx . coroutines . delay Ċ import Ġkotlinx . coroutines . launch Ċ import Ġkotlinx . coroutines . run Blocking Ċ import Ġkotlinx . serialization . Experimental Serialization Api Ċ import Ġkotlinx . serialization . Serialization Exception Ċ import Ġkotlinx . serialization . json . Json Ċ import Ġorg . http 4 k . client . Apache Client Ċ import Ġorg . http 4 k . core .* Ċ import Ġorg . http 4 k . core . ContentType Ċ import Ġorg . http 4 k . filter . Debugging Filters Ċ import Ġorg . http 4 k . filter . Server Filters Ċ import Ġorg . http 4 k . routing . bind Ċ import Ġorg . http 4 k . routing . routes Ċ import Ġorg . http 4 k . server . Jet ty Ċ import Ġorg . http 4 k . server . as Server Ċ import Ġorg . lit ote . km ongo .* Ċ import Ġpro . w smi . room map . lib . api . API Room List Req Ċ import Ġpro . w smi . room map . lib . api . API Server List Req Ċ import Ġpro . w smi . room map . lib . api . API Server Req Ċ import Ġjava . io . File Ċ import Ġjava . util . logging . Level Ċ import Ġjava . util . logging . Logger Ċ import Ġkotlin . system . exit Process Ċ Ċ const Ġval ĠAPP _ NAME Ġ= Ġ" Room Map - API " Ċ const Ġval ĠAPP _ VERSION Ġ= Ġ" 0 . 1 . 0 " Ċ val ĠDEFAULT _ CFG _ FILE _ DIR Ġ= ĠFile ( System . getProperty (" user . home ")) Ċ const Ġval ĠDEFAULT _ CFG _ FILE _ NAME Ġ= Ġ". room map - api . yml " Ċ const Ġval ĠM ONGO DB _ MATRIX _ SERVER S _ COL _ NAME Ġ= Ġ" matrix _ servers " Ċ const Ġval ĠMAT RIX _ API _ PUBLIC _ RO O MS _ PATH Ġ= Ġ"/ _ matrix / client / r 0 / public Rooms " ĊĊ Ċ @ Experimental Unsigned Types Ċ @ Experimental Serialization Api Ċ fun Ġget Base Requests ( matrix Servers : ĠList < Matrix Server >, Ġbackend Cfg : ĠBackend Configuration ) Ġ: ĠMap < Matrix Server , ĠRequest > Ġ= Ġmatrix Servers . associate With Ġ{ Ġmatrix Server Ġ-> ĊĊĠĠĠ Ġval Ġreq Ġ= ĠRequest ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmethod Ġ= ĠMethod . GET , ĊĠĠĠĠĠĠĠĠĠĠĠ ĠUri ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġscheme Ġ= Ġmatrix Server . api URL . protocol , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠuserInfo Ġ= Ġ"", ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhost Ġ= Ġmatrix Server . api URL . host , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġport Ġ= Ġmatrix Server . api URL . port , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġpath Ġ= Ġ"", ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġquery Ġ= Ġ"", ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfragment Ġ= Ġ"" ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠ Ġ) ĊĠĠĠ Ġreq . replace Header (" User - Agent ", Ġ"$ APP _ NAME /$ APP _ VERSION Ġ(${ backend Cfg . instance Name }) ") Ċ } Ċ Ċ @ Experimental Serialization Api Ċ fun Ġget Room ListOf Server Ġ( base HttpRequest : ĠRequest ) Ġ: ĠResult < List < Matrix Room >> Ċ { ĊĠĠĠ Ġval Ġpublic Rooms Req Ġ= Ġbase HttpRequest . uri ( base HttpRequest . uri . path ( MATRIX _ API _ PUBLIC _ RO O MS _ PATH )) ĊĊĠĠĠ Ġval ĠhttpClient Ġ= ĠApache Client () ĊĠĠĠ Ġval Ġpublic Rooms Response Ġ= ĠhttpClient ( public Rooms Req ) ĊĊĠĠĠ Ġif Ġ( public Rooms Response . status Ġ!= ĠStatus . OK ) ĊĠĠĠĠĠĠĠ Ġreturn ĠResult . failure ( Exception (" The Ġserver Ġ${ base HttpRequest . uri . host } Ġreturned Ġthe ĠHTTP Ġcode Ġ${ public Rooms Response . status . code }. ")) ĊĊĠĠĠ Ġval Ġpublic Room List Req 2 0 0 Response Ġ= Ġtry Ġ{ ĊĠĠĠĠĠĠĠ ĠJson . decode FromString ( Public Room List Req 2 0 0 Response . serializer (), Ġpublic Rooms Response . body String ()) ĊĠĠĠ Ġ} Ġcatch Ġ( e : ĠSerialization Exception ) Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn ĠResult . failure ( e ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġreturn ĠResult . success ( ĊĠĠĠĠĠĠĠ Ġpublic Room List Req 2 0 0 Response . chunk . map Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠMatrix Room Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . roomId , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . aliases , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . canonical Alias , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . name ?. replace ( regex Ġ= ĠRegex ("[ \\ n \\ r \\ f \\ t ] "), Ġ"") ?. replace ( regex Ġ= ĠRegex ("^ Ġ+ "), Ġ""), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . num Joined Members , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . topic ?. replace ( regex Ġ= ĠRegex ("^ [ \\ n \\ r \\ f \\ t Ġ] + "), Ġ""), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . world Readable , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . guest Can Join , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . avatar Url ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ) Ċ } Ċ Ċ @ Experimental Serialization Api Ċ fun Ġconfigure API Global Http Filter ( debug Mode : ĠBoolean , Ġbackend Cfg : ĠBackend Configuration ) Ġ: ĠFilter Ċ { ĊĠĠĠ Ġval Ġserver Header Filter Ġ: ĠFilter Ġ= ĠFilter Ġ{ next : ĠHttp Handler Ġ-> ĊĠĠĠĠĠĠĠ Ġ{ Ġreq : ĠRequest Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġoriginal Response Ġ= Ġnext ( req ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġoriginal Response . header (" Server ", Ġ"$ APP _ NAME /$ APP _ VERSION ") ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĠĠĠ Ġval ĠcontentType Filter Ġ= Ġserver Header Filter . then ( Server Filters . Set ContentType ( ContentType . APPLICATION _ JSON )) ĊĠĠĠ Ġval Ġcompression Filter Ġ= Ġif Ġ( backend Cfg . api HttpServer . compression ) ĠcontentType Filter . then ( Server Filters . G Zip ()) Ġelse ĠcontentType Filter ĊĠĠĠ Ġreturn Ġif Ġ( debug Mode ) Ġcompression Filter . then ( Debugging Filters . Print Request And Response ()) Ġelse Ġcompression Filter Ċ } ĊĊ Ċ @ Experimental Unsigned Types Ċ class ĠBase Line Cmd Ġ: ĠCli kt Command ( name Ġ= Ġ" Room Map - API ") Ċ { ĊĠĠĠ Ġprivate Ġval Ġcfg FilePath CLA : ĠFile ? Ġby Ġoption ("- f ", Ġ"-- config - file ", Ġhelp Ġ= Ġ" Path Ġof Ġthe Ġbackend Ġconfiguration Ġfile ") ĊĠĠĠĠĠĠĠ Ġ. file Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmust Exist Ġ= Ġtrue , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcan Be File Ġ= Ġtrue , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcan Be Dir Ġ= Ġfalse , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmust Be Readable Ġ= Ġtrue , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmust Be Writable Ġ= Ġfalse , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcan Be S ymlink Ġ= Ġtrue ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠ Ġprivate Ġval Ġdebug Mode CLA Ġby Ġoption ("-- debug ", Ġhelp Ġ= Ġ" Turn Ġon Ġthe Ġdebug Ġmode "). flag () ĊĊĠĠĠ Ġ@ Experimental Serialization Api ĊĠĠĠ Ġoverride Ġfun Ġrun (): ĠUnit Ġ= Ġrun Blocking Ġ{ ĊĠĠĠĠĠĠĠ Ġprint (" Loading Ġof Ġbackend Ġconfiguration Ġ... Ġ") ĊĊĠĠĠĠĠĠĠ Ġval Ġconfig File Ġ= Ġthis @ Base Line Cmd . cfg FilePath CLA Ġ?: ĠFile ( DEFAULT _ CFG _ FILE _ DIR , ĠDEFAULT _ CFG _ FILE _ NAME ) ĊĠĠĠĠĠĠĠ Ġif Ġ(! configFile . exists () Ġ|| Ġ! configFile . isFile ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprintln (" FAILED ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprintln (" The Ġconfiguration Ġfile Ġ${ configFile . canonical File } Ġdoes Ġnot Ġexist .") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġexit Process ( 1 ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ(! configFile . can Read ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprintln (" FAILED ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprintln (" The Ġconfiguration Ġfile Ġ${ configFile . canonical File } Ġis Ġnot Ġreadable .") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġexit Process ( 2 ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġbackend Cfg Ġ= Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠYaml . default . decode FromString ( Backend Configuration . serializer (), Ġconfig File . read Text ( Charsets . UTF _ 8 )) ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprintln (" FAILED ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprintln (" There Ġis Ġan Ġerror Ġin Ġthe Ġconfiguration Ġfile Ġ${ configFile . canonical File }. ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( this @ Base Line Cmd . debug Mode CLA ) Ġe . printStackTrace () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġprintln ( e . localized Message ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġexit Process ( 3 ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġprintln (" OK ") ĊĊĠĠĠĠĠĠĠ Ġprint (" Connection Ġto Ġdatabase Ġ... Ġ") ĊĊĠĠĠĠĠĠĠ ĠLogger . getLogger (" org . mongodb . driver "). level Ġ= ĠLevel . OFF ĊĊĠĠĠĠĠĠĠ Ġval Ġmongo Client Ġ= ĠK Mongo . create Client ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ" mongodb ://${ if Ġ( backend Cfg . mongo Cfg . credentials Ġ!= Ġnull ) Ġbackend Cfg . mongo Cfg . credentials . username Ġ+ Ġ":" Ġ+ Ġbackend Cfg . mongo Cfg . credentials . password Ġ+ Ġ"@ " Ġelse Ġ"" }${ backend Cfg . mongo Cfg . server . host String }:${ backend Cfg . mongo Cfg . server . port }" ĊĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠ Ġval Ġmongo DB Ġ= Ġmongo Client . get Database ( backend Cfg . mongo Cfg . dbName ) ĊĊĠĠĠĠĠĠĠ Ġprintln (" OK ") ĊĊĠĠĠĠĠĠĠ Ġprint (" Loading Ġof Ġmatrix Ġservers Ġlist Ġ... Ġ") ĊĊĠĠĠĠĠĠĠ Ġval Ġmatrix Servers Col Ġ= Ġmongo DB . get Collection < Matrix Server >( MONGO DB _ MATRIX _ SERVER S _ COL _ NAME ) ĊĊĠĠĠĠĠĠĠ Ġval Ġmatrix Servers Ġ= Ġmatrix Servers Col . find (). toList () ĊĊĠĠĠĠĠĠĠ Ġval Ġenabled Matrix Servers Ġ= Ġmatrix Servers . filter Not Ġ{ Ġit . disabled Ġ}. to Mutable List () ĊĊĊĠĠĠĠĠĠĠ Ġprintln (" OK ") ĊĊĠĠĠĠĠĠĠ Ġprint (" First Ġquerying Ġto ĠMatrix Ġservers Ġto Ġinitialize Ġthe Ġroom Ġlist Ġ... Ġ") ĊĊĠĠĠĠĠĠĠ Ġval Ġbase Http Requests Ġ= Ġget Base Requests ( enabled Matrix Servers , Ġbackend Cfg ) ĊĊĠĠĠĠĠĠĠ Ġfor Ġ(( server , Ġbase Req ) Ġin Ġbase Http Requests ) ĊĠĠĠĠĠĠĠ Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġroom ListResult Ġ= Ġget Room ListOf Server ( base Req ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġroom List Ġ= Ġroom ListResult . getOrElse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġprintln (" FAILED ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . printStackTrace () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexit Process ( 1 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( room List . isNotEmpty ()) Ġserver . matrix Rooms Ġ= Ġroom List ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġprintln (" OK ") ĊĊĠĠĠĠĠĠĠ Ġprintln (" Backend Ġstarted ") ĊĊĠĠĠĠĠĠĠ Ġval Ġupdate Room Jobs Ġ= Ġbase Http Requests . map Values Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlaunch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ( it . key . try Before Dis abling Ġ> Ġ 0 u ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelay ( it . key . update Freq ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġroom ListResult Ġ= Ġget Room ListOf Server ( it . value ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġroom List Ġ= Ġroom ListResult . getOrElse Ġ{ Ġ_ Ġ-> ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . key . try Before Dis abling -- ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( room List Ġ!= Ġnull ) Ġit . key . matrix Rooms Ġ= Ġroom List ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( it . key . try Before Dis abling Ġ== Ġ 0 u ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . key . disabled Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġmatrix Servers Col . update One Ġ( Matrix Server :: id Ġeq Ġit . key . id , Ġit . key ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġenabled Matrix Servers . remove ( it . key ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĊĠĠĠĠĠĠĠ Ġconfigure API Global Http Filter ( debug Mode CLA , Ġbackend Cfg ). then ( routes ( ĊĠĠĠĠĠĠĠĠĠĠĠ ĠAPI Room List Req . REQ _ PATH Ġbind ĠMethod . POST Ġto Ġhandle API Room List Req ( debug Mode CLA , Ġenabled Matrix Servers ), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠAPI Server List Req . REQ _ PATH Ġbind ĠMethod . GET Ġto Ġhandle API Server List Req ( debug Mode CLA , Ġenabled Matrix Servers ), ĊĠĠĠĠĠĠĠĠĠĠĠ ĠAPI Server Req . REQ _ PATH Ġbind ĠMethod . POST Ġto Ġhandle API Server Req ( debug Mode CLA , Ġenabled Matrix Servers ) ĊĠĠĠĠĠĠĠ Ġ )). as Server ( Jet ty ( backend Cfg . api HttpServer . port )). start () ĊĠĠĠ Ġ} Ċ } Ċ Ċ @ Experimental Unsigned Types Ċ fun Ġmain ( args : ĠArray < String >) Ġ= ĠBase Line Cmd (). main ( args )