package Ġai . plat on . pulsar . browser . driver . chrome . impl Ċ Ċ import Ġai . plat on . pulsar . browser . driver . chrome . Dev Tools Config Ċ import Ġai . plat on . pulsar . browser . driver . chrome . Method Invocation Ċ import Ġai . plat on . pulsar . browser . driver . chrome . Remote Dev Tools Ċ import Ġai . plat on . pulsar . browser . driver . chrome . WebSocket Client Ċ import Ġai . plat on . pulsar . browser . driver . chrome . util . Chrome Dev Tools Invocation Exception Ċ import Ġai . plat on . pulsar . browser . driver . chrome . util . WebSocket ServiceException Ċ import Ġai . plat on . pulsar . common . config . App Constants Ċ import Ġai . plat on . pulsar . common . readable Ċ import Ġch . qos . log back . classic . Level Ċ import Ġch . qos . log back . classic . Logger Context Ċ import Ġcom . co da h ale . metrics . Gauge Ċ import Ġcom . co da h ale . metrics . Shared Metric Regist ries Ċ import Ġcom . fasterxml . jackson . annotation . JsonInclude Ċ import Ġcom . fasterxml . jackson . databind . Deserialization Feature Ċ import Ġcom . fasterxml . jackson . databind . Java Type Ċ import Ġcom . fasterxml . jackson . databind . JsonNode Ċ import Ġcom . fasterxml . jackson . databind . ObjectMapper Ċ import Ġcom . fasterxml . jackson . databind . type . Type Factory Ċ import Ġcom . github . k kl is ura . cdt . protocol . support . types . EventHandler Ċ import Ġcom . github . k kl is ura . cdt . protocol . support . types . EventListener Ċ import Ġorg . slf 4 j . LoggerFactory Ċ import Ġjava . io . IOException Ċ import Ġjava . time . Duration Ċ import Ġjava . time . Instant Ċ import Ġjava . util . concurrent . Concurrent HashMap Ċ import Ġjava . util . concurrent . Concurrent Skip List Set Ċ import Ġjava . util . concurrent . Count DownLatch Ċ import Ġjava . util . concurrent . TimeUnit Ċ import Ġjava . util . concurrent . atomic . Atomic Boolean Ċ import Ġjava . util . concurrent . atomic . Atomic Integer Ċ import Ġjava . util . concurrent . locks . Re entrant Lock Ċ import Ġjava . util . function . Consumer Ċ import Ġkotlin . concurrent . with Lock Ċ Ċ internal Ġclass ĠInvocation Future ( val Ġreturn Property : ĠString ? Ġ= Ġnull ) Ġ{ ĊĠĠĠ Ġvar Ġresult : ĠJsonNode ? Ġ= Ġnull ĊĠĠĠ Ġvar Ġis Success Ġ= Ġfalse ĊĠĠĠ Ġprivate Ġval Ġcount DownLatch Ġ= ĠCount DownLatch ( 1 ) ĊĊĠĠĠ Ġfun Ġsignal ( is Success : ĠBoolean , Ġresult : ĠJsonNode ?) Ġ{ ĊĠĠĠĠĠĠĠ Ġthis . is Success Ġ= Ġis Success ĊĠĠĠĠĠĠĠ Ġthis . result Ġ= Ġresult ĊĠĠĠĠĠĠĠ Ġcount DownLatch . count Down () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Throws ( InterruptedException :: class ) ĊĠĠĠ Ġfun Ġawait ( timeout : ĠLong , Ġtime Unit : ĠTimeUnit ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġif Ġ( timeout Ġ== Ġ 0 L ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcount DownLatch . await () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtrue ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġcount DownLatch . await ( timeout , Ġtime Unit ) ĊĠĠĠ Ġ} Ċ } Ċ Ċ /** ĠError Ġobject Ġreturned Ġfrom Ġdev Ġtools . Ġ Ġ*/ Ċ internal Ġclass ĠError Object Ġ{ ĊĠĠĠ Ġvar Ġcode : ĠLong Ġ= Ġ 0 ĊĠĠĠ Ġvar Ġmessage : ĠString Ġ= Ġ"" ĊĠĠĠ Ġvar Ġdata : ĠString ? Ġ= Ġnull Ċ } Ċ Ċ abstract Ġclass ĠBasic Dev Tools ( ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġws Client : ĠWebSocket Client , ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġdev Tools Config : ĠDev Tools Config Ċ ): ĠRemote Dev Tools , ĠConsumer < String >, ĠAuto Closeable Ġ{ ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠID _ PROPERTY Ġ= Ġ" id " ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠERROR _ PROPERTY Ġ= Ġ" error " ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠRESULT _ PROPERTY Ġ= Ġ" result " ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠMETHOD _ PROPERTY Ġ= Ġ" method " ĊĠĠĠĠĠĠĠ Ġprivate Ġconst Ġval ĠPARAM S _ PROPERTY Ġ= Ġ" params " ĊĊĠĠĠĠĠĠĠ Ġprivate Ġval ĠOBJECT _ MAP PER Ġ= ĠObjectMapper () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Serialization In clusion ( JsonInclude . Include . NON _ NULL ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. configure ( Deserialization Feature . FAIL _ ON _ UNKNOWN _ PROPERTIES , Ġfalse ) ĊĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġinstance Se qu encer Ġ= ĠAtomicInteger () ĊĊĠĠĠĠĠĠĠ Ġprivate Ġval ĠstartTime Ġ= ĠInstant . now () ĊĠĠĠĠĠĠĠ Ġprivate Ġvar Ġlast Active Time Ġ= ĠstartTime ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġidle Time Ġget () Ġ= ĠDuration . between ( last Active Time , ĠInstant . now ()) ĊĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġmetrics Ġ= ĠShared Metric Regist ries . get OrCreate ( App Constants . DEFAULT _ METR ICS _ NAME ) ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġmetrics Prefix Ġ= Ġ" c . i . Basic Dev Tools . global " ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġnum Inv okes Ġ= Ġmetrics . counter ("$ metrics Prefix . inv okes ") ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġnum Accept s Ġ= Ġmetrics . counter ("$ metrics Prefix . accept s ") ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġg au ges Ġ= Ġmap Of ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" idle Time " Ġto ĠG auge Ġ{ Ġidle Time . readable () Ġ} ĊĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġinit Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġg au ges . forEach Ġ{ Ġ( name , Ġgauge ) Ġ-> Ġmetrics . gauge ("$ metrics Prefix .$ name ") Ġ{ Ġgauge Ġ} Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġval Ġlogger Ġ= ĠLoggerFactory . getLogger ( Basic Dev Tools :: class . java ) ĊĠĠĠ Ġprivate Ġval Ġid Ġ= Ġinstance Se qu encer . increment AndGet () ĊĠĠĠ Ġprivate Ġval Ġworker Group Ġ= Ġdev Tools Config . worker Group ĊĠĠĠ Ġprivate Ġval Ġinvocation F utures : ĠMutable Map < Long , ĠInvocation Future > Ġ= ĠConcurrent HashMap () ĊĠĠĠ Ġprivate Ġval Ġevent Listeners : ĠMutable Map < String , ĠMutable Set < Dev Tools EventListener >> Ġ= Ġmutable Map Of () ĊĊĠĠĠ Ġprivate Ġval Ġlock Ġ= ĠRe entrant Lock () Ġ// Ġlock Ġfor Ġcontainers ĊĠĠĠ Ġprivate Ġval Ġnot Busy Ġ= Ġlock . new Condition () ĊĠĠĠ Ġprivate Ġval Ġclose Latch Ġ= ĠCount DownLatch ( 1 ) ĊĠĠĠ Ġprivate Ġval Ġclosed Ġ= ĠAtomic Boolean () ĊĠĠĠ Ġoverride Ġval ĠisOpen Ġget () Ġ= Ġ! closed . get () Ġ&& Ġ! ws Client . is Closed () ĊĊĠĠĠ Ġinit Ġ{ ĊĠĠĠĠĠĠĠ Ġws Client . add MessageHandler ( this ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġopen Ġoperator Ġfun Ġ< T > Ġinvoke ( return Property : ĠString , Ġclazz : ĠClass < T >, Ġmethod Invocation : ĠMethod Invocation ): ĠT ? Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġinvoke ( return Property , Ġclazz , Ġnull , Ġmethod Invocation ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġoperator Ġfun Ġ< T > Ġinvoke ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Property : ĠString ?, ĊĠĠĠĠĠĠĠĠĠĠĠ Ġclazz : ĠClass < T >, ĊĠĠĠĠĠĠĠĠĠĠĠ ĠreturnType Classes : ĠArray < Class < out ĠAny >> ?, ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmethod : ĠMethod Invocation ĊĠĠĠ Ġ): ĠT ? Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! isOpen ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġnull ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġnum Inv okes . inc () ĊĠĠĠĠĠĠĠ Ġlast Active Time Ġ= ĠInstant . now () ĊĊĠĠĠĠĠĠĠ Ġval Ġfuture Ġ= Ġinvocation F utures . compute If Absent ( method . id ) Ġ{ ĠInvocation Future ( return Property ) Ġ} ĊĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠTODO : Ġconsider Ġuse Ġcoroutine Ġor Ġws Client . async Send ĊĠĠĠĠĠĠĠĠĠĠĠ Ġws Client . send ( OBJECT _ MAP PER . writeValue AsString ( method )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġrespon ded Ġ= Ġfuture . await ( dev Tools Config . read Timeout . seconds , ĠTimeUnit . SECONDS ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġinvocation F utures . remove ( method . id ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlast Active Time Ġ= ĠInstant . now () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġlock . with Lock Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( invocation F utures . isEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnot Busy . signal All () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! respon ded ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . warn (" Timeout Ġto Ġwait Ġfor Ġws Ġresponse Ġ# {}", Ġnum Inv okes . count ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠChrome Dev Tools Invocation Exception (" Timeout Ġto Ġwait Ġfor Ġws Ġresponse Ġ# ${ num Inv okes . count }") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( future . is Success ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġwhen Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠVoid . TYPE Ġ== Ġclazz Ġ-> Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠreturnType Classes Ġ!= Ġnull Ġ-> Ġread JsonObject ( returnType Classes , Ġclazz , Ġfuture . result ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġread JsonObject ( clazz , Ġfuture . result ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠReceived Ġa Ġerror ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġerror Ġ= Ġread JsonObject ( Error Object :: class . java , Ġfuture . result ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsb Ġ= ĠStringBuilder ( error . message ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( error . data Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsb . append (": Ġ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsb . append ( error . data ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠChrome Dev Tools Invocation Exception ( error . code , Ġsb . toString ()) ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠWebSocket ServiceException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠChrome Dev Tools Invocation Exception (" Web Ġsocket Ġconnection Ġlost ", Ġe ) ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠInterruptedException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . warn (" Inter rupted Ġwhile Ġinvoke Ġ${ method . method }") ĊĠĠĠĠĠĠĠĠĠĠĠ ĠThread . currentThread (). interrupt () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġnull ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠIOException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠChrome Dev Tools Invocation Exception (" Failed Ġreading Ġresponse Ġmessage ", Ġe ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġadd EventListener ( domain Name : ĠString , ĊĠĠĠĠĠĠĠĠĠĠĠ ĠeventName : ĠString , Ġevent Handler : ĠEventHandler < Any >, ĠeventType : ĠClass < *> ): ĠEvent Listener Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġname Ġ= Ġ"$ domain Name .$ eventName " ĊĠĠĠĠĠĠĠ Ġval Ġlistener Ġ= ĠDev Tools EventListener ( name , Ġevent Handler , ĠeventType , Ġthis ) ĊĠĠĠĠĠĠĠ Ġevent Listeners . compute If Absent ( name ) Ġ{ ĠConcurrent Skip List Set < Dev Tools EventListener >() Ġ}. add ( listener ) ĊĠĠĠĠĠĠĠ Ġreturn Ġlistener ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġremove EventListener ( event Listener : ĠEvent Listener ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġlistener Ġ= Ġevent Listener Ġas ĠDev Tools EventListener ĊĠĠĠĠĠĠĠ Ġevent Listeners [ listener . key ]?. remove If Ġ{ Ġlistener . handler Ġ== Ġit . handler Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġaccept ( message : ĠString ) Ġ{ ĊĠĠĠĠĠĠĠ Ġlogger . take If Ġ{ Ġit . is Trace Enabled Ġ} ?. trace (" Accept Ġ{}", Ġmessage ) ĊĊĠĠĠĠĠĠĠ Ġnum Accept s . inc () ĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġjson Node Ġ= ĠOBJECT _ MAP PER . read Tree ( message ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġid Node Ġ= Ġjson Node . get ( ID _ PROPERTY ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( id Node Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġid Ġ= Ġid Node . as Long () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġfuture Ġ= Ġinvocation F utures [ id ] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( future Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġresult Node Ġ= Ġjson Node . get ( RESULT _ PROPERTY ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġerror Node Ġ= Ġjson Node . get ( ERROR _ PROPERTY ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( error Node Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfuture . signal ( false , Ġerror Node ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( future . return Property Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( result Node Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġresult Node Ġ= Ġresult Node . get ( future . return Property ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( result Node Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfuture . signal ( true , Ġresult Node ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfuture . signal ( true , Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . warn (" Received Ġresponse Ġwith Ġunknown Ġinvocation Ġ# {} Ġ- Ġ{}", Ġid , Ġjson Node . as Text ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmethod Node Ġ= Ġjson Node . get ( METHOD _ PROPERTY ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġparams Node Ġ= Ġjson Node . get ( PARAMS _ PROPERTY ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( method Node Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhandle Event ( method Node . as Text (), Ġparams Node ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( ex : ĠIOException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . error (" Failed Ġreading Ġweb Ġsocket Ġmessage ", Ġex ) ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( ex : Ġjava . lang . Exception ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . error (" Failed Ġreceiving Ġweb Ġsocket Ġmessage ", Ġex ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġwait Until Closed () Ġ{ ĊĠĠĠĠĠĠĠ Ġrun Catch ing Ġ{ Ġclose Latch . await () Ġ}. on Failure Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( it Ġis ĠInterruptedException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠThread . currentThread (). interrupt () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġclose () Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( closed . compare AndSet ( false , Ġtrue )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġkotlin . run Catch ing Ġ{ Ġdo Close () Ġ}. on Failure Ġ{ Ġlogger . warn ( it . message ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġclose Latch . count Down () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Throws ( Exception :: class ) ĊĠĠĠ Ġprivate Ġfun Ġdo Close () Ġ{ ĊĠĠĠĠĠĠĠ Ġlock . with Lock Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġi Ġ= Ġ 0 ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ( i ++ Ġ< Ġ 5 Ġ&& Ġinvocation F utures . isNotEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnot Busy . await ( 1 , ĠTimeUnit . SECONDS ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠInterruptedException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠThread . currentThread (). interrupt () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġlogger . trace (" Closing Ġws Ġclient Ġ... Ġ| Ġ{}", Ġws Client ) ĊĊĠĠĠĠĠĠĠ Ġws Client . close () ĊĠĠĠĠĠĠĠ Ġworker Group . shutdown Grace fully () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġhandle Event ( name : ĠString , Ġparams : ĠJsonNode ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! isOpen ) Ġreturn ĊĊĠĠĠĠĠĠĠ Ġval Ġlisteners Ġ= Ġevent Listeners [ name ] Ġ?: return ĊĊĠĠĠĠĠĠĠ Ġ// Ġmake Ġa Ġcopy ĊĠĠĠĠĠĠĠ Ġval Ġun modified Listeners Ġ= Ġmutable Set Of < Dev Tools EventListener >() ĊĠĠĠĠĠĠĠ Ġsynchronized ( listeners ) Ġ{ Ġlisteners . to Collection ( un modified Listeners ) Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ( un modified Listeners . isEmpty ()) Ġreturn ĊĊĠĠĠĠĠĠĠ Ġ// Ġcoroutine Ġis ĠOK ĊĠĠĠĠĠĠĠ Ġworker Group . execute Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġevent : ĠAny ? Ġ= Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( listener Ġin Ġun modified Listeners ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( event Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġevent Ġ= Ġread JsonObject ( listener . param Type , Ġparams ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( event Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlistener . handler . on Event ( event ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( t : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . warn (" Unexpected Ġexception ", Ġt ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . error (" Error Ġwhile Ġprocessing Ġevent Ġ{}", Ġname , Ġe ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Throws ( IOException :: class ) ĊĠĠĠ Ġprivate Ġfun Ġ< T > Ġread JsonObject ( class Parameters : ĠArray < Class <* >>, Ġparameter ized Clazz : ĠClass < T >, Ġjson Node : ĠJsonNode ?): ĠT Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( json Node Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠChrome Dev Tools Invocation Exception (" Failed Ġconverting Ġnull Ġresponse Ġto Ġclazz Ġ$ parameter ized Clazz ") ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġtype Factory : ĠType Factory Ġ= ĠOBJECT _ MAP PER . type Factory ĊĠĠĠĠĠĠĠ Ġvar Ġjava Type : ĠJava Type ? Ġ= Ġnull ĊĠĠĠĠĠĠĠ Ġif Ġ( class Parameters . size Ġ> Ġ 1 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( i Ġin Ġclass Parameters . size Ġ- Ġ 2 Ġdown To Ġ 0 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġjava Type Ġ= Ġif Ġ( java Type Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtype Factory . construct Parame tric Type ( class Parameters [ i ], Ġclass Parameters [ i Ġ+ Ġ 1 ]) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtype Factory . construct Parame tric Type ( class Parameters [ i ], Ġjava Type ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġjava Type Ġ= Ġtype Factory . construct Parame tric Type ( parameter ized Clazz , Ġjava Type ) ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġjava Type Ġ= Ġtype Factory . construct Parame tric Type ( parameter ized Clazz , Ġclass Parameters [ 0 ]) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġreturn ĠOBJECT _ MAP PER . reader For ( java Type ). readValue ( json Node ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Throws ( IOException :: class ) ĊĠĠĠ Ġprivate Ġfun Ġ< T > Ġread JsonObject ( clazz : ĠClass < T >, Ġjson Node : ĠJsonNode ?): ĠT Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( json Node Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠChrome Dev Tools Invocation Exception (" Failed Ġconverting Ġnull Ġresponse Ġto Ġclazz Ġ" Ġ+ Ġclazz . name ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn ĠOBJECT _ MAP PER . reader For ( clazz ). readValue ( json Node ) ĊĠĠĠ Ġ} Ċ } Ċ