1
|
=== modified file 'src/com/goldencode/p2j/main/WebClientBuilder.java'
|
2
|
--- src/com/goldencode/p2j/main/WebClientBuilder.java 2016-02-05 10:17:52 +0000
|
3
|
+++ src/com/goldencode/p2j/main/WebClientBuilder.java 2016-02-20 18:09:00 +0000
|
4
|
@@ -15,6 +15,7 @@
|
5
|
** 004 GES 20150312 Added support for the GUI web client.
|
6
|
** 005 GES 20150710 Modified/added configuration processing for GUI, clipboard flag is ChUI-only.
|
7
|
** 006 CA 20160205 Changed to use ServerKeyStore.getStore().
|
8
|
+** SBI 20160220 Added maxBinaryMessage, maxTextMessage, maxIdleTime websocket's parameters.
|
9
|
*/
|
10
|
|
11
|
package com.goldencode.p2j.main;
|
12
|
@@ -96,10 +97,14 @@
|
13
|
command.add("client:chui:fontsize=" + options.get("fontsize"));
|
14
|
command.add("client:web:clipboard=" + options.get("clipboard"));
|
15
|
}
|
16
|
-
|
17
|
+ // Common Websocket parameters:
|
18
|
command.add("client:web:socketTimeout=" + options.get("webSocketTimeout"));
|
19
|
command.add("client:web:watchdogTimeout=" + options.get("watchdogTimeout"));
|
20
|
|
21
|
+ command.add("client:web:maxBinaryMessage=" + options.get("maxBinaryMessage"));
|
22
|
+ command.add("client:web:maxTextMessage=" + options.get("maxTextMessage"));
|
23
|
+ command.add("client:web:maxIdleTime=" + options.get("maxIdleTime"));
|
24
|
+
|
25
|
if (options.get("port") != null)
|
26
|
{
|
27
|
command.add("client:web:port=" + options.get("port"));
|
28
|
|
29
|
=== modified file 'src/com/goldencode/p2j/main/WebClientBuilderOptions.java'
|
30
|
--- src/com/goldencode/p2j/main/WebClientBuilderOptions.java 2015-08-07 20:47:38 +0000
|
31
|
+++ src/com/goldencode/p2j/main/WebClientBuilderOptions.java 2016-02-20 18:09:36 +0000
|
32
|
@@ -13,6 +13,7 @@
|
33
|
** 002 MAG 20140711 Enable/Disable clipboard.
|
34
|
** 003 GES 20150310 Made this class generic for web clients, not just for ChUI web clients.
|
35
|
** 004 GES 20150717 Added some GUI configuration values.
|
36
|
+** 005 SBI 20160220 Added maxBinaryMessage, maxTextMessage, maxIdleTime websocket's parameters
|
37
|
*/
|
38
|
|
39
|
package com.goldencode.p2j.main;
|
40
|
@@ -20,7 +21,6 @@
|
41
|
import java.util.*;
|
42
|
|
43
|
import com.goldencode.p2j.net.*;
|
44
|
-import com.goldencode.p2j.ui.client.*;
|
45
|
import com.goldencode.p2j.ui.client.chui.driver.*;
|
46
|
|
47
|
/**
|
48
|
@@ -35,6 +35,15 @@
|
49
|
{
|
50
|
/** Directory node name in which our configuration can be found. */
|
51
|
public static final String DIRECTORY_NODE_ID = "webClient";
|
52
|
+
|
53
|
+ /** The default maximal binary message size excepted by the configured websocket */
|
54
|
+ private static final int MAX_BINARY_MESSAGE_SIZE = 32768;
|
55
|
+
|
56
|
+ /** The default maximal text message size excepted by the configured websocket */
|
57
|
+ private static final int MAX_TEXT_MESSAGE_SIZE = 4096;
|
58
|
+
|
59
|
+ /** The default maximal idle time of the configured websocket */
|
60
|
+ private static final int MAX_IDLE_TIMEOUT = 90000;
|
61
|
|
62
|
/**
|
63
|
* Singleton instance. Not set as final to allow it to be invalidated (in case these
|
64
|
@@ -150,6 +159,12 @@
|
65
|
fontsize = getNode(DIRECTORY_NODE_ID, "fontsize", fontsize);
|
66
|
stimeout = getNode(DIRECTORY_NODE_ID, "webSocketTimeout", (int) stimeout);
|
67
|
wtimeout = getNode(DIRECTORY_NODE_ID, "watchdogTimeout", (int) wtimeout);
|
68
|
+
|
69
|
+ // Common websocket parameters:
|
70
|
+ int maxBinaryMessage = getNode(DIRECTORY_NODE_ID, "maxBinaryMessage", MAX_BINARY_MESSAGE_SIZE);
|
71
|
+ int maxTextMessage = getNode(DIRECTORY_NODE_ID, "maxTextMessage", MAX_TEXT_MESSAGE_SIZE);
|
72
|
+ int maxIdleTime = getNode(DIRECTORY_NODE_ID, "maxIdleTime", MAX_IDLE_TIMEOUT);
|
73
|
+
|
74
|
port = getNode(DIRECTORY_NODE_ID, "port", port);
|
75
|
host = getNode(DIRECTORY_NODE_ID, "host", host);
|
76
|
clipboard = getNode(DIRECTORY_NODE_ID, "clipboard", true);
|
77
|
@@ -171,5 +186,8 @@
|
78
|
options.put("host", host);
|
79
|
options.put("clipboard", clipboard ? "true" : "false");
|
80
|
options.put("taskbar", taskbar ? "true" : "false");
|
81
|
+ options.put("maxBinaryMessage", String.valueOf(maxBinaryMessage));
|
82
|
+ options.put("maxTextMessage", String.valueOf(maxTextMessage));
|
83
|
+ options.put("maxIdleTime", String.valueOf(maxIdleTime));
|
84
|
}
|
85
|
}
|
86
|
|
87
|
=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/WebClientMessageTypes.java'
|
88
|
--- src/com/goldencode/p2j/ui/client/driver/web/WebClientMessageTypes.java 2016-02-03 11:21:56 +0000
|
89
|
+++ src/com/goldencode/p2j/ui/client/driver/web/WebClientMessageTypes.java 2016-02-20 16:11:14 +0000
|
90
|
@@ -19,6 +19,7 @@
|
91
|
** and z-order operations.
|
92
|
** 005 CA 20151024 Added support for WINDOW:SENSITIVE attribute.
|
93
|
** 006 CA 20160203 Added hash management operations.
|
94
|
+** SBI 20160220 Added MSG_PARTIAL, MSG_FILE_UPLOAD
|
95
|
*/
|
96
|
|
97
|
package com.goldencode.p2j.ui.client.driver.web;
|
98
|
@@ -183,4 +184,10 @@
|
99
|
|
100
|
/** Inform the javascript side to remove the list of expired hashes. */
|
101
|
public static final byte MSG_REMOVE_EXPIRED_HASH = (byte) 0xA0;
|
102
|
+
|
103
|
+ /** Wraps the large message from the client to the sequence of this partial type messages. */
|
104
|
+ public static final byte MSG_PARTIAL = (byte) 0xFE;
|
105
|
+
|
106
|
+ /** File upload message. */
|
107
|
+ public static final byte MSG_FILE_UPLOAD = (byte) 0xFD;
|
108
|
}
|
109
|
|
110
|
=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/WebClientProtocol.java'
|
111
|
--- src/com/goldencode/p2j/ui/client/driver/web/WebClientProtocol.java 2016-02-03 11:21:56 +0000
|
112
|
+++ src/com/goldencode/p2j/ui/client/driver/web/WebClientProtocol.java 2016-02-20 16:50:14 +0000
|
113
|
@@ -19,17 +19,23 @@
|
114
|
** message result.
|
115
|
** 005 CA 20160203 Fixed deadlock for receivedMessages - it must lock on the "lock" field, as
|
116
|
** this object is used for all sock operations (including key reading).
|
117
|
+** SBI 20160220 Added MSG_PARTIAL and MSG_FILE_UPLOAD.
|
118
|
*/
|
119
|
|
120
|
package com.goldencode.p2j.ui.client.driver.web;
|
121
|
|
122
|
+import java.io.*;
|
123
|
import java.nio.*;
|
124
|
+import java.nio.channels.*;
|
125
|
+import java.nio.file.*;
|
126
|
+import java.nio.file.attribute.*;
|
127
|
import java.util.*;
|
128
|
import java.util.concurrent.*;
|
129
|
|
130
|
import org.eclipse.jetty.websocket.api.*;
|
131
|
import org.eclipse.jetty.websocket.api.annotations.*;
|
132
|
|
133
|
+
|
134
|
/**
|
135
|
* Implements the WebSockets protocol to drive communications with a JavaScript web client.
|
136
|
* <p>
|
137
|
@@ -144,7 +150,7 @@
|
138
|
*
|
139
|
*/
|
140
|
@SuppressWarnings("serial")
|
141
|
-@WebSocket(maxIdleTime = 900000, maxTextMessageSize = 4096, maxBinaryMessageSize = 32768)
|
142
|
+@WebSocket
|
143
|
public class WebClientProtocol
|
144
|
implements WebClientMessageTypes
|
145
|
{
|
146
|
@@ -174,7 +180,48 @@
|
147
|
* "synchronous" approach must call {@link #waitForResult} for the expected operation.
|
148
|
*/
|
149
|
private Map<Integer, Object> receivedMessages = new HashMap<>();
|
150
|
-
|
151
|
+
|
152
|
+ /** Partial messages are mapped to open file channels. */
|
153
|
+ private Map<Integer, FileChannel> partialMessages = new HashMap<>();
|
154
|
+
|
155
|
+ /** The directory to save partial messages to the corresponding temporary file */
|
156
|
+ private Path tmpDir;
|
157
|
+
|
158
|
+ /** The options used to open file channels for created temporary files */
|
159
|
+ private static final StandardOpenOption[] TMP_FILE_OPTIONS
|
160
|
+ = new StandardOpenOption[]
|
161
|
+ {
|
162
|
+ StandardOpenOption.READ,
|
163
|
+ StandardOpenOption.WRITE,
|
164
|
+ StandardOpenOption.DELETE_ON_CLOSE
|
165
|
+ };
|
166
|
+
|
167
|
+ /** The file permissions to create a new temporary file */
|
168
|
+ private static final Set<PosixFilePermission> NEW_TMP_FILE_PERMISSIONS;
|
169
|
+
|
170
|
+ static
|
171
|
+ {
|
172
|
+ PosixFilePermission[] permissions
|
173
|
+ = new PosixFilePermission[]
|
174
|
+ {
|
175
|
+ PosixFilePermission.OWNER_READ,
|
176
|
+ PosixFilePermission.OWNER_WRITE
|
177
|
+ };
|
178
|
+ NEW_TMP_FILE_PERMISSIONS = new HashSet<PosixFilePermission>(Arrays.asList(permissions));
|
179
|
+ }
|
180
|
+
|
181
|
+ /** The new created temporary file name should start from this string */
|
182
|
+ private static final String TMP_FILE_PREFIX = "msg";
|
183
|
+
|
184
|
+ /** The new created temporary file extension */
|
185
|
+ private static final String TMP_FILE_EXT = ".tmp";
|
186
|
+
|
187
|
+ /**
|
188
|
+ * Executes tasks to collect partial messages having the same id number to a one large
|
189
|
+ * binary message.
|
190
|
+ */
|
191
|
+ private final ExecutorService asynchIOExecutor = Executors.newSingleThreadExecutor();
|
192
|
+
|
193
|
/** Callbacks for delegated processing. */
|
194
|
protected ClientProtocolHooks callbacks = null;
|
195
|
|
196
|
@@ -207,7 +254,14 @@
|
197
|
this.callbacks = callbacks;
|
198
|
this.timeout = timeout;
|
199
|
this.wdtimeout = wdtimeout;
|
200
|
-
|
201
|
+ try
|
202
|
+ {
|
203
|
+ this.tmpDir = Files.createTempDirectory(null);
|
204
|
+ }
|
205
|
+ catch (IOException e)
|
206
|
+ {
|
207
|
+ e.printStackTrace();
|
208
|
+ }
|
209
|
startWatchdog(wdtimeout);
|
210
|
}
|
211
|
|
212
|
@@ -331,6 +385,98 @@
|
213
|
paste(message, offset, length);
|
214
|
handled = true;
|
215
|
}
|
216
|
+ else if (length > 11 && message[offset] == MSG_PARTIAL)
|
217
|
+ {
|
218
|
+ // [MSG_PARTIAL_TYPE][MSG_ID][PARTIAL_STATUS][PAYLOAD_LENGTH][PAYLOAD_DATA]
|
219
|
+ // 1 + 4 + 1 + 4 + length(payload data) > 10
|
220
|
+ final int msgId = readMessageInt32(message, offset + 1);
|
221
|
+ // PARTIAL_STATUS is 1 byte that equals 0 if it is the last message with MSG_ID or
|
222
|
+ // 1 if a next message with the same MSG_ID should follow this one.
|
223
|
+ final boolean isLast = message[offset + 5] == 0x0;
|
224
|
+ final int payloadLength = readMessageInt32(message, offset + 6);
|
225
|
+ final ByteBuffer payloadData = ByteBuffer.wrap(message, offset + 10, payloadLength);
|
226
|
+ FileChannel channel = partialMessages.get(msgId);
|
227
|
+ if (channel == null)
|
228
|
+ {
|
229
|
+ try
|
230
|
+ {
|
231
|
+
|
232
|
+ Path channelPath = Files.createTempFile(tmpDir, TMP_FILE_PREFIX, TMP_FILE_EXT,
|
233
|
+ PosixFilePermissions.asFileAttribute(NEW_TMP_FILE_PERMISSIONS));
|
234
|
+ channel = FileChannel.open(channelPath, TMP_FILE_OPTIONS);
|
235
|
+ partialMessages.put(msgId, channel);
|
236
|
+ }
|
237
|
+ catch (IOException e)
|
238
|
+ {
|
239
|
+ // TODO how to log exceptions
|
240
|
+ // e.printStackTrace();
|
241
|
+ }
|
242
|
+ }
|
243
|
+
|
244
|
+ if (channel != null && channel.isOpen())
|
245
|
+ {
|
246
|
+ asynchIOExecutor.submit(
|
247
|
+ /**
|
248
|
+ * The task that appends a new partial message to the already received
|
249
|
+ * messages having the same id number (or belonging to the same packet
|
250
|
+ * of messages).
|
251
|
+ */
|
252
|
+ new Runnable()
|
253
|
+ {
|
254
|
+ @Override
|
255
|
+ public void run()
|
256
|
+ {
|
257
|
+
|
258
|
+ try
|
259
|
+ {
|
260
|
+ // Find a channel by id
|
261
|
+ FileChannel channel = partialMessages.get(msgId);
|
262
|
+ // Write a payload data
|
263
|
+ channel.write(payloadData);
|
264
|
+ if (isLast)
|
265
|
+ {
|
266
|
+ // if message is the last message in this messages packet
|
267
|
+ // then read all gathered payload data and deliver it
|
268
|
+ // to the messages processor
|
269
|
+
|
270
|
+ int size = (int) channel.size();
|
271
|
+ ByteBuffer dst = ByteBuffer.allocate(size);
|
272
|
+ final int readedBytes = channel.read(dst, 0);
|
273
|
+ dst.flip();
|
274
|
+
|
275
|
+ // close channel to dispose used resources
|
276
|
+ channel.close();
|
277
|
+ partialMessages.remove(msgId);
|
278
|
+
|
279
|
+ if (readedBytes == size)
|
280
|
+ {
|
281
|
+ // deliver the large message to its processor
|
282
|
+ webWorker.post(new Runnable()
|
283
|
+ {
|
284
|
+ @Override
|
285
|
+ public void run()
|
286
|
+ {
|
287
|
+ processBinaryMessage(dst.array(), 0, readedBytes);
|
288
|
+ }
|
289
|
+ });
|
290
|
+ }
|
291
|
+ }
|
292
|
+ }
|
293
|
+ catch (IOException e)
|
294
|
+ {
|
295
|
+ // TODO how to log exceptions
|
296
|
+ // e.printStackTrace();
|
297
|
+ }
|
298
|
+ }
|
299
|
+ });
|
300
|
+ }
|
301
|
+ handled = true;
|
302
|
+ }
|
303
|
+ else if (length > 5 && message[offset] == MSG_FILE_UPLOAD)
|
304
|
+ {
|
305
|
+ // TODO : MSG_FILE_UPLOAD is wrapped by MSG_PARTIAL messages as payload data
|
306
|
+ handled = true;
|
307
|
+ }
|
308
|
|
309
|
return handled;
|
310
|
}
|
311
|
|
312
|
=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/WebPageHandler.java'
|
313
|
--- src/com/goldencode/p2j/ui/client/driver/web/WebPageHandler.java 2015-08-07 20:47:38 +0000
|
314
|
+++ src/com/goldencode/p2j/ui/client/driver/web/WebPageHandler.java 2016-02-20 17:05:56 +0000
|
315
|
@@ -12,6 +12,8 @@
|
316
|
** 001 GES 20150312 Created initial version by moving code from the ChuiWebPageHandler and making
|
317
|
** it more generic (to handle GUI too).
|
318
|
** 002 GES 20150717 Moved clipboard processing to ChUI-specific location.
|
319
|
+** 003 SBI 20160220 Added maxBinaryMessage parameter to the template file in order to deliver
|
320
|
+** its value to the JS client.
|
321
|
*/
|
322
|
|
323
|
package com.goldencode.p2j.ui.client.driver.web;
|
324
|
@@ -145,10 +147,17 @@
|
325
|
|
326
|
if (text.contains("${referrer}"))
|
327
|
{
|
328
|
- String referrer = config.getString("web", "referrer", "url", null);
|
329
|
+ String referrer = config.getString("web", "referrer", "url", null);
|
330
|
text = text.replace("${referrer}", referrer);
|
331
|
}
|
332
|
|
333
|
+ if (text.contains("${maxBinaryMessage}"))
|
334
|
+ {
|
335
|
+ // configuration must provide the valid value of client:web:maxBinaryMessage
|
336
|
+ int maxBinaryMessage = config.getInt("client", "web", "maxBinaryMessage", 1024);
|
337
|
+ text = text.replace("${maxBinaryMessage}", String.valueOf(maxBinaryMessage));
|
338
|
+ }
|
339
|
+
|
340
|
return text;
|
341
|
}
|
342
|
|
343
|
|
344
|
=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/index.html'
|
345
|
--- src/com/goldencode/p2j/ui/client/driver/web/index.html 2015-12-17 20:00:50 +0000
|
346
|
+++ src/com/goldencode/p2j/ui/client/driver/web/index.html 2016-02-19 22:07:40 +0000
|
347
|
@@ -38,7 +38,7 @@
|
348
|
'font' : {'name' : '${font.name}', 'size' : ${font.size}, 'color' : {'f' : '${font.color}', 'b' : '${font.background}'}},
|
349
|
'cursor' : {'type' : 'solid', 'visible' : true, 'blinking' : false},
|
350
|
'sound' : {'id' : 'beep', 'enabled' : true},
|
351
|
- 'socket' : {'url' : 'wss://' + window.location.host + '${context}/ajax'},
|
352
|
+ 'socket' : {'url' : 'wss://' + window.location.host + '${context}/ajax', 'maxBinaryMessage' : ${maxBinaryMessage}},
|
353
|
'page' : 'index.html',
|
354
|
'clipboard' : {'enabled' : ${clipboard.enabled}, 'id' : 'clipboard', 'stroke' : true, 'input' : 'copy'},
|
355
|
'taskbar' : {'enabled' : ${taskbar.enabled}},
|
356
|
|
357
|
=== modified file 'src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js'
|
358
|
--- src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js 2016-02-16 20:45:37 +0000
|
359
|
+++ src/com/goldencode/p2j/ui/client/driver/web/res/p2j.socket.js 2016-02-20 17:36:01 +0000
|
360
|
@@ -41,7 +41,8 @@
|
361
|
** SBI 20160107 Supported new message with 0x9F id to test if the target font family is
|
362
|
** available for the browser.
|
363
|
** CA 20160629 Added a drawing cache (and cache management, when the hash was expired by the
|
364
|
-* client-side).
|
365
|
+** client-side).
|
366
|
+** SBI 20160202 Implemented MSG_PARTIAL.
|
367
|
*/
|
368
|
|
369
|
"use strict";
|
370
|
@@ -66,6 +67,116 @@
|
371
|
/** The count of the drawing operations. */
|
372
|
var drawNo = 0;
|
373
|
|
374
|
+ /** The maximal size for binary messages that can be accepted by the websocket server. */
|
375
|
+ var maxBinaryMessage;
|
376
|
+
|
377
|
+ /**
|
378
|
+ * The next unique message id.
|
379
|
+ */
|
380
|
+ var nextMsgId = 0;
|
381
|
+
|
382
|
+ /** The fast timer object */
|
383
|
+ var fastTimer = new FastTimer("https://" + window.location.host);
|
384
|
+
|
385
|
+ /**
|
386
|
+ * The fast timer to execute tasks in the UI thread.
|
387
|
+ *
|
388
|
+ * @param {String} origin
|
389
|
+ * The message origin is an URL that defines what messages are handled by this timer.
|
390
|
+ */
|
391
|
+ function FastTimer(origin)
|
392
|
+ {
|
393
|
+ var notification = "fast-timer-notification";
|
394
|
+ var targetOrigin = origin;
|
395
|
+
|
396
|
+ /**
|
397
|
+ * The tasks queue to be performed by the fast timer. A task must have "execute" function
|
398
|
+ * as its public member.
|
399
|
+ */
|
400
|
+ var tasksQueue = [];
|
401
|
+
|
402
|
+ /**
|
403
|
+ * Schedule a task to be executed by the fast timer.
|
404
|
+ *
|
405
|
+ * @param {Task} task
|
406
|
+ */
|
407
|
+ function scheduleTask(task)
|
408
|
+ {
|
409
|
+ tasksQueue.push(task);
|
410
|
+ window.postMessage(notification, targetOrigin);
|
411
|
+ }
|
412
|
+
|
413
|
+ this.scheduleTask = scheduleTask;
|
414
|
+
|
415
|
+ /**
|
416
|
+ * Executes the next task from the tasks queue as soon as a notification message is caught.
|
417
|
+ *
|
418
|
+ * @param {Event} event
|
419
|
+ * A notification event that is handled by this fast timer
|
420
|
+ */
|
421
|
+ function executeTask(event)
|
422
|
+ {
|
423
|
+ if (event.source == window && event.data == notification)
|
424
|
+ {
|
425
|
+ event.stopPropagation();
|
426
|
+ if (tasksQueue.length > 0)
|
427
|
+ {
|
428
|
+ var task = tasksQueue.shift();
|
429
|
+ task.execute();
|
430
|
+ }
|
431
|
+ }
|
432
|
+ }
|
433
|
+
|
434
|
+ window.addEventListener("message", executeTask, true);
|
435
|
+ };
|
436
|
+
|
437
|
+ /**
|
438
|
+ * Sends a large message via partial messages as payload data nested by MSG_PARTIAL messages.
|
439
|
+ *
|
440
|
+ * @param {Uint8Array} msg
|
441
|
+ * The large source message that should be send by packets.
|
442
|
+ */
|
443
|
+ function sendMessageByPackets(msg)
|
444
|
+ {
|
445
|
+ var task = {position : 0, capacity : msg.byteLength, msg : msg};
|
446
|
+ task.msgId = nextMsgId;
|
447
|
+ nextMsgId++;
|
448
|
+ task.execute = function ()
|
449
|
+ {
|
450
|
+ var position = task.position;
|
451
|
+ var capacity = task.capacity;
|
452
|
+ var remaining = capacity - position;
|
453
|
+
|
454
|
+ var payloadLength;
|
455
|
+ var isLast;
|
456
|
+ if (remaining >= maxBinaryMessage - 10)
|
457
|
+ {
|
458
|
+ payloadLength = maxBinaryMessage - 10;
|
459
|
+ isLast = false;
|
460
|
+ }
|
461
|
+ else
|
462
|
+ {
|
463
|
+ payloadLength = remaining;
|
464
|
+ isLast = true;
|
465
|
+ }
|
466
|
+ var limit = position + payloadLength;
|
467
|
+ // send partial message
|
468
|
+ me.sendPartialMessage(task.msg, position, limit, payloadLength, task.msgId, isLast)
|
469
|
+
|
470
|
+ position = limit;
|
471
|
+ remaining = capacity - position;
|
472
|
+ task.position = position;
|
473
|
+ task.remaining = remaining;
|
474
|
+ // if there are bytes to send, then schedule new task
|
475
|
+ if (remaining > 0)
|
476
|
+ {
|
477
|
+ fastTimer.scheduleTask(task);
|
478
|
+ }
|
479
|
+ };
|
480
|
+
|
481
|
+ fastTimer.scheduleTask(task);
|
482
|
+ }
|
483
|
+
|
484
|
/**
|
485
|
* Send data.
|
486
|
*
|
487
|
@@ -75,7 +186,14 @@
|
488
|
{
|
489
|
if (connected)
|
490
|
{
|
491
|
- ws.send(data);
|
492
|
+ if (data.byteLength <= maxBinaryMessage)
|
493
|
+ {
|
494
|
+ ws.send(data);
|
495
|
+ }
|
496
|
+ else
|
497
|
+ {
|
498
|
+ sendMessageByPackets(data);
|
499
|
+ }
|
500
|
}
|
501
|
else
|
502
|
{
|
503
|
@@ -98,6 +216,38 @@
|
504
|
};
|
505
|
|
506
|
/**
|
507
|
+ * Send a partial message that wraps the payload data.
|
508
|
+ *
|
509
|
+ * @param {Uint8Array} data
|
510
|
+ * The large source message that should be send by packets.
|
511
|
+ * @param {Number} position
|
512
|
+ * It points to the first byte of the payload data.
|
513
|
+ * @param {Number} limit
|
514
|
+ * The upper barrier index of the payload data. T
|
515
|
+ * @param {Number} payloadLength
|
516
|
+ * The number of bytes to send starting from the given position.
|
517
|
+ * @param {Number} msgId
|
518
|
+ * The message id that identifies the large source message.
|
519
|
+ * @param {Boolean} isLast
|
520
|
+ * Indicates the last message in the packets to send.
|
521
|
+ */
|
522
|
+ me.sendPartialMessage = function(data, position, limit, payloadLength, msgId, isLast)
|
523
|
+ {
|
524
|
+ var msg = new Uint8Array(payloadLength + 10);
|
525
|
+ msg[0] = 0xFE;
|
526
|
+ me.writeInt32BinaryMessage(msg, 1, msgId);
|
527
|
+ msg[5] = isLast ? 0 : 1;
|
528
|
+ me.writeInt32BinaryMessage(msg, 6, payloadLength);
|
529
|
+ var i, j;
|
530
|
+ for(i = position, j = 10; i < limit; i++, j++)
|
531
|
+ {
|
532
|
+ msg[j] = data[i];
|
533
|
+ }
|
534
|
+
|
535
|
+ me.send(msg);
|
536
|
+ };
|
537
|
+
|
538
|
+ /**
|
539
|
* Sends the window active event to the server.
|
540
|
*
|
541
|
* @param {Number} wid
|
542
|
@@ -455,6 +605,8 @@
|
543
|
{
|
544
|
referrer = cfg.referrer;
|
545
|
|
546
|
+ maxBinaryMessage = cfg.socket.maxBinaryMessage
|
547
|
+
|
548
|
if ('WebSocket' in window)
|
549
|
{
|
550
|
ws = new WebSocket(cfg.socket.url);
|
551
|
|
552
|
=== modified file 'src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java'
|
553
|
--- src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java 2016-02-16 20:45:37 +0000
|
554
|
+++ src/com/goldencode/p2j/ui/client/gui/driver/web/GuiWebSocket.java 2016-02-19 20:25:02 +0000
|
555
|
@@ -63,7 +63,7 @@
|
556
|
* is running during session establishment with the P2J server using logging no messages are
|
557
|
* written into the log and the application is blocked.
|
558
|
*/
|
559
|
-@WebSocket(maxIdleTime = 900000, maxTextMessageSize = 4096, maxBinaryMessageSize = 32768)
|
560
|
+@WebSocket
|
561
|
public class GuiWebSocket
|
562
|
extends WebClientProtocol
|
563
|
{
|
564
|
|
565
|
=== modified file 'src/com/goldencode/p2j/web/GenericWebServer.java'
|
566
|
--- src/com/goldencode/p2j/web/GenericWebServer.java 2015-05-18 20:48:28 +0000
|
567
|
+++ src/com/goldencode/p2j/web/GenericWebServer.java 2016-02-20 18:09:39 +0000
|
568
|
@@ -12,6 +12,7 @@
|
569
|
** 001 MAG 20131105 First version based on jetty 9.1
|
570
|
** 002 MAG 20131129 Import server KeyStore.
|
571
|
** 003 AB 20150515 Removed configWsContext() and now directly use the handler collection.
|
572
|
+** 004 SBI 20160220 Changed to set the websocket parameters from the server provided configuration.
|
573
|
*/
|
574
|
|
575
|
package com.goldencode.p2j.web;
|
576
|
@@ -232,7 +233,7 @@
|
577
|
*/
|
578
|
public void addWebSocketHandler(String target, Class<?> webSocket)
|
579
|
{
|
580
|
- Handler wsHandler = new PojoWebSocketHandler(target, webSocket);
|
581
|
+ Handler wsHandler = new PojoWebSocketHandler(target, webSocket, new WebSocketConfig(config));
|
582
|
handlerCollection.addHandler(wsHandler);
|
583
|
}
|
584
|
|
585
|
@@ -246,7 +247,7 @@
|
586
|
*/
|
587
|
public void addWebSocketHandler(String target, WebSocketCreator creator)
|
588
|
{
|
589
|
- Handler wsHandler = new PojoWebSocketHandler(target, creator);
|
590
|
+ Handler wsHandler = new PojoWebSocketHandler(target, creator, new WebSocketConfig(config));
|
591
|
handlerCollection.addHandler(wsHandler);
|
592
|
}
|
593
|
|
594
|
@@ -439,4 +440,5 @@
|
595
|
{
|
596
|
this.serverKeyStore = keyStore;
|
597
|
}
|
598
|
+
|
599
|
}
|
600
|
|
601
|
=== modified file 'src/com/goldencode/p2j/web/PojoWebSocketHandler.java'
|
602
|
--- src/com/goldencode/p2j/web/PojoWebSocketHandler.java 2013-11-16 08:00:52 +0000
|
603
|
+++ src/com/goldencode/p2j/web/PojoWebSocketHandler.java 2016-02-20 17:55:05 +0000
|
604
|
@@ -10,6 +10,7 @@
|
605
|
**
|
606
|
** -#- -I- --Date-- ----------------------Description--------------------------
|
607
|
** 001 MAG 20131105 First version based on jetty 9.1
|
608
|
+** 002 SBI 20160220 Added websocket configuration parameters.
|
609
|
*/
|
610
|
|
611
|
package com.goldencode.p2j.web;
|
612
|
@@ -23,6 +24,7 @@
|
613
|
import org.eclipse.jetty.websocket.server.*;
|
614
|
import org.eclipse.jetty.websocket.servlet.*;
|
615
|
|
616
|
+
|
617
|
/**
|
618
|
* This class is used to register and handle WebSockets POJO objects.
|
619
|
* <p>
|
620
|
@@ -44,7 +46,10 @@
|
621
|
|
622
|
/** WebSocketCreator used to create WebSockets by hand */
|
623
|
private WebSocketCreator creator;
|
624
|
-
|
625
|
+
|
626
|
+ /** Websocket configuration */
|
627
|
+ private WebSocketConfig config;
|
628
|
+
|
629
|
/**
|
630
|
* Constructor.
|
631
|
*
|
632
|
@@ -55,11 +60,14 @@
|
633
|
* @param creator
|
634
|
* The WebSocketCreator instance used tom create
|
635
|
* WebSockets by hand.
|
636
|
+ * @param config
|
637
|
+ * The websocket configuration parameters.
|
638
|
*/
|
639
|
- public PojoWebSocketHandler(String webSocketTarget, WebSocketCreator creator)
|
640
|
+ public PojoWebSocketHandler(String webSocketTarget, WebSocketCreator creator, WebSocketConfig config)
|
641
|
{
|
642
|
this.webSocketTarget = webSocketTarget;
|
643
|
this.creator = creator;
|
644
|
+ this.config = config;
|
645
|
}
|
646
|
|
647
|
/**
|
648
|
@@ -71,11 +79,14 @@
|
649
|
* of handlers for the same server context.
|
650
|
* @param webSocketPojo
|
651
|
* The WebSocket POJO class.
|
652
|
+ * @param config
|
653
|
+ * The websocket configuration parameters.
|
654
|
*/
|
655
|
- public PojoWebSocketHandler(String webSocketTarget, Class<?> webSocketPojo)
|
656
|
+ public PojoWebSocketHandler(String webSocketTarget, Class<?> webSocketPojo, WebSocketConfig config)
|
657
|
{
|
658
|
this.webSocketTarget = webSocketTarget;
|
659
|
this.webSocketPojo = webSocketPojo;
|
660
|
+ this.config = config;
|
661
|
}
|
662
|
|
663
|
/**
|
664
|
@@ -90,6 +101,14 @@
|
665
|
@Override
|
666
|
public void configure(WebSocketServletFactory wsServletFactory)
|
667
|
{
|
668
|
+ if (config != null)
|
669
|
+ {
|
670
|
+ wsServletFactory.getPolicy().setIdleTimeout(config.getMaxIdleTime());
|
671
|
+ wsServletFactory.getPolicy().setMaxBinaryMessageSize(config.getMaxBinaryMessage());
|
672
|
+ wsServletFactory.getPolicy().setMaxTextMessageBufferSize(config.getMaxTextMessage());
|
673
|
+ // used only by streams
|
674
|
+ wsServletFactory.getPolicy().setMaxBinaryMessageBufferSize(config.getMaxBinaryMessage());
|
675
|
+ }
|
676
|
if (creator == null)
|
677
|
{
|
678
|
wsServletFactory.register(webSocketPojo);
|
679
|
|
680
|
=== added file 'src/com/goldencode/p2j/web/WebSocketConfig.java'
|
681
|
--- src/com/goldencode/p2j/web/WebSocketConfig.java 1970-01-01 00:00:00 +0000
|
682
|
+++ src/com/goldencode/p2j/web/WebSocketConfig.java 2016-02-20 18:05:51 +0000
|
683
|
@@ -0,0 +1,81 @@
|
684
|
+/*
|
685
|
+** Module : WebSocketConfig.java
|
686
|
+** Abstract : Wraps Websocket configuration parameters.
|
687
|
+**
|
688
|
+** Copyright (c) 2016, Golden Code Development Corporation.
|
689
|
+** ALL RIGHTS RESERVED. Use is subject to license terms.
|
690
|
+**
|
691
|
+** Golden Code Development Corporation
|
692
|
+** CONFIDENTIAL
|
693
|
+**
|
694
|
+** -#- -I- --Date-- ------------------------------Description----------------------------------
|
695
|
+** 001 SBI 20160220 Added to set the websocket parameters from the server provided configuration.
|
696
|
+*/
|
697
|
+package com.goldencode.p2j.web;
|
698
|
+
|
699
|
+import com.goldencode.p2j.cfg.BootstrapConfig;
|
700
|
+
|
701
|
+/**
|
702
|
+ * Wraps Websocket configuration parameters.
|
703
|
+ */
|
704
|
+public class WebSocketConfig
|
705
|
+{
|
706
|
+ /**
|
707
|
+ * Maximal size of accepted text messages
|
708
|
+ */
|
709
|
+ private final int maxTextMessage;
|
710
|
+
|
711
|
+ /**
|
712
|
+ * Maximal idle time
|
713
|
+ */
|
714
|
+ private final int maxIdleTime;
|
715
|
+
|
716
|
+ /**
|
717
|
+ * Maximal size of accepted binary messages
|
718
|
+ */
|
719
|
+ private final int maxBinaryMessage;
|
720
|
+
|
721
|
+ /**
|
722
|
+ * Create an immutable instance of the websocket configuration parameters.
|
723
|
+ *
|
724
|
+ * @param config
|
725
|
+ * The server provided bootstrap configuration.
|
726
|
+ */
|
727
|
+ public WebSocketConfig(BootstrapConfig config)
|
728
|
+ {
|
729
|
+ this.maxTextMessage = config.getInt("client", "web", "maxTextMessage", -1);
|
730
|
+ this.maxIdleTime = config.getInt("client", "web", "maxIdleTime", -1);
|
731
|
+ this.maxBinaryMessage = config.getInt("client", "web", "maxBinaryMessage", -1);
|
732
|
+ }
|
733
|
+
|
734
|
+ /**
|
735
|
+ * Return the maximal size of accepted text messages.
|
736
|
+ *
|
737
|
+ * @return Maximal size of accepted text messages.
|
738
|
+ */
|
739
|
+ public int getMaxTextMessage()
|
740
|
+ {
|
741
|
+ return this.maxTextMessage;
|
742
|
+ }
|
743
|
+
|
744
|
+ /**
|
745
|
+ * Returns the maximal idle time.
|
746
|
+ *
|
747
|
+ * @return Maximal idle time
|
748
|
+ */
|
749
|
+ public int getMaxIdleTime()
|
750
|
+ {
|
751
|
+ return this.maxIdleTime;
|
752
|
+ }
|
753
|
+
|
754
|
+ /**
|
755
|
+ * Returns the maximal size of accepted binary messages.
|
756
|
+ *
|
757
|
+ * @return Maximal size of accepted binary messages.
|
758
|
+ */
|
759
|
+ public int getMaxBinaryMessage()
|
760
|
+ {
|
761
|
+ return this.maxBinaryMessage;
|
762
|
+ }
|
763
|
+
|
764
|
+}
|
765
|
|