package Ġbrowser . control Ċ Ċ import Ġcom . google . gson . Gson Ċ import Ġcom . google . gson . JsonArray Ċ import Ġcom . google . gson . JsonObject Ċ import Ġjava . io . Invalid Object Exception Ċ import Ġjava . net . Server Socket Ċ import Ġjava . net . Socket Exception Ċ import Ġjava . util . concurrent . TimeoutException Ċ import Ġkotlin . concurrent . thread Ċ Ċ class ĠBrowser Ġ{ ĊĊĠĠĠ Ġprivate Ġvar Ġserver : ĠServer Socket ? Ġ= Ġnull ĊĠĠĠ Ġprivate Ġvar Ġthread : ĠThread ? Ġ= Ġnull ĊĠĠĠ Ġprivate Ġvar Ġcheck Interval Ġ= Ġ 5 0 0 L ĊĊĠĠĠ Ġprivate Ġval Ġgson Ġ= ĠGson () ĊĠĠĠ Ġprivate Ġvar Ġpacket Index Ġ= Ġ 1 ĊĠĠĠ Ġprivate Ġval Ġrequest Queue Ġ= ĠArrayList < JsonObject >() ĊĠĠĠ Ġprivate Ġval Ġresponse Queue Ġ= ĠHashMap < Int , ĠJsonObject >() ĊĊĠĠĠ Ġprivate Ġval Ġon Tab Created Ġ= ĠArrayList <( Tab ) Ġ-> ĠUnit >() ĊĠĠĠ Ġprivate Ġval Ġon Tab Updated Ġ= ĠArrayList <( Tab ) Ġ-> ĠUnit >() ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġopens Ġthe Ġconnection Ġto Ġreceive Ġmessages Ġfrom Ġan Ġaddon ĊĠĠĠĠ Ġ* Ġ@ param Ġport Ġ( default Ġ= Ġ 5 8 0 0 1 ) ĊĠĠĠĠ Ġ* Ġ@ param Ġdaemon Ġ( default Ġ= Ġfalse ) Ġshould Ġthe Ġthread Ġrun Ġas Ġa Ġde amon ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġstart ( port : ĠInt Ġ= Ġ 5 8 0 0 1 , Ġdaemon : ĠBoolean Ġ= Ġfalse ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( server Ġ!= Ġnull ) Ġreturn ĊĊĠĠĠĠĠĠĠ Ġserver Ġ= ĠServer Socket ( port ) ĊĠĠĠĠĠĠĠ Ġthread Ġ= Ġthread ( is Daemon Ġ= Ġdaemon , Ġblock Ġ= Ġ:: run ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġstops Ġthe Ġconnection Ġto Ġbe Ġable Ġto Ġreceive Ġmessages Ġfrom Ġan Ġaddon ĊĠĠĠĠ Ġ* Ġ@ param Ġclear Listeners Ġ( default Ġ= Ġfalse ) Ġremoves Ġall Ġlisteners Ġadd Ġby Ġon Functions ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġstop ( clear Listeners : ĠBoolean Ġ= Ġfalse ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( server Ġ== Ġnull ) Ġreturn ĊĊĠĠĠĠĠĠĠ Ġthread ?. interrupt () ĊĠĠĠĠĠĠĠ Ġserver ?. close () ĊĠĠĠĠĠĠĠ Ġrequest Queue . clear () ĊĠĠĠĠĠĠĠ Ġresponse Queue . clear () ĊĠĠĠĠĠĠĠ Ġif Ġ( clear Listeners ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġon Tab Created . clear () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġon Tab Updated . clear () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġserver Ġ= Ġnull ĊĠĠĠĠĠĠĠ Ġthread Ġ= Ġnull ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġrun () Ġ{ ĊĠĠĠĠĠĠĠ Ġwhile Ġ(! Thread . inter rupted () Ġ&& Ġserver Ġ!= Ġnull Ġ&& Ġ! server !!. is Closed ) Ġ{ ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsocket Ġ= Ġtry Ġ{ Ġserver !!. accept () Ġ} Ġcatch Ġ( e : ĠSocket Exception ) Ġ{ Ġcontinue Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval ĠinputStream Ġ= Ġsocket . getInputStream () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval ĠoutputStream Ġ= Ġsocket . get OutputStream () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġheaders Ġ= ĠHashMap < String , String >() ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdescriptor Ġ= Ġread Line ( inputStream ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ( true ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġline Ġ= Ġread Line ( inputStream ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( line . isEmpty ()) Ġbreak ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġkey Ġ= Ġline . substring Before (": Ġ"). lowercase () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġvalue Ġ= Ġline . substring After (": Ġ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġheaders [ key ] Ġ= Ġvalue ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġtype Ġ= Ġdescriptor . substring Before (" Ġ"). uppercase () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcontent Length Ġ= Ġheaders . get OrDefault (" content - length ", Ġ" 0 "). toInt () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġbuffer Ġ= ĠByteArray ( content Length ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠinputStream . read ( buffer ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġjson Ġ= Ġwhen Ġ( type ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" GET " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrun Catch ing Ġ{ Ġdescriptor . split (" Ġ" )[ 1 ]. substring ( 1 ). to Long () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. on Success Ġ{ Ġcheck Interval Ġ= Ġit Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrun Get () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" POST " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġjson Ġ= Ġgson . fromJson ( buffer . decode ToString (), ĠJsonObject :: class . java ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrun Post ( json ) Ġ?: ĠJsonObject () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġrun Get () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ}. let ( gson :: toJson ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġresponse Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" HTTP / 1 . 1 Ġ 2 0 0 ĠOK \ n " Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" Access - Control - Allow - Origin : Ġ* \ n " Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" Access - Control - Allow - Headers : Ġ* \ n " Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" Content - Type : Ġapplication / json \ n " Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" Content - Length : Ġ${ json . length }\ n " Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ"\ n " Ġ+ Ġjson ĊĠĠĠĠĠĠĠĠĠĠĠ ĠoutputStream . write ( response . encode To ByteArray ()) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠoutputStream . flush () ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠinputStream . close () ĊĠĠĠĠĠĠĠĠĠĠĠ ĠoutputStream . close () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġsocket . close () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġrun Get () Ġ= ĊĠĠĠĠĠĠĠ ĠJsonObject (). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġadd (" queue ", ĠJson Array (). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsynchronized ( request Queue ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrequest Queue . forEach (:: add ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrequest Queue . clear () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ}) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġrun Post ( packet : ĠJsonObject ): ĠJsonObject ? Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(" id " Ġ! in Ġpacket Ġ|| Ġ" type " Ġ! in Ġpacket ) Ġreturn Ġnull ĊĠĠĠĠĠĠĠ Ġwhen Ġ( packet [" type "]. asString ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ" on Tab Created " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġtab Ġ= ĠTab . fromJson ( this , Ġpacket [" response "]. as JsonObject [" tab "]. as JsonObject ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġon Tab Created . forEach Ġ{ Ġit ( tab ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ" on Tab Updated " Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġtab Ġ= ĠTab . fromJson ( this , Ġpacket [" response "]. as JsonObject [" tab "]. as JsonObject ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġon Tab Updated . forEach Ġ{ Ġit ( tab ) Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġresponse Queue [ packet [" id "]. as Int ] Ġ= Ġpacket ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn Ġnull ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġmanually Ġsend Ġa Ġpacket Ġto Ġan Ġaddon , Ġnormally Ġnot Ġinvoked Ġby Ġyou ĊĠĠĠĠ Ġ* Ġ@ param Ġrequest Ġpacket Ġto Ġsend ĊĠĠĠĠ Ġ* Ġ@ param Ġtype Ġpacket Ġtype Ġso Ġaddon Ġknows Ġwhat Ġto Ġdo ĊĠĠĠĠ Ġ* Ġ@ param Ġexpect Answer Ġif Ġset Ġto Ġtrue Ġfunction Ġwill Ġblock Ġuntil Ġaddon Ġsends Ġa Ġresponse Ġback ĊĠĠĠĠ Ġ* Ġ@ exception ĠTimeout Exception Ġthrown Ġif Ġ 1 2 * check Interval Ġhas Ġpassed Ġwithout Ġa Ġresponse Ġ( only Ġif Ġexpect Answer ) ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġrequest ( request : ĠJsonObject , Ġtype : ĠString , Ġexpect Answer : ĠBoolean ): ĠJsonObject ? Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( server Ġ== Ġnull ) Ġthrow ĠException (" Server Ġis Ġnot Ġrunning . ĠBrowser . start () Ġhas Ġyet Ġto Ġbe Ġcalled .") ĊĠĠĠĠĠĠĠ Ġval Ġid Ġ= Ġpacket Index ++ ĊĊĠĠĠĠĠĠĠ Ġval Ġpacket Ġ= ĠJsonObject (). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġadd Property (" id ", Ġid ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġadd Property (" type ", Ġtype ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġadd Property (" expect Answer ", Ġexpect Answer ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġadd (" request ", Ġrequest ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġsynchronized ( request Queue ) Ġ{ Ġrequest Queue Ġ+= Ġpacket Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ(! expect Answer ) Ġreturn Ġnull ĊĊĠĠĠĠĠĠĠ Ġvar Ġtries Ġ= Ġ 0 ĊĠĠĠĠĠĠĠ Ġwhile Ġ( true ) Ġ{ ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( id Ġin Ġresponse Queue ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġr Packet Ġ= Ġresponse Queue [ id ] !! ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġresponse Queue . remove ( id ) ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( r Packet [" type "]. asString Ġ== Ġ" heartbeat ") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtries Ġ= Ġ 0 ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontinue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(" response " Ġ! in Ġr Packet ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠInvalid Object Exception (" invalid Ġpacket : Ġ$ r Packet ") ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġr Packet [" response "]. as JsonObject ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(++ tri es Ġ>= Ġ 1 2 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠTimeout Exception (" no Ġresponse Ġfrom Ġpacket : Ġ$ packet ") ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠThread . sleep ( check Interval ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġcheck Ġif Ġan Ġaddon Ġhas Ġestablished Ġa Ġconnection , Ġelse Ġthrow Ġan Ġerror ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġping () Ġ{ ĊĠĠĠĠĠĠĠ Ġrequest ( JsonObject (), Ġ" ping ", Ġtrue ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġ@ param Ġurl ĊĠĠĠĠ Ġ* Ġ@ param Ġactive Ġ( default Ġ= Ġtrue ) Ġshould Ġthe Ġnew Ġtab Ġbecome Ġthe Ġcurrent Ġactive Ġone ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġnew Tab ( url : ĠString , Ġactive : ĠBoolean Ġ= Ġtrue ): ĠTab Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġresponse Ġ= Ġrequest ( JsonObject (). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġadd Property (" url ", Ġurl ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġadd Property (" active ", Ġactive ) ĊĠĠĠĠĠĠĠ Ġ}, Ġ" new Tab ", Ġtrue ) !! ĊĊĠĠĠĠĠĠĠ Ġreturn ĠTab . fromJson ( this , Ġresponse [" tab "]. as JsonObject ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** Ġ= Ġget Tabs ( active = true , Ġcurrent Window = true ). last () Ġ*/ ĊĠĠĠ Ġfun ĠgetCurrent Tab (): ĠTab Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġget Tabs ( Tab Options (). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġactive Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcurrent Window Ġ= Ġtrue ĊĠĠĠĠĠĠĠ Ġ}). last () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġget Tabs ( options : ĠTab Options ? Ġ= Ġnull ): ĠList < Tab > Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġresponse Ġ= Ġrequest ( JsonObject (). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġadd (" options ", Ġ( options Ġ?: ĠTab Options ()). toJson ()) ĊĠĠĠĠĠĠĠ Ġ}, Ġ" get Tabs ", Ġtrue ) !! ĊĊĠĠĠĠĠĠĠ Ġval Ġlist Ġ= ĠArrayList < Tab >() ĊĠĠĠĠĠĠĠ Ġval Ġtabs Ġ= Ġresponse [" tabs "]. as JsonArray ĊĠĠĠĠĠĠĠ Ġfor Ġ( tab Ġin Ġtabs ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlist Ġ+= ĠTab . fromJson ( this , Ġtab . as JsonObject ) ĊĠĠĠĠĠĠĠ Ġreturn Ġlist ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġon Tab Created ( block : Ġ( Tab ) Ġ-> ĠUnit ) Ġ{ Ġon Tab Created Ġ+= Ġblock Ġ} ĊĠĠĠ Ġfun Ġon Tab Updated ( block : Ġ( Tab ) Ġ-> ĠUnit ) Ġ{ Ġon Tab Updated Ġ+= Ġblock Ġ} Ċ Ċ }