44
55use Evenement \EventEmitter ;
66use React \Stream \Util ;
7+ use React \EventLoop \LoopInterface ;
78
89/**
910 * @internal
@@ -16,13 +17,25 @@ class LazyClient extends EventEmitter implements Client
1617 private $ closed = false ;
1718 private $ promise ;
1819
20+ private $ loop ;
21+ private $ idlePeriod = 60.0 ;
22+ private $ idleTimer ;
23+ private $ pending = 0 ;
24+
1925 /**
2026 * @param $target
2127 */
22- public function __construct ($ target , Factory $ factory )
28+ public function __construct ($ target , Factory $ factory, LoopInterface $ loop )
2329 {
30+ $ args = array ();
31+ \parse_str (\parse_url ($ target , \PHP_URL_QUERY ), $ args );
32+ if (isset ($ args ['idle ' ])) {
33+ $ this ->idlePeriod = (float )$ args ['idle ' ];
34+ }
35+
2436 $ this ->target = $ target ;
2537 $ this ->factory = $ factory ;
38+ $ this ->loop = $ loop ;
2639 }
2740
2841 private function client ()
@@ -33,11 +46,13 @@ private function client()
3346
3447 $ self = $ this ;
3548 $ pending =& $ this ->promise ;
36- return $ pending = $ this ->factory ->createClient ($ this ->target )->then (function (Client $ client ) use ($ self , &$ pending ) {
49+ $ idleTimer =& $ this ->idleTimer ;
50+ $ loop = $ this ->loop ;
51+ return $ pending = $ this ->factory ->createClient ($ this ->target )->then (function (Client $ client ) use ($ self , &$ pending , &$ idleTimer , $ loop ) {
3752 // connection completed => remember only until closed
3853 $ subscribed = array ();
3954 $ psubscribed = array ();
40- $ client ->on ('close ' , function () use (&$ pending , $ self , &$ subscribed , &$ psubscribed ) {
55+ $ client ->on ('close ' , function () use (&$ pending , $ self , &$ subscribed , &$ psubscribed, & $ idleTimer , $ loop ) {
4156 $ pending = null ;
4257
4358 // foward unsubscribe/punsubscribe events when underlying connection closes
@@ -49,6 +64,11 @@ private function client()
4964 foreach ($ psubscribed as $ pattern => $ _ ) {
5065 $ self ->emit ('punsubscribe ' , array ($ pattern , --$ n ));
5166 }
67+
68+ if ($ idleTimer !== null ) {
69+ $ loop ->cancelTimer ($ idleTimer );
70+ $ idleTimer = null ;
71+ }
5272 });
5373
5474 // keep track of all channels and patterns this connection is subscribed to
@@ -93,8 +113,19 @@ public function __call($name, $args)
93113 return \React \Promise \reject (new \RuntimeException ('Connection closed ' ));
94114 }
95115
96- return $ this ->client ()->then (function (Client $ client ) use ($ name , $ args ) {
97- return \call_user_func_array (array ($ client , $ name ), $ args );
116+ $ that = $ this ;
117+ return $ this ->client ()->then (function (Client $ client ) use ($ name , $ args , $ that ) {
118+ $ that ->awake ();
119+ return \call_user_func_array (array ($ client , $ name ), $ args )->then (
120+ function ($ result ) use ($ that ) {
121+ $ that ->idle ();
122+ return $ result ;
123+ },
124+ function ($ error ) use ($ that ) {
125+ $ that ->idle ();
126+ throw $ error ;
127+ }
128+ );
98129 });
99130 }
100131
@@ -134,7 +165,45 @@ public function close()
134165 $ this ->promise = null ;
135166 }
136167
168+ if ($ this ->idleTimer !== null ) {
169+ $ this ->loop ->cancelTimer ($ this ->idleTimer );
170+ $ this ->idleTimer = null ;
171+ }
172+
137173 $ this ->emit ('close ' );
138174 $ this ->removeAllListeners ();
139175 }
176+
177+ /**
178+ * @internal
179+ */
180+ public function awake ()
181+ {
182+ ++$ this ->pending ;
183+
184+ if ($ this ->idleTimer !== null ) {
185+ $ this ->loop ->cancelTimer ($ this ->idleTimer );
186+ $ this ->idleTimer = null ;
187+ }
188+ }
189+
190+ /**
191+ * @internal
192+ */
193+ public function idle ()
194+ {
195+ --$ this ->pending ;
196+
197+ if ($ this ->pending < 1 && $ this ->idlePeriod >= 0 ) {
198+ $ idleTimer =& $ this ->idleTimer ;
199+ $ promise =& $ this ->promise ;
200+ $ idleTimer = $ this ->loop ->addTimer ($ this ->idlePeriod , function () use (&$ idleTimer , &$ promise ) {
201+ $ promise ->then (function (Client $ client ) {
202+ $ client ->close ();
203+ });
204+ $ promise = null ;
205+ $ idleTimer = null ;
206+ });
207+ }
208+ }
140209}
0 commit comments