4
4
5
5
use React \Dns \Resolver \Resolver ;
6
6
use React \EventLoop \LoopInterface ;
7
- use React \EventLoop \Timer \TimerInterface ;
8
7
use Rx \Disposable \CallbackDisposable ;
9
8
use Rx \Observable ;
10
9
use Rx \ObserverInterface ;
@@ -17,8 +16,8 @@ final class AsyncClient
17
16
{
18
17
const NO_ACTIVITY_TIMEOUT = 120 ;
19
18
const NO_PING_RESPONSE_TIMEOUT = 30 ;
20
- //const NO_ACTIVITY_TIMEOUT = 12;
21
- //const NO_PING_RESPONSE_TIMEOUT = 3 ;
19
+
20
+ protected $ noActivityTimeout = self :: NO_ACTIVITY_TIMEOUT ;
22
21
23
22
/**
24
23
* @var LoopInterface
@@ -50,16 +49,6 @@ final class AsyncClient
50
49
*/
51
50
protected $ delay = 200 ;
52
51
53
- /**
54
- * @var TimerInterface
55
- */
56
- private $ noActivityTimer ;
57
-
58
- /**
59
- * @var TimerInterface
60
- */
61
- private $ pingIimeoutTimer ;
62
-
63
52
/**
64
53
* @param LoopInterface $loop
65
54
* @param string $app Application ID
@@ -93,17 +82,20 @@ public static function create(LoopInterface $loop, string $app, Resolver $resolv
93
82
public function __construct (LoopInterface $ loop , WebsocketClient $ client )
94
83
{
95
84
$ this ->loop = $ loop ;
96
- $ this ->messages = $ client-> shareReplay ( 1 )
85
+ $ this ->messages = $ client
97
86
// Save this subject for sending stuff
98
87
->do (function (MessageSubject $ ms ) {
99
- echo 'set snedSubject ' , PHP_EOL ;
100
88
$ this ->sendSubject = $ ms ;
89
+
90
+ // Resubscribe to an channels we where subscribed to when disconnected
91
+ foreach ($ this ->channels as $ channel => $ _ ) {
92
+ $ this ->subscribeOnChannel ($ channel );
93
+ }
101
94
})
102
95
103
96
// Make sure if there is a disconnect or something
104
97
// that we unset the sendSubject
105
98
->finally (function () {
106
- echo 'unset snedSubject ' , PHP_EOL ;
107
99
$ this ->sendSubject = null ;
108
100
})
109
101
@@ -118,9 +110,8 @@ public function __construct(LoopInterface $loop, WebsocketClient $client)
118
110
// if another value comes along, this all gets disposed (because we are using flatMapLatest)
119
111
// before the timeouts start get triggered
120
112
return Observable::never ()
121
- ->timeout (self :: NO_ACTIVITY_TIMEOUT * 1000 )
113
+ ->timeout ($ this -> noActivityTimeout * 1000 )
122
114
->catch (function () use ($ x ) {
123
- echo 'send ping ' , PHP_EOL ;
124
115
// ping (do something that causes incoming stream to get a message)
125
116
$ this ->send (['event ' => 'pusher:ping ' ]);
126
117
// this timeout will actually timeout with a TimeoutException - causing
@@ -129,16 +120,28 @@ public function __construct(LoopInterface $loop, WebsocketClient $client)
129
120
})
130
121
->startWith ($ x );
131
122
})
123
+
124
+ // Handle connection level errors
132
125
->retryWhen (function (Observable $ errors ) {
133
- echo __LINE__ , ': ' , time (), PHP_EOL ;
134
126
return $ errors ->flatMap (function (Throwable $ throwable ) {
135
127
return $ this ->handleLowLevelError ($ throwable );
136
128
});
137
129
})
130
+
131
+ // Decode JSON
138
132
->_ApiClients_jsonDecode ()
133
+
134
+ // Deal with connection established messages
139
135
->map (function (array $ message ) {
140
- return Event::createFromMessage ($ message );
141
- });
136
+ $ event = Event::createFromMessage ($ message );
137
+
138
+ if ($ event ->getEvent () === 'pusher:connection_established ' ) {
139
+ $ this ->setActivityTimeout ($ event );
140
+ }
141
+
142
+ return $ event ;
143
+ })
144
+ ->share ();
142
145
}
143
146
144
147
/**
@@ -169,7 +172,7 @@ public function channel(string $channel): Observable
169
172
})
170
173
->subscribe ($ observer );
171
174
172
- $ this ->send ([ ' event ' => ' pusher:subscribe ' , ' data ' => [ ' channel ' => $ channel]] );
175
+ $ this ->subscribeOnChannel ( $ channel );
173
176
174
177
return new CallbackDisposable (function () use ($ channel , $ subscription ) {
175
178
$ this ->send (['event ' => 'pusher:unsubscribe ' , 'data ' => ['channel ' => $ channel ]]);
@@ -186,26 +189,54 @@ public function channel(string $channel): Observable
186
189
* Send a message through the client
187
190
*
188
191
* @param array $message Message to send, will be json encoded
192
+ *
193
+ * @return A bool indicating whether or not the connection was active
194
+ * and the given message has been pass onto the connection.
189
195
*/
190
- public function send (array $ message )
196
+ public function send (array $ message ): bool
191
197
{
192
198
if ($ this ->sendSubject === null ) {
193
- echo 'send subject is null when trying to send ' , PHP_EOL ;
194
- return ;
199
+ return false ;
195
200
}
196
201
197
- echo __LINE__ , ' Sending JSON: ' , json_encode ($ message ), PHP_EOL ;
198
202
$ this ->sendSubject ->onNext (json_encode ($ message ));
203
+ return true ;
199
204
}
200
205
201
206
private function handleLowLevelError (Throwable $ throwable )
202
207
{
203
208
$ this ->delay *= 2 ;
204
- echo get_class ($ throwable ), PHP_EOL ;
205
- /*echo get_class($throwable->getPrevious()), PHP_EOL;
206
- echo get_class($throwable->getPrevious()->getPrevious()), PHP_EOL;
207
- echo get_class($throwable->getPrevious()->getPrevious()->getPrevious()), PHP_EOL;*/
208
- echo __LINE__ , ': ' , time (), PHP_EOL ;
209
209
return Observable::timer ($ this ->delay );
210
210
}
211
+
212
+ /**
213
+ * @param string $channel
214
+ */
215
+ private function subscribeOnChannel (string $ channel )
216
+ {
217
+ $ this ->send (['event ' => 'pusher:subscribe ' , 'data ' => ['channel ' => $ channel ]]);
218
+ }
219
+
220
+
221
+ /**
222
+ * Get connection activity timeout from connection established event
223
+ *
224
+ * @param Event $event
225
+ */
226
+ private function setActivityTimeout (Event $ event )
227
+ {
228
+ $ data = $ event ->getData ();
229
+
230
+ // No activity_timeout found on event
231
+ if (!isset ($ data ['activity_timeout ' ])) {
232
+ return ;
233
+ }
234
+
235
+ // activity_timeout holds zero or invalid value (we don't want to hammer Pusher)
236
+ if ((int )$ data ['activity_timeout ' ] <= 0 ) {
237
+ return ;
238
+ }
239
+
240
+ $ this ->noActivityTimeout = (int )$ data ['activity_timeout ' ];
241
+ }
211
242
}
0 commit comments