package Ġai . plat on . pulsar . protocol . browser . emulator . context Ċ Ċ import Ġai . plat on . pulsar . common . DateTime s Ċ import Ġai . plat on . pulsar . common . metrics . App Metrics Ċ import Ġai . plat on . pulsar . common . config . Capability Types Ċ import Ġai . plat on . pulsar . common . config . Immutable Config Ċ import Ġai . plat on . pulsar . common . proxy .* Ċ import Ġai . plat on . pulsar . crawl . fetch . Fetch Result Ċ import Ġai . plat on . pulsar . crawl . fetch . Fetch Task Ċ import Ġai . plat on . pulsar . crawl . fetch . driver . WebDriver Ċ import Ġai . plat on . pulsar . crawl . fetch . privacy . Browser InstanceId Ċ import Ġai . plat on . pulsar . crawl . fetch . privacy . Privacy Context Id Ċ import Ġai . plat on . pulsar . protocol . browser . driver . WebDriver Pool Manager Ċ import Ġai . plat on . pulsar . protocol . browser . driver . WebDriver Pool Manager . Companion . DRIVER _ CLOSE _ TIME _ OUT Ċ import Ġai . plat on . pulsar . protocol . browser . emulator . WebDriver Pool Exception Ċ import Ġai . plat on . pulsar . protocol . browser . emulator . WebDriver Pool Ex hausted Exception Ċ import Ġcom . co da h ale . metrics . Gauge Ċ import Ġorg . slf 4 j . LoggerFactory Ċ import Ġjava . time . Duration Ċ import Ġjava . time . Instant Ċ import Ġjava . util . concurrent . Concurrent Linked Deque Ċ 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 Ġkotlin . concurrent . with Lock Ċ import Ġkotlin . random . Random Ċ Ċ class ĠWebDriver Context ( ĊĠĠĠĠĠĠĠ Ġval Ġbrowser Id : ĠBrowser InstanceId , ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġdriver Pool Manager : ĠWebDriver Pool Manager , ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġconf : ĠImmutable Config Ċ ): ĠAuto Closeable Ġ{ ĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġnum Global Running Tasks Ġ= ĠAtomicInteger () ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġglobal Tasks Ġ= ĠApp Metrics . reg . meter ( this , Ġ" global Tasks ") ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġglobal Finished Tasks Ġ= ĠApp Metrics . reg . meter ( this , Ġ" global Finished Tasks ") ĊĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġlock Ġ= ĠRe entrant Lock () ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġnot Busy Ġ= Ġlock . new Condition () ĊĊĠĠĠĠĠĠĠ Ġinit Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ ĠApp Metrics . reg . register ( this ," global Running Tasks ", ĠG auge Ġ{ Ġnum Global Running Tasks . get () Ġ}) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġval Ġlog Ġ= ĠLoggerFactory . getLogger ( WebDriver Context :: class . java ) !! ĊĠĠĠ Ġprivate Ġval Ġfetch Max Retry Ġ= Ġconf . getInt ( Capability Types . HTTP _ FETCH _ MAX _ RETRY , Ġ 3 ) ĊĠĠĠ Ġprivate Ġval Ġrunning Tasks Ġ= ĠConcurrent Linked Deque < Fetch Task >() ĊĠĠĠ Ġprivate Ġval Ġclosed Ġ= ĠAtomic Boolean () ĊĠĠĠ Ġprivate Ġval ĠisActive Ġget () Ġ= Ġ! closed . get () ĊĠĠĠ Ġprivate Ġval Ġis Shutdown Ġ= ĠAtomic Boolean () ĊĊĠĠĠ Ġsuspend Ġfun Ġrun ( task : ĠFetch Task , Ġbrowse Fun : Ġsuspend Ġ( Fetch Task , ĠWebDriver ) Ġ-> ĠFetch Result ): ĠFetch Result Ġ{ ĊĠĠĠĠĠĠĠ Ġglobal Tasks . mark () ĊĠĠĠĠĠĠĠ Ġreturn Ġcheck Ab normal Result ( task ) Ġ?: Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġrunning Tasks . add ( task ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġnum Global Running Tasks . increment AndGet () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdriver Pool Manager . run ( browser Id , Ġtask . priority , Ġtask . volatile Config ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġbrowse Fun ( task , Ġit ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ?: Fetch Result . crawl Retry ( task ) ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠWebDriver Pool Ex hausted Exception ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlog . warn (" {}. ĠRetry Ġtask Ġ{} Ġin Ġcrawl Ġscope Ġ| Ġcause Ġby : Ġ{}", Ġtask . page . id , Ġtask . id , Ġe . message ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠFetch Result . crawl Retry ( task ) ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠWebDriver Pool Exception ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlog . warn (" {}. ĠRetry Ġtask Ġ{} Ġin Ġcrawl Ġscope Ġ| Ġcaused Ġby : Ġ{}", Ġtask . page . id , Ġtask . id , Ġe . message ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠFetch Result . crawl Retry ( task ) ĊĠĠĠĠĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġrunning Tasks . remove ( task ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġnum Global Running Tasks . decrement AndGet () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġglobal Finished Tasks . mark () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( running Tasks . isEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlock . with Lock Ġ{ Ġnot Busy . signal All () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( num Global Running Tasks . get () Ġ== Ġ 0 Ġ&& Ġglobal Finished Tasks . five Minute Rate Ġ> Ġ 0 . 1 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . debug (" No Ġrunning Ġtask Ġnow Ġ| Ġ${ global Finished Tasks . count }/${ global Tasks . count } Ġ( finished / all )") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġshutdown () Ġ{ ĊĠĠĠĠĠĠĠ Ġis Shutdown . set ( true ) ĊĠĠĠĠĠĠĠ Ġclose () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġclose () Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( closed . compare AndSet ( false , Ġtrue )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdo Close () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( t : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . error (" Unexpected Ġexception ", Ġt ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġdo Close () Ġ{ ĊĠĠĠĠĠĠĠ Ġ// Ġclose Ġunderlying ĠIO Ġbased Ġmodules Ġasynchronously ĊĠĠĠĠĠĠĠ Ġclose Under lying Layer () ĊĊĠĠĠĠĠĠĠ Ġif Ġ(! is Shutdown . get ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwait Until No Running Tasks () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġif Ġ( running Tasks . isNotEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlog . warn (" Still Ġ{} Ġrunning Ġtasks Ġafter Ġcontext Ġclose Ġ| Ġ{}", ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrunning Tasks . size , Ġrunning Tasks . join ToString Ġ{ Ġ"${ it . id } (${ it . state })" Ġ}) ĊĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlog . info (" Web Ġdriver Ġcontext Ġis Ġclosed Ġsuccessfully Ġ| Ġ{}", Ġbrowser Id ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġclose Under lying Layer () Ġ{ ĊĠĠĠĠĠĠĠ Ġ// ĠMark Ġall Ġworking Ġtasks Ġare Ġcanceled , Ġso Ġthey Ġreturn Ġas Ġsoon Ġas Ġpossible , ĊĠĠĠĠĠĠĠ Ġ// Ġthe Ġready Ġtasks Ġare Ġblocked Ġto Ġwait Ġfor Ġdriver Manager . reset () Ġfinish ĊĠĠĠĠĠĠĠ Ġ// ĠTODO : Ġwhy Ġthe Ġcanceled Ġtasks Ġdo Ġnot Ġreturn Ġin Ġtime ? ĊĠĠĠĠĠĠĠ Ġrunning Tasks . forEach Ġ{ Ġit . cancel () Ġ} ĊĠĠĠĠĠĠĠ Ġ// Ġmay Ġwait Ġfor Ġcancell ing Ġfinish ? ĊĠĠĠĠĠĠĠ Ġ// ĠClose Ġall Ġonline Ġdrivers Ġand Ġdelete Ġthe Ġbrowser Ġdata ĊĠĠĠĠĠĠĠ Ġdriver Pool Manager . close Driver Pool ( browser Id , ĠDRI VER _ CLOSE _ TIME _ OUT ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġwait Until No Running Tasks () Ġ{ ĊĠĠĠĠĠĠĠ Ġlock . with Lock Ġ{ Ġnot Busy . await ( 2 0 , ĠTimeUnit . SECONDS ) Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġcheck Ab normal Result ( task : ĠFetch Task ): ĠFetch Result ? Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! isActive ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠFetch Result . privacy Retry ( task ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġif Ġ( driver Pool Manager . is Ret ired Pool ( browser Id )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠFetch Result . privacy Retry ( task ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġif Ġ(++ task . n Retries Ġ> Ġfetch Max Retry ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠFetch Result . crawl Retry ( task ). also Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . info (" Too Ġmany Ġtask Ġretries , Ġupgrade Ġto Ġcrawl Ġretry Ġ| Ġ{}", Ġtask . url ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġreturn Ġnull ĊĠĠĠ Ġ} Ċ } Ċ Ċ class ĠProxy Context ( ĊĠĠĠĠĠĠĠ Ġvar Ġproxy Entry : ĠProxy Entry ? Ġ= Ġnull , ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġproxy Pool Manager : ĠProxy Pool Manager , ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġdriver Context : ĠWebDriver Context , ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġconf : ĠImmutable Config Ċ ): ĠAuto Closeable Ġ{ ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġnum Proxy Abs ence Ġ= ĠAtomicInteger () ĊĠĠĠĠĠĠĠ Ġvar Ġlast Proxy Absent Time Ġ= ĠInstant . now () ĊĠĠĠĠĠĠĠ Ġval Ġnum Running Tasks Ġ= ĠAtomicInteger () ĊĠĠĠĠĠĠĠ Ġvar Ġmax Allowed Proxy Abs ence Ġ= Ġ 2 0 0 ĊĊĠĠĠĠĠĠĠ Ġinit Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmap Of ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" proxy Abs ences " Ġto ĠG auge Ġ{ Ġnum Proxy Abs ence . get () Ġ}, ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" running Tasks " Ġto ĠG auge Ġ{ Ġnum Running Tasks . get () Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ). forEach Ġ{ ĠApp Metrics . reg . register ( this , Ġit . key , Ġit . value ) Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ@ Throws ( Proxy Exception :: class ) ĊĠĠĠĠĠĠĠ Ġfun Ġcreate ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġid : ĠPrivacy Context Id , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdriver Context : ĠWebDriver Context , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġproxy Pool Manager : ĠProxy Pool Manager , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġconf : ĠImmutable Config ĊĠĠĠĠĠĠĠ Ġ): ĠProxy Context Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġproxy Pool Ġ= Ġproxy Pool Manager . proxy Pool ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġproxy Ġ= Ġproxy Pool . take () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( proxy Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnum Proxy Abs ence . take If Ġ{ Ġit . get () Ġ> Ġ 0 Ġ} ?. decrement AndGet () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġproxy Entry 0 Ġ= Ġproxy Pool Manager . active Proxy Entries . compute If Absent ( id . data Dir ) Ġ{ Ġproxy Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġproxy Entry 0 . start Work () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠProxy Context ( proxy Entry 0 , Ġproxy Pool Manager , Ġdriver Context , Ġconf ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnum Proxy Abs ence . increment AndGet () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcheck Proxy Abs ence () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠNo Proxy Exception (" No Ġproxy Ġfound Ġin Ġpool Ġ${ proxy Pool . java Class . simple Name } Ġ| Ġ$ proxy Pool ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġfun Ġcheck Proxy Abs ence () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( num Proxy Abs ence . get () Ġ> Ġmax Allowed Proxy Abs ence ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġnow Ġ= ĠInstant . now () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġday 1 Ġ= ĠDateTime s . day OfMonth ( last Proxy Absent Time ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġday 2 Ġ= ĠDateTime s . day OfMonth ( now ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( day 2 Ġ!= Ġday 1 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġclear Ġthe Ġproxy Ġabsence Ġcounter Ġat Ġevery Ġstart Ġof Ġday ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnum Proxy Abs ence . set ( 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlast Proxy Absent Time Ġ= Ġnow ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠProxy Vendor Un trusted Exception (" No Ġproxy Ġavailable , Ġthe Ġvendor Ġis Ġun trusted ." Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" ĠProxy Ġis Ġabsent Ġfor Ġ$ num Proxy Abs ence Ġtimes Ġfrom Ġ$ last Proxy Absent Time ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġval Ġlog Ġ= ĠLoggerFactory . getLogger ( Proxy Context :: class . java ) !! ĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠIf Ġthe Ġnumber Ġof Ġsuccess Ġexceeds Ġ[ max Fetch Success ], Ġemit Ġa ĠPrivacy Retry Ġresult ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġprivate Ġval Ġmax Fetch Success Ġ= Ġconf . getInt ( Capability Types . PROXY _ MAX _ FETCH _ SUCCESS , ĠInt . MAX _ VALUE Ġ/ Ġ 1 0 ) ĊĠĠĠ Ġprivate Ġval Ġmin TimeTo Live Ġ= ĠDuration . of Seconds ( 3 0 ) ĊĠĠĠ Ġprivate Ġval Ġclosing Ġ= ĠAtomic Boolean () ĊĠĠĠ Ġprivate Ġval Ġclosed Ġ= ĠAtomic Boolean () ĊĊĠĠĠ Ġval Ġis Enabled Ġget () Ġ= Ġproxy Pool Manager . isEnabled ĊĠĠĠ Ġval ĠisActive Ġget () Ġ= Ġproxy Pool Manager . isActive Ġ&& Ġ! closing . get () Ġ&& Ġ! closed . get () ĊĊĠĠĠ Ġinit Ġ{ ĊĠĠĠĠĠĠĠ Ġmax Allowed Proxy Abs ence Ġ= Ġconf . getInt ( Capability Types . PROXY _ MAX _ ALLOWED _ PROXY _ ABS ENCE , Ġ 1 0 ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġsuspend Ġfun Ġrun ( task : ĠFetch Task , Ġbrowse Fun : Ġsuspend Ġ( Fetch Task , ĠWebDriver ) Ġ-> ĠFetch Result ): ĠFetch Result Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġcheck Ab normal Result ( task ) Ġ?: run 0 ( task , Ġbrowse Fun ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Throws ( Proxy Exception :: class ) ĊĠĠĠ Ġprivate Ġsuspend Ġfun Ġrun 0 ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtask : ĠFetch Task , Ġbrowse Fun : Ġsuspend Ġ( Fetch Task , ĠWebDriver ) Ġ-> ĠFetch Result ): ĠFetch Result Ġ{ ĊĠĠĠĠĠĠĠ Ġvar Ġsuccess Ġ= Ġfalse ĊĠĠĠĠĠĠĠ Ġreturn Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġbefore Task Start ( task ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġproxy Pool Manager . run With ( proxy Entry ) Ġ{ Ġdriver Context . run ( task , Ġbrowse Fun ) Ġ}. also Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsuccess Ġ= Ġit . response . status . is Success ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . response . page Datum . proxy Entry Ġ= Ġproxy Entry ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnum Proxy Abs ence . take If Ġ{ Ġit . get () Ġ> Ġ 0 Ġ} ?. decrement AndGet () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠProxy Exception ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġhandle Proxy Exception ( task , Ġe ) ĊĠĠĠĠĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġafter Task Finished ( task , Ġsuccess ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġcheck Ab normal Result ( task : ĠFetch Task ): ĠFetch Result ? Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! isActive ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠFetch Result . privacy Retry ( task ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġcheck Proxy Abs ence () ĊĊĠĠĠĠĠĠĠ Ġreturn Ġnull ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġhandle Proxy Exception ( task : ĠFetch Task , Ġe : ĠProxy Exception ): ĠFetch Result Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġwhen Ġ( e ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠProxy Ins ufficient Balance Exception Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow Ġe ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠProxy Ret ired Exception Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . warn (" {}, Ġcontext Ġreset Ġwill Ġbe Ġtriggered Ġ| Ġ{}", Ġe . message , Ġtask . proxy Entry ? :" < no Ġproxy >") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠFetch Result . privacy Retry ( task , Ġreason Ġ= Ġe ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġis ĠNo Proxy Exception Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnum Proxy Abs ence . increment AndGet () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcheck Proxy Abs ence () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . warn (" No Ġproxy Ġavailable Ġtemporary Ġthe Ġ{} th Ġtimes , Ġcause : Ġ{}", Ġnum Proxy Abs ence , Ġe . message ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠFetch Result . crawl Retry ( task ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġelse Ġ-> Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . warn (" Task Ġfailed Ġwith Ġproxy Ġ{}, Ġcause : Ġ{}", Ġproxy Entry , Ġe . message ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠFetch Result . privacy Retry ( task ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġbefore Task Start ( task : ĠFetch Task ) Ġ{ ĊĠĠĠĠĠĠĠ Ġnum Running Tasks . increment AndGet () ĊĊĠĠĠĠĠĠĠ Ġ// ĠIf Ġthe Ġproxy Ġis Ġidle , Ġand Ġhere Ġcomes Ġa Ġnew Ġtask , Ġreset Ġthe Ġcontext ĊĠĠĠĠĠĠĠ Ġ// ĠThe Ġproxy Ġis Ġabout Ġto Ġbe Ġun usable , Ġreset Ġthe Ġcontext ĊĠĠĠĠĠĠĠ Ġproxy Entry ?. also Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġtask . proxy Entry Ġ= Ġit ĊĠĠĠĠĠĠĠĠĠĠĠ Ġit . last Active Time Ġ= ĠInstant . now () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( it . will Expire After ( min TimeTo Live )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( closing . compare AndSet ( false , Ġtrue )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠProxy Ret ired Exception (" The Ġproxy Ġis Ġexpired Ġ($ min TimeTo Live )") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġsuccess Pages Ġ= Ġit . num Success Pages . get () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠAdd Ġa Ġrandom Ġnumber Ġto Ġdist urb Ġthe Ġanti - spider ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġdelta Ġ= Ġ( 0 . 2 5 Ġ* Ġmax Fetch Success ). toInt () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġlimit Ġ= Ġmax Fetch Success Ġ+ ĠRandom ( System . currentTimeMillis ()). nextInt (- delta , Ġdelta ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( success Pages Ġ> Ġlimit ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠIf Ġa Ġproxy Ġserved Ġto Ġmany Ġpages , Ġthe Ġtarget Ġsite Ġmay Ġtrack Ġthe Ġfinger Ġprint Ġof Ġthe Ġc rawler ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// Ġand Ġalso Ġmax Fetch Success Ġcan Ġbe Ġused Ġfor Ġtest Ġpurpose ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog . info (" Ser ved Ġtoo Ġmany Ġpages Ġ($ success Pages /$ max Fetch Success ) Ġ| Ġ{}", Ġit ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( closing . compare AndSet ( false , Ġtrue )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠProxy Ret ired Exception (" Ser ved Ġtoo Ġmany Ġpages ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġafter Task Finished ( task : ĠFetch Task , Ġsuccess : ĠBoolean ) Ġ{ ĊĠĠĠĠĠĠĠ Ġnum Running Tasks . decrement AndGet () ĊĠĠĠĠĠĠĠ Ġproxy Entry ?. apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( success ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrefresh () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnum Success Pages . increment AndGet () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlast Target Ġ= Ġtask . url ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġserved Domains . add ( task . domain ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnum Failed Pages . increment AndGet () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠBlock Ġuntil Ġthe Ġproxy Ġis Ġoffline ĊĠĠĠĠ Ġ* Ġ*/ ĊĠĠĠ Ġoverride Ġfun Ġclose () Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( closed . compare AndSet ( false , Ġtrue )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġproxy Pool Manager . active Proxy Entries . remove ( driver Context . browser Id . data Dir ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ