/* Ċ Ġ* ĠCopyright Ġ 2 0 2 0 - 2 0 2 1 ĠJetBrains Ġs . r . o . Ġand Ġrespective Ġauthors Ġand Ġdevelopers . Ċ Ġ* ĠUse Ġof Ġthis Ġsource Ġcode Ġis Ġgoverned Ġby Ġthe ĠApache Ġ 2 . 0 Ġlicense Ġthat Ġcan Ġbe Ġfound Ġin Ġthe ĠLICENSE . txt Ġfile . Ċ Ġ*/ Ċ Ċ package Ġorg . jetbrains . compose . desktop . ui . tool ing . preview . rpc Ċ Ċ import Ġjava . io .* Ċ import Ġjava . net . Socket Ċ import Ġjava . net . Socket TimeoutException Ċ import Ġjava . util . concurrent . atomic . Atomic Boolean Ċ Ċ fun Ġget Local Connection OrNull ( ĊĠĠĠ Ġport : ĠInt , Ġlogger : ĠPreview Logger , ĠonClose : Ġ() Ġ-> ĠUnit Ċ ): ĠRemote Connection ? Ġ= ĊĠĠĠ Ġget Local Socket OrNull ( port , Ġtrials Ġ= Ġ 3 , Ġtrial Delay Ġ= Ġ 5 0 0 )?. let Ġ{ Ġsocket Ġ-> ĊĠĠĠĠĠĠĠ ĠRemote Connection Impl ( socket , Ġlogger , ĠonClose ) ĊĠĠĠ Ġ} Ċ Ċ abstract Ġclass ĠRemote Connection Ġ: ĠAuto Closeable Ġ{ ĊĠĠĠ Ġabstract Ġval Ġis Alive : ĠBoolean ĊĠĠĠ Ġabstract Ġfun Ġreceive Command ( on Result : Ġ( Command ) Ġ-> ĠUnit ) ĊĠĠĠ Ġabstract Ġfun Ġreceive Data ( on Result : Ġ( ByteArray ) Ġ-> ĠUnit ) ĊĠĠĠ Ġabstract Ġfun Ġsend Command ( command : ĠCommand ) ĊĠĠĠ Ġabstract Ġfun Ġsend Data ( data : ĠByteArray ) ĊĊĠĠĠ Ġfun Ġreceive Utf 8 String Data ( on Result : Ġ( String ) Ġ-> ĠUnit ) Ġ{ ĊĠĠĠĠĠĠĠ Ġreceive Data Ġ{ Ġbytes Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġstring Ġ= Ġbytes . toString ( Charsets . UTF _ 8 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġon Result ( string ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĠĠĠ Ġfun Ġsend Utf 8 String Data ( string : ĠString ) Ġ{ ĊĠĠĠĠĠĠĠ Ġsend Data ( string . toByteArray ( Charsets . UTF _ 8 )) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġsend Command ( type : ĠCommand . Type , Ġvar arg Ġargs : ĠString ) Ġ{ ĊĠĠĠĠĠĠĠ Ġsend Command ( Command ( type , Ġ* args )) ĊĠĠĠ Ġ} Ċ } Ċ Ċ internal Ġclass ĠRemote Connection Impl ( ĊĠĠĠ Ġprivate Ġval Ġsocket : ĠSocket , ĊĠĠĠ Ġprivate Ġval Ġlog : ĠPreview Logger , ĊĠĠĠ Ġprivate Ġval ĠonClose : Ġ() Ġ-> ĠUnit Ċ ): ĠRemote Connection () Ġ{ ĊĠĠĠ Ġinit Ġ{ ĊĠĠĠĠĠĠĠ Ġsocket . so Timeout Ġ= ĠSOCKET _ TIMEOUT _ MS ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġval Ġinput Ġ= ĠData InputStream ( socket . getInputStream ()) ĊĠĠĠ Ġprivate Ġval Ġoutput Ġ= ĠData OutputStream ( socket . get OutputStream ()) ĊĠĠĠ Ġprivate Ġvar Ġis Connection Alive Ġ= ĠAtomic Boolean ( true ) ĊĊĠĠĠ Ġoverride Ġval Ġis Alive : ĠBoolean ĊĠĠĠĠĠĠĠ Ġget () Ġ= Ġ! socket . is Closed Ġ&& Ġis Connection Alive . get () ĊĊĠĠĠ Ġprivate Ġinline Ġfun Ġif Alive ( fn : Ġ() Ġ-> ĠUnit ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( is Alive ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfn () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġclose () Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( is Connection Alive . compare AndSet ( true , Ġfalse )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlog Ġ{ Ġ" CLO SING " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġsocket . close () ĊĠĠĠĠĠĠĠĠĠĠĠ ĠonClose () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlog Ġ{ Ġ" CLOSED " Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġsend Command ( command : ĠCommand ) Ġ= Ġif Alive Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġcommand Str Ġ= Ġcommand . asString () ĊĠĠĠĠĠĠĠ Ġval Ġdata Ġ= Ġcommand Str . toByteArray () ĊĠĠĠĠĠĠĠ Ġwrite Data ( output , Ġdata , Ġmax DataSize Ġ= ĠMAX _ CMD _ SIZE ) ĊĠĠĠĠĠĠĠ Ġlog Ġ{ Ġ" SENT ĠCOMMAND Ġ'$ command Str '" Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġsend Data ( data : ĠByteArray ) Ġ= Ġif Alive Ġ{ ĊĠĠĠĠĠĠĠ Ġwrite Data ( output , Ġdata , Ġmax DataSize Ġ= ĠMAX _ BINARY _ SIZE ) ĊĠĠĠĠĠĠĠ Ġlog Ġ{ Ġ" SENT ĠDATA Ġ[ ${ data . size }] " Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġreceive Command ( on Result : Ġ( Command ) Ġ-> ĠUnit ) Ġ= Ġif Alive Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġline Ġ= Ġread Data ( input , ĠMAX _ CMD _ SIZE )?. toString ( Charsets . UTF _ 8 ) ĊĠĠĠĠĠĠĠ Ġif Ġ( line Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġcmd Ġ= ĠCommand . fromString ( line ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( cmd Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog Ġ{ Ġ" G OT ĠUNKNOWN ĠCOMMAND Ġ'$ line '" Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog Ġ{ Ġ" G OT ĠCOMMAND Ġ'$ line '" Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġon Result ( cmd ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġclose () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġreceive Data ( on Result : Ġ( ByteArray ) Ġ-> ĠUnit ) Ġ= Ġif Alive Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġdata Ġ= Ġread Data ( input , ĠMAX _ BINARY _ SIZE ) ĊĠĠĠĠĠĠĠ Ġif Ġ( data Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlog Ġ{ Ġ" G OT Ġ[ ${ data . size }] " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġon Result ( data ) ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġclose () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġwrite Data ( output : ĠData OutputStream , Ġdata : ĠByteArray , Ġmax DataSize : ĠInt ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! is Alive ) Ġreturn Ġfalse ĊĊĠĠĠĠĠĠĠ Ġreturn Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsize Ġ= Ġdata . size ĊĠĠĠĠĠĠĠĠĠĠĠ Ġassert ( size Ġ< Ġmax DataSize ) Ġ{ Ġ" Data Ġis Ġtoo Ġbig : Ġ$ size Ġ>= Ġ$ max DataSize " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġoutput . writeInt ( size ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġindex Ġ= Ġ 0 ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġbuf Size Ġ= Ġmin Of ( MAX _ BUF _ SIZE , Ġsize ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ( index Ġ< Ġsize ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġlen Ġ= Ġmin Of ( buf Size , Ġsize Ġ- Ġindex ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoutput . write ( data , Ġindex , Ġlen ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġindex Ġ+= Ġlen ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġoutput . flush () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtrue ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠIOException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġfalse ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġread Data ( input : ĠData InputStream , Ġmax DataSize : ĠInt ): ĠByteArray ? Ġ{ ĊĠĠĠĠĠĠĠ Ġwhile Ġ( is Alive ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsize Ġ= Ġinput . readInt () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( size Ġ== Ġ- 1 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbreak ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġassert ( size Ġ< Ġmax DataSize ) Ġ{ Ġ" Data Ġis Ġtoo Ġbig : Ġ$ size Ġ>= Ġ$ max DataSize " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġbytes Ġ= ĠByteArray ( size ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġbuf Size Ġ= Ġmin Of ( size , ĠMAX _ BUF _ SIZE ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġindex Ġ= Ġ 0 ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ( index Ġ< Ġsize ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġlen Ġ= Ġmin Of ( buf Size , Ġsize Ġ- Ġindex ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġbytes Read Ġ= Ġinput . read ( bytes , Ġindex , Ġlen ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġindex Ġ+= Ġbytes Read ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġbytes ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠIOException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( e Ġ! is ĠSocket TimeoutException ) Ġbreak ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġreturn Ġnull ĊĠĠĠ Ġ} Ċ } ĊĊĊ