package Ġclub . it sp . el ang . ag mob . workspace Ċ Ċ import Ġio . ktor . application . call Ċ import Ġio . ktor . application . install Ċ import Ġio . ktor . application . log Ċ import Ġio . ktor . http . ContentType Ċ import Ġio . ktor . http . HttpStatusCode Ċ import Ġio . ktor . http . c io . websocket .* Ċ import Ġio . ktor . request . receive Text Ċ import Ġio . ktor . response . respond Text Ċ import Ġio . ktor . routing . get Ċ import Ġio . ktor . routing . post Ċ import Ġio . ktor . routing . put Ċ import Ġio . ktor . routing . routing Ċ import Ġio . ktor . server . engine . embedded Server Ċ import Ġio . ktor . server . netty . Net ty Ċ import Ġio . ktor . websocket . WebSocket Server Session Ċ import Ġio . ktor . websocket . WebSocket s Ċ import Ġio . ktor . websocket . web Socket Ċ import Ġkotlinx . serialization . Serializable Ċ import Ġkotlinx . serialization . Transient Ċ import Ġkotlinx . serialization . json . Json Ċ import Ġorg . slf 4 j . LoggerFactory Ċ import Ġjava . util .* Ċ import Ġkotlin . collections . HashMap Ċ Ċ @ Serializable Ċ class ĠSession Configuration ( ĊĠĠĠĠĠĠĠ Ġ// ĠThe Ġlength Ġof Ġa Ġ' mob Ġsession ' Ġin Ġseconds ĊĠĠĠĠĠĠĠ Ġvar Ġinterval : ĠInt , ĊĠĠĠĠĠĠĠ Ġ// ĠThe Ġunix Ġtime Ġstamp Ġin Ġseconds Ġ( JavaScript : ĠDate . now () Ġ/ Ġ 1 0 0 0 ) ĊĠĠĠĠĠĠĠ Ġvar Ġbegin : ĠLong , ĊĠĠĠĠĠĠĠ Ġ// ĠThe Ġmode Ġof Ġa Ġ' mob Ġsession ' ĊĠĠĠĠĠĠĠ Ġvar Ġmode : ĠString Ġ= Ġ" Free ĠMode ", ĊĠĠĠĠĠĠĠ Ġ// ĠThe Ġstate Ġof Ġa Ġmob Ġ' session ' ĊĠĠĠĠĠĠĠ Ġvar Ġstate : ĠString Ġ= Ġ" No ĠConnection " Ċ ) Ċ Ċ @ Serializable Ċ class ĠSession ( var Ġconfig : ĠSession Configuration ) Ġ{ ĊĠĠĠ Ġval Ġid Ġ= ĠUUID . randomUUID (). toString () ĊĊĠĠĠ Ġ// ĠThe Ġhistory Ġof Ġchat ĊĠĠĠ Ġvar Ġhistory : ĠString Ġ= Ġ"" ĊĊĠĠĠ Ġ@ Transient ĊĠĠĠ Ġvar Ġdriver : ĠDriver Connection ? Ġ= Ġnull ĊĠĠĠĠĠĠĠ Ġprivate Ġset ĊĠĠĠ Ġ@ Transient ĊĠĠĠ Ġval Ġnavig ators Ġ= ĠHashMap < Int , ĠNavigator Connection >() ĊĊĠĠĠ Ġ@ Transient ĊĠĠĠ Ġval Ġlog Ġ= ĠLoggerFactory . getLogger ( this . java Class ) !! ĊĊĠĠĠ Ġ@ Synchron ized ĊĠĠĠ Ġfun Ġadd Navigator ( conn : ĠNavigator Connection ) Ġ{ ĊĠĠĠĠĠĠĠ Ġnavig ators [ conn . id ] Ġ= Ġconn ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Synchron ized ĊĠĠĠ Ġsuspend Ġfun Ġset Driver ( conn : ĠDriver Connection ?) Ġ{ ĊĠĠĠĠĠĠĠ Ġdisconnect Driver ( driver ) ĊĊĠĠĠĠĠĠĠ Ġlog . debug (" [$ id ] Ġconnecting Ġdriver : Ġ$ conn ") ĊĠĠĠĠĠĠĠ Ġdriver Ġ= Ġconn ĊĊĠĠĠĠĠĠĠ Ġ// ĠNotify Ġalready - connected Ġnavig ators Ġthat Ġthey Ġcan Ġnow Ġattempt ĠWeb RTC Ġconnection ĊĠĠĠĠĠĠĠ Ġlog . debug (" [$ id ] Ġnotify ing Ġnavig ators Ġconnection Ġof Ġdriver : Ġ$ conn ") ĊĠĠĠĠĠĠĠ Ġnavig ators . values . forEach Ġ{ Ġnav Ġ-> Ġif Ġ(! nav . dead ) Ġnav . notify Driver Ready () Ġ} ĊĠĠĠĠĠĠĠ Ġprune Dead Navig ators () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ// ĠY ucks ĊĠĠĠ Ġ@ Synchron ized ĊĠĠĠ Ġsuspend Ġfun Ġdisconnect Driver ( current : ĠDriver Connection ?) Ġ{ ĊĠĠĠĠĠĠĠ Ġlog . debug (" [$ id ] Ġdisconnect ing Ġdriver : Ġ$ current ") ĊĠĠĠĠĠĠĠ Ġif Ġ( driver Ġ!= Ġcurrent Ġ|| Ġcurrent Ġ== Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠ Ġlog . debug (" [$ id ] Ġdisconnect ing ĠWebSocket Ġwith Ġdriver : Ġ$ current ") ĊĠĠĠĠĠĠĠ Ġcurrent . disconnect () ĊĠĠĠĠĠĠĠ Ġdriver Ġ= Ġnull ĊĠĠĠĠĠĠĠ Ġlog . debug (" [$ id ] Ġnotify ing Ġnavig ators Ġdis connection Ġof Ġdriver : Ġ$ current ") ĊĠĠĠĠĠĠĠ Ġnavig ators . values . forEach Ġ{ Ġnav Ġ-> Ġif Ġ(! nav . dead ) Ġnav . notify Driver Quit () Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Synchron ized ĊĠĠĠ Ġprivate Ġfun Ġprune Dead Navig ators () Ġ{ ĊĠĠĠĠĠĠĠ ĠArrayList ( navig ators . values ). forEach Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( it . dead ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnavig ators . remove ( it . id ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ abstract Ġclass ĠBase Connection ( val Ġsession : ĠSession , Ġprotected Ġval Ġws Session : ĠWebSocket Server Session ) Ġ{ ĊĠĠĠ Ġval Ġid Ġ= Ġid Base ++ ĊĠĠĠ Ġvar Ġdead Ġ= Ġfalse ĊĠĠĠĠĠĠĠ Ġprivate Ġset ĊĊĠĠĠ Ġprotected Ġfun Ġmark As Dead () Ġ{ ĊĠĠĠĠĠĠĠ Ġdead Ġ= Ġtrue ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprotected Ġsuspend Ġfun ĠsendMessage ( m : ĠWebSocket Message ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( dead ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġsession . log . info ("[ BUG ] ĠsendMessage Ġcalled Ġon Ġa Ġdead Ġconnection : Ġ${ Exception (). stack Trace }") ĊĠĠĠĠĠĠĠ Ġval Ġs Ġ= Ġm . toJson () ĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġws Session . send ( s ) ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġsession . log . debug ("[ ${ session . id }] Ġdead Ġconnection Ġdetected Ġduring ĠsendMessage : Ġ$ this ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmark As Dead () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun Ġdisconnect () Ġ{ ĊĠĠĠĠĠĠĠ Ġws Session . close () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġprivate Ġvar Ġid Base Ġ= Ġ 0 ĊĠĠĠ Ġ} Ċ } Ċ Ċ class ĠDriver Connection ( session : ĠSession , Ġws Session : ĠWebSocket Server Session ) Ġ: ĠBase Connection ( session , Ġws Session ) Ġ{ ĊĠĠĠ Ġsuspend Ġfun Ġrequest S dp Offer ( nav Conn : ĠNavigator Connection , Ġmessage : ĠWebSocket Message ) Ġ{ ĊĠĠĠĠĠĠĠ ĠsendMessage ( WebSocket Message (" request _ sdp ", Ġmessage . payload , Ġnav Conn . id )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun Ġreceive Navigator S dp ( nav Conn : ĠNavigator Connection , Ġmessage : ĠWebSocket Message , Ġremote Id : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ ĠsendMessage ( WebSocket Message (" navigator _ sdp ", Ġmessage . payload , Ġnav Conn . id , Ġremote Id )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun Ġanswer Navigator S dp ( nav Conn : ĠNavigator Connection , Ġmessage : ĠWebSocket Message , Ġremote Id : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ ĠsendMessage ( WebSocket Message (" navigator _ answer ", Ġmessage . payload , Ġnav Conn . id , Ġremote Id )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun Ġnavigator Ice ( nav Conn : ĠNavigator Connection , Ġmessage : ĠWebSocket Message , Ġremote Id : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ ĠsendMessage ( WebSocket Message (" navigator _ ice ", Ġmessage . payload , Ġnav Conn . id , Ġremote Id )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun Ġreceive S dp Answer ( nav Conn : ĠNavigator Connection , Ġmessage : ĠWebSocket Message ) Ġ{ ĊĠĠĠĠĠĠĠ ĠsendMessage ( WebSocket Message (" sdp ", Ġmessage . payload , Ġnav Conn . id )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun Ġreceive Ice Candidate ( nav Conn : ĠNavigator Connection , Ġmessage : ĠWebSocket Message ) Ġ{ ĊĠĠĠĠĠĠĠ ĠsendMessage ( WebSocket Message (" ice _ candidate ", Ġmessage . payload , Ġnav Conn . id )) ĊĠĠĠ Ġ} ĊĊĊĠĠĠ Ġsuspend Ġfun Ġsend ChatMessage ( nav Conn : ĠNavigator Connection , Ġmessage : ĠWebSocket Message ) Ġ{ ĊĠĠĠĠĠĠĠ ĠsendMessage ( WebSocket Message (" chat ", Ġmessage . payload , Ġnav Conn . id )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun Ġdriver ChatMessage ( message : ĠWebSocket Message ) Ġ{ ĊĠĠĠĠĠĠĠ ĠsendMessage ( WebSocket Message (" chat ", Ġmessage . payload )) ĊĠĠĠ Ġ} Ċ } Ċ Ċ class ĠNavigator Connection ( session : ĠSession , Ġws Session : ĠWebSocket Server Session ) Ġ: ĠBase Connection ( session , Ġws Session ) Ġ{ ĊĠĠĠ Ġsuspend Ġfun Ġrequest S dp Offer ( message : ĠWebSocket Message , Ġnavigator _ id : ĠInt , Ġremote Id : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ ĠsendMessage ( WebSocket Message (" navigator _ request _ sdp ", Ġmessage . payload , Ġnavigator _ id , Ġremote Id )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun Ġreceive Navigator S dp ( message : ĠWebSocket Message , Ġnavigator _ id : ĠInt , Ġremote Id : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ ĠsendMessage ( WebSocket Message (" navigator _ sdp ", Ġmessage . payload , Ġnavigator _ id , Ġremote Id )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun Ġanswer Navigator S dp ( message : ĠWebSocket Message , Ġnavigator _ id : ĠInt , Ġremote Id : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ ĠsendMessage ( WebSocket Message (" navigator _ answer ", Ġmessage . payload , Ġnavigator _ id , Ġremote Id )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun Ġnavigator Ice ( message : ĠWebSocket Message , Ġnavigator _ id : ĠInt , Ġremote Id : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ ĠsendMessage ( WebSocket Message (" navigator _ ice ", Ġmessage . payload , Ġnavigator _ id , Ġremote Id )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun Ġreceive S dp Offer ( message : ĠWebSocket Message , Ġnavigator _ id : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ ĠsendMessage ( WebSocket Message (" sdp ", Ġmessage . payload , Ġnavigator _ id )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun Ġreceive Ice Candidate ( message : ĠWebSocket Message , Ġnavigator _ id : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ ĠsendMessage ( WebSocket Message (" ice _ candidate ", Ġmessage . payload , Ġnavigator _ id )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun Ġnotify Driver Ready () Ġ{ ĊĠĠĠĠĠĠĠ ĠsendMessage ( WebSocket Message (" driver _ ready ", Ġ"")) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun Ġnotify Driver Quit () Ġ{ ĊĠĠĠĠĠĠĠ ĠsendMessage ( WebSocket Message (" driver _ quit ", Ġ"")) ĊĠĠĠ Ġ} Ċ } Ċ Ċ // ĠFIXME : Ġnavigator _ id Ġs mell s Ġbad Ċ @ Serializable Ċ data Ġclass ĠWebSocket Message ( val Ġkind : ĠString , Ġval Ġpayload : ĠString , Ġval Ġnavigator _ id : ĠInt Ġ= Ġ- 1 , Ġval Ġremote Id : ĠInt Ġ= Ġ- 1 ) Ġ{ ĊĠĠĠ Ġfun ĠtoJson (): ĠString Ġ= ĠJson . stringify ( serializer (), Ġthis ) ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġfun Ġparse Json ( data : ĠString ) Ġ= ĠJson . parse ( serializer (), Ġdata ) ĊĠĠĠ Ġ} Ċ } Ċ Ċ fun Ġmain ( args : ĠArray < String >) Ġ{ ĊĠĠĠ Ġval Ġsessions Ġ= ĠHashMap < String , ĠSession >() ĊĊĠĠĠ Ġembedded Server ( Net ty , Ġ 8 0 8 0 ) Ġ{ ĊĠĠĠĠĠĠĠ Ġinstall ( WebSocket s ) ĊĊĠĠĠĠĠĠĠ Ġrouting Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġpost ("/ api / session ") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġconfig Text Ġ= Ġcall . receive Text () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠFIXME : ĠOnce Ġdriver Ġsupports Ġit , Ġthis Ġ' if ' Ġmust Ġbe Ġremoved ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsess Ġ= ĠSession ( if Ġ( config Text . isNotBlank ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠJson . parse ( Session Configuration . serializer (), Ġconfig Text ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠSession Configuration ( 1 0 Ġ* Ġ 6 0 , ĠSystem . currentTimeMillis () Ġ/ Ġ 1 0 0 0 L )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsessions [ sess . id ] Ġ= Ġsess ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . respond Text ( Json . stringify ( Session . serializer (), Ġsess ), ĠContentType . Application . Json ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġput ("/ api / session /{ id }") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsess Ġ= Ġsessions [ call . parameters [" id "]] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( sess Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . respond Text (" FIX ME : Ġinvalid Ġsess Ġid ", Ġstatus Ġ= ĠHttpStatusCode . BadRequest ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ put ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġnew Config Ġ= ĠJson . parse ( Session Configuration . serializer (), Ġcall . receive Text ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsess . config Ġ= Ġnew Config ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . respond Text ( Json . stringify ( Session . serializer (), Ġsess ), ĠContentType . Application . Json ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġget ("/ api / session /{ id }") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsess Ġ= Ġsessions [ call . parameters [" id "]] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( sess Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . respond Text (" FIX ME : Ġinvalid Ġsess Ġid ", Ġstatus Ġ= ĠHttpStatusCode . BadRequest ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ get ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . respond Text ( Json . stringify ( Session . serializer (), Ġsess ), ĠContentType . Application . Json ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġweb Socket ("/ api / session /{ id }/ navigator ") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsess Ġ= Ġsessions [ call . parameters [" id "]] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( sess Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . respond Text (" FIX ME : Ġinvalid Ġsess Ġid ", Ġstatus Ġ= ĠHttpStatusCode . BadRequest ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ web Socket ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġconn Ġ= ĠNavigator Connection ( sess , Ġthis ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("[ ${ sess . id }] Ġconnecting Ġnavigator : Ġ$ conn ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsess . add Navigator ( conn ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( frame Ġin Ġincoming ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( frame Ġ! is ĠFrame . Text ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġclose ( Close Reason ( Close Reason . Codes . CAN NOT _ ACCEPT , Ġ" FIX ME : Ġinvalid Ġframe ")) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontinue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmsg Ġ= ĠWebSocket Message . parse Json ( frame . read Text ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( msg . kind ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" request _ sdp " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdriver Ġ= Ġsess . driver ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( driver Ġ== Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("[ ${ sess . id }] Ġignoring Ġrequest _ sdp Ġfrom Ġnav -${ conn . id }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdriver ?. request S dp Offer ( conn , Ġmsg ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" navigator _ sdp " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdriver Ġ= Ġsess . driver ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġremote Id Ġ= Ġmsg . remote Id ; ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( driver Ġ== Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("[ ${ sess . id }] Ġignoring Ġs dp Ġfrom Ġnav -${ conn . id }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdriver ?. receive Navigator S dp ( conn , Ġmsg , Ġremote Id ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" navigator _ answer " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdriver Ġ= Ġsess . driver ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġremote Id Ġ= Ġmsg . remote Id ; ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( driver Ġ== Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("[ ${ sess . id }] Ġignoring Ġs dp Ġfrom Ġnav -${ conn . id }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdriver ?. answer Navigator S dp ( conn , Ġmsg , Ġremote Id ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" navigator _ ice " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdriver Ġ= Ġsess . driver ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġremote Id Ġ= Ġmsg . remote Id ; ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( driver Ġ== Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("[ ${ sess . id }] Ġignoring Ġs dp Ġfrom Ġnav -${ conn . id }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdriver ?. navigator Ice ( conn , Ġmsg , Ġremote Id ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" sdp " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdriver Ġ= Ġsess . driver ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( driver Ġ== Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("[ ${ sess . id }] Ġignoring Ġs dp Ġfrom Ġnav -${ conn . id }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdriver ?. receive S dp Answer ( conn , Ġmsg ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" ice _ candidate " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdriver Ġ= Ġsess . driver ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( driver Ġ== Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("[ ${ sess . id }] Ġignoring Ġice _ candidate Ġfrom Ġnav -${ conn . id }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdriver ?. receive Ice Candidate ( conn , Ġmsg ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" chat " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdriver Ġ= Ġsess . driver ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( driver Ġ== Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("[ ${ sess . id }] Ġignoring Ġchat Ġfrom Ġnav -${ conn . id }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdriver ?. send ChatMessage ( conn , Ġmsg ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . info ("[ ${ sess . id }] Ġinvalid Ġwebsocket Ġmessage Ġ${ msg . kind } Ġfrom Ġnav -${ conn . id }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġweb Socket ("/ api / session /{ id }/ driver ") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsess Ġ= Ġsessions [ call . parameters [" id "]] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( sess Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcall . respond Text (" FIX ME : Ġinvalid Ġsess Ġid ", Ġstatus Ġ= ĠHttpStatusCode . BadRequest ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ web Socket ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġconn Ġ= ĠDriver Connection ( sess , Ġthis ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("[ ${ sess . id }] Ġconnecting Ġdriver : Ġ$ conn ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsess . set Driver ( conn ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfor Ġ( frame Ġin Ġincoming ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( frame Ġ! is ĠFrame . Text ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġclose ( Close Reason ( Close Reason . Codes . CAN NOT _ ACCEPT , Ġ" FIX ME : Ġinvalid Ġframe ")) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontinue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġmsg Ġ= ĠWebSocket Message . parse Json ( frame . read Text ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhen Ġ( msg . kind ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" navigator _ request _ sdp " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġnav Conn Ġ= Ġsess . navig ators [ msg . navigator _ id ] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( nav Conn Ġ== Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("[ ${ sess . id }] Ġignoring Ġrequest Ġs dp Ġto Ġnav -${ msg . navigator _ id }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnav Conn ?. request S dp Offer ( msg , Ġmsg . navigator _ id , Ġmsg . remote Id ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" navigator _ sdp " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġnav Conn Ġ= Ġsess . navig ators [ msg . navigator _ id ] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( nav Conn Ġ== Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("[ ${ sess . id }] Ġignoring Ġrequest Ġs dp Ġto Ġnav -${ msg . navigator _ id }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnav Conn ?. receive Navigator S dp ( msg , Ġmsg . navigator _ id , Ġmsg . remote Id ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" navigator _ answer " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġnav Conn Ġ= Ġsess . navig ators [ msg . navigator _ id ] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( nav Conn Ġ== Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("[ ${ sess . id }] Ġignoring Ġrequest Ġs dp Ġto Ġnav -${ msg . navigator _ id }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnav Conn ?. answer Navigator S dp ( msg , Ġmsg . navigator _ id , Ġmsg . remote Id ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" navigator _ ice " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġnav Conn Ġ= Ġsess . navig ators [ msg . navigator _ id ] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( nav Conn Ġ== Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("[ ${ sess . id }] Ġignoring Ġrequest Ġs dp Ġto Ġnav -${ msg . navigator _ id }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnav Conn ?. navigator Ice ( msg , Ġmsg . navigator _ id , Ġmsg . remote Id ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" sdp " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġnav Conn Ġ= Ġsess . navig ators [ msg . navigator _ id ] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( nav Conn Ġ== Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("[ ${ sess . id }] Ġignoring Ġs dp Ġto Ġnav -${ msg . navigator _ id }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("${ msg . navigator _ id }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ( msg . payload ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnav Conn ?. receive S dp Offer ( msg , Ġmsg . navigator _ id ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" ice _ candidate " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġnav Conn Ġ= Ġsess . navig ators [ msg . navigator _ id ] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( nav Conn Ġ== Ġnull ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("[ ${ sess . id }] Ġignoring Ġice _ candidate Ġto Ġnav -${ msg . navigator _ id }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ("${ msg . navigator _ id }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug ( msg . payload ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnav Conn ?. receive Ice Candidate ( msg , Ġmsg . navigator _ id ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" quit " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . info (" driver : Ġquit ting ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġclose () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ web Socket ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" driver _ quit " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsess . config . state Ġ= Ġ" No ĠConnection " ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" chat _ history " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsess . history Ġ+= Ġmsg . payload ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" chat " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdriver Ġ= Ġsess . driver ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdriver ?. driver ChatMessage ( msg ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . info (" invalid Ġwebsocket Ġmessage Ġfrom Ġdriver : Ġ" Ġ+ Ġmsg . kind ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsess . disconnect Driver ( conn ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ}. start ( wait Ġ= Ġtrue ) Ċ } Ċ