This repository has been archived by the owner on Apr 6, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 37
/
DeepstreamClient.java
336 lines (304 loc) · 14.2 KB
/
DeepstreamClient.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
package io.deepstream;
import com.google.gson.JsonElement;
import com.google.j2objc.annotations.ObjectiveCName;
import java.net.URISyntaxException;
import java.util.Date;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
/**
* The main entry point for a DeepstreamClient. You can create a client directly using the constructors or use the
* {@link DeepstreamFactory#getClient()}, {@link DeepstreamFactory#getClient(String)} or
* {@link DeepstreamFactory#getClient(String, Properties)} to create one for you and hold them for future reference.
*/
public class DeepstreamClient extends DeepstreamClientAbstract {
/**
* The getters for data-sync, such as {@link RecordHandler#getRecord(String)},
* {@link RecordHandler#getList(String)}, provider functionality such as {@link RecordHandler#listen(String, ListenListener)}
* and single requests like {@link RecordHandler#snapshot(String)}
*/
public final RecordHandler record;
/**
* The entry point for events, such as {@link EventHandler#subscribe(String, EventListener)},
* {@link EventHandler#emit(String)} and provider functionality such as {@link EventHandler#listen(String, ListenListener)}
*/
public final EventHandler event;
/**
* The entry point for rpcs, both requesting them via {@link RpcHandler#make(String, Object)} and
* providing them via {@link RpcHandler#provide(String, RpcRequestedListener)}
*/
public final RpcHandler rpc;
/**
* The entry point for presence, both querying for clients via {@link PresenceHandler#getAll()}
* and subscribing/unsubscribing to login events via {@link PresenceHandler#subscribe(PresenceEventListener)} and
* {@link PresenceHandler#unsubscribe(PresenceEventListener)}
*/
public final PresenceHandler presence;
private final Connection connection;
/**
* deepstream.io javascript client, defaults to using default properties
* {@link DeepstreamClient#DeepstreamClient(String, Properties)}
*
* @throws URISyntaxException Thrown if the url in incorrect
*/
@ObjectiveCName("init:")
public DeepstreamClient(final String url) throws URISyntaxException {
this(url, new DeepstreamConfig());
}
/**
* deepstream.io javascript client
*
* @throws URISyntaxException Thrown if the url in incorrect
*/
@ObjectiveCName("init:options:")
public DeepstreamClient(final String url, Map options) throws URISyntaxException, InvalidDeepstreamConfig {
this(url, new DeepstreamConfig(options));
}
/**
* deepstream.io javascript client
*
* @throws URISyntaxException Thrown if the url in incorrect
*/
@ObjectiveCName("init:properties:")
public DeepstreamClient(final String url, Properties options) throws URISyntaxException, InvalidDeepstreamConfig {
this(url, new DeepstreamConfig(options));
}
/**
* deepstream.io java client
* @param url URL to connect to. The protocol can be omited, e.g. <host>:<port>
* @param endpointFactory An EndpointFactory that returns an Endpoint
* @throws URISyntaxException Thrown if the url in incorrect
*/
@ObjectiveCName("init:endpointFactory:")
public DeepstreamClient(final String url, EndpointFactory endpointFactory) throws URISyntaxException, InvalidDeepstreamConfig{
this(url, new DeepstreamConfig(), endpointFactory);
}
/**
* deepstream.io java client
* @param url URL to connect to. The protocol can be omited, e.g. <host>:<port>
* @param endpointFactory An EndpointFactory that returns an Endpoint
* @throws URISyntaxException Thrown if the url in incorrect
*/
@ObjectiveCName("init:options:endpointFactory:")
public DeepstreamClient(final String url, Properties options, EndpointFactory endpointFactory) throws URISyntaxException, InvalidDeepstreamConfig {
this(url, new DeepstreamConfig(options), endpointFactory);
}
/**
* deepstream.io java client
* @param url URL to connect to. The protocol can be omited, e.g. <host>:<port>
* @param endpointFactory An EndpointFactory that returns an Endpoint
* @throws URISyntaxException Thrown if the url in incorrect
*/
@ObjectiveCName("init:properties:endpointFactory:")
public DeepstreamClient(final String url, Map options, EndpointFactory endpointFactory) throws URISyntaxException, InvalidDeepstreamConfig {
this(url, new DeepstreamConfig(options), endpointFactory);
}
/**
* deepstream.io java client
* @param url URL to connect to. The protocol can be omited, e.g. <host>:<port>
* @param deepstreamConfig A map of options that extend the ones specified in DefaultConfig.properties
* @throws URISyntaxException Thrown if the url in incorrect
*/
@ObjectiveCName("init:deepstreamConfig:")
private DeepstreamClient(final String url, DeepstreamConfig deepstreamConfig) throws URISyntaxException {
this(url, deepstreamConfig, new JavaEndpointFactory());
}
/**
* deepstream.io java client
* @param url URL to connect to. The protocol can be omited, e.g. <host>:<port>
* @param deepstreamConfig A map of options that extend the ones specified in DefaultConfig.properties
* @param endpointFactory An EndpointFactory that returns an Endpoint
* @throws URISyntaxException Thrown if the url in incorrect
*/
@ObjectiveCName("init:deepstreamConfig:endpointFactory:")
public DeepstreamClient(final String url, DeepstreamConfig deepstreamConfig, EndpointFactory endpointFactory) throws URISyntaxException {
this.connection = new Connection(url, deepstreamConfig, this, endpointFactory);
this.event = new EventHandler(deepstreamConfig, this.connection, this);
this.rpc = new RpcHandler(deepstreamConfig, this.connection, this);
this.record = new RecordHandler(deepstreamConfig, this.connection, this);
this.presence = new PresenceHandler(deepstreamConfig, this.connection, this);
}
/**
* Gets the {@link RecordHandler} used for data-sync in deepstream. Through records and lists {@link RecordHandler#getRecord(String)},
* {@link RecordHandler#getList(String)}, as well as provider functionality such as {@link RecordHandler#listen(String, ListenListener)}
* and single requests like {@link RecordHandler#snapshot(String)}
*
* @return the {@link RecordHandler}
*/
public RecordHandler getRecordHandler() {
return this.record;
}
/**
* Gets the {@link EventHandler} used for events in deepstream. Through subscribing and emitting events
* {@link EventHandler#subscribe(String, EventListener)}, {@link EventHandler#emit(String)}, as well as provider
* functionality such as {@link EventHandler#listen(String, ListenListener)}
*
* @return the {@link EventHandler}
*/
public EventHandler getEventHandler() {
return this.event;
}
/**
* Gets the {@link RpcHandler} used for rpcs in deepstream. Used for both requesting them via {@link RpcHandler#make(String, Object)} and
* providing them via {@link RpcHandler#provide(String, RpcRequestedListener)}
*/
public RpcHandler getRpcHandler() {
return this.rpc;
}
/**
* Gets the {@link PresenceHandler} for presence functionality in deepstream. Both querying for clients via {@link PresenceHandler#getAll()}
* and subscribing/unsubscribing to login events via {@link PresenceHandler#subscribe(PresenceEventListener)} and
* {@link PresenceHandler#unsubscribe(PresenceEventListener)}
*/
public PresenceHandler getPresenceHandler() {
return this.presence;
}
/**
* Adds a {@link DeepstreamRuntimeErrorHandler} that will catch all RuntimeErrors such as AckTimeouts and allow
* the user to gracefully handle them.
*
* @param deepstreamRuntimeErrorHandler The listener to set
*/
@ObjectiveCName("setRuntimeErrorHandler:")
public void setRuntimeErrorHandler( DeepstreamRuntimeErrorHandler deepstreamRuntimeErrorHandler ) {
super.setRuntimeErrorHandler( deepstreamRuntimeErrorHandler );
}
/**
* @see DeepstreamClient#login(JsonElement)
*
* Does not call the login callback, used mainly for anonymous logins where your guaranteed login
*
* @return The login result
*/
@ObjectiveCName("login")
public LoginResult login() {
return this.login(null);
}
/**
* Send authentication parameters to the client to fully open
* the connection.
*
* Please note: Authentication parameters are send over an already established
* connection, rather than appended to the server URL. This means the parameters
* will be encrypted when used with a WSS / HTTPS connection. If the deepstream server
* on the other side has message logging enabled it will however be written to the logs in
* plain text. If additional security is a requirement it might therefor make sense to hash
* the password on the client.
*
* If the connection is not yet established the authentication parameter will be
* stored and send once it becomes available
*
* authParams can be any JSON serializable data structure and its up for the
* permission handler on the server to make sense of them, although something
* like { username: 'someName', password: 'somePass' } will probably make the most sense.
*
* login can be called multiple times until either the connection is authenticated or
* forcefully closed by the server since its maxAuthAttempts threshold has been exceeded
*
* @param authParams JSON.serializable authentication data
* @return The login result
*/
@ObjectiveCName("login:")
public LoginResult login(JsonElement authParams) {
final CountDownLatch loggedInLatch = new CountDownLatch(1);
final LoginResult[] loginResult = new LoginResult[1];
this.connection.authenticate(authParams, new LoginCallback() {
@Override
@ObjectiveCName("loginSuccess:")
public void loginSuccess(Object userData) {
loginResult[0] = new LoginResult(true, userData);
loggedInLatch.countDown();
}
@Override
@ObjectiveCName("loginFailed:data:")
public void loginFailed(Event errorEvent, Object data) {
loginResult[0] = new LoginResult(false, errorEvent, data);
loggedInLatch.countDown();
}
});
try {
loggedInLatch.await();
} catch (InterruptedException e) {
loginResult[0] = new LoginResult(false, null, "An issue occured during login");
}
return loginResult[0];
}
/**
* Closes the connection to the server.
* @return The deepstream client
*/
public DeepstreamClient close() {
this.connection.close(false);
this.getAckTimeoutRegistry().close();
return this;
}
/**
* Add a listener that can be notified via {@link ConnectionStateListener#connectionStateChanged(ConnectionState)}
* whenever the {@link ConnectionState} changes
* @param connectionStateListener The listener to add
* @return The deepstream client
*/
@ObjectiveCName("addConnectionChangedListener:")
public DeepstreamClient addConnectionChangeListener( ConnectionStateListener connectionStateListener) {
this.connection.addConnectionChangeListener(connectionStateListener);
return this;
}
/**
* Removes a {@link ConnectionStateListener} added via {@link DeepstreamClient#addConnectionChangeListener(ConnectionStateListener)}
* @param connectionStateListener The listener to remove
* @return The deepstream client
*/
@ObjectiveCName("removeConnectionChangedListener:")
public DeepstreamClient removeConnectionChangeListener( ConnectionStateListener connectionStateListener) {
this.connection.removeConnectionChangeListener(connectionStateListener);
return this;
}
/**
* Returns the current state of the connection.
* @return The connection state
*/
public ConnectionState getConnectionState() {
return this.connection.getConnectionState();
}
/**
* Sets global connectivity state and notifies current connections about it. When connectivity is {@link GlobalConnectivityState#DISCONNECTED)} connection will be closed and
* no reconnects will be attempted. If connectivity is set to {@link GlobalConnectivityState#CONNECTED)} and current {@link ConnectionState)} is {@link ConnectionState#CLOSED)}
* or {@link ConnectionState#ERROR)} then client will try reconnecting.
* @param {GlobalConnectivityState} globalConnectivityState Current global connectivity state
*/
public void setGlobalConnectivityState(GlobalConnectivityState globalConnectivityState){
this.connection.setGlobalConnectivityState(globalConnectivityState);
}
/**
* Returns a random string. The first block of characters
* is a timestamp, in order to allow databases to optimize for semi-
* sequentuel numberings
* @return A unique id
*/
public String getUid() {
String date = Long.toString(new Date().getTime(), 36);
String random = Long.toString((long) (Math.random() * 100000000000000000L), 36);
return date + "-" + random;
}
/**
* A callback that notifies the user if the login process was completed successfully or not, and contains optional data
* received from the server associated to the user
*/
interface LoginCallback {
/**
* Called when {@link DeepstreamClient#login(JsonElement)} is successful
*
* @param userData Optional data that is specific to the user and returned on succesfuly authentication
*/
@ObjectiveCName("loginSuccess:")
void loginSuccess(Object userData);
/**
* Called when {@link DeepstreamClient#login(JsonElement)} is unsuccessful
*
* @param errorEvent error event
* @param data Contains data associated to the failed login, such as the reason
*/
@ObjectiveCName("loginFailed:data:")
void loginFailed(Event errorEvent, Object data);
}
}