Skip to content
This repository was archived by the owner on Feb 20, 2022. It is now read-only.

Commit f63823b

Browse files
committed
Bugfix: block sending and handle receiving in thread without extra await. (Unity will not disconnect anymore when receiving data > 4096 byte and will not freeze when to many send-commands are send after another. Added Benchmark capabilities)
1 parent 59058be commit f63823b

18 files changed

+1801
-171
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { Meteor } from 'meteor/meteor';
2+
import { Mongo } from 'meteor/mongo';
3+
import { check } from 'meteor/check';
4+
import { Match } from 'meteor/check';
5+
6+
let fs = Npm.require('fs');
7+
8+
export const Benchmark = new Mongo.Collection('benchmark');
9+
// amount of entries we use to test
10+
const NUM_ENTRIES = 100;
11+
12+
// cache image data in local variable
13+
let IMAGE = null;
14+
15+
let getImage = function() {
16+
IMAGE = IMAGE || Assets.getText('test-pattern.txt');
17+
return IMAGE;
18+
}
19+
20+
function genTestData() {
21+
return {
22+
"arr": [1, 2, 3],
23+
"str": "some string",
24+
"float": 1.23456789,
25+
"int": 123456789,
26+
"null": null,
27+
"date": new Date(),
28+
// png image as base-64
29+
"image": getImage()
30+
}
31+
}
32+
33+
function getBenchmarkData() {
34+
let qry = {}
35+
let bench = Benchmark.find(qry, {limit: NUM_ENTRIES});
36+
if (bench.count() >= NUM_ENTRIES) {
37+
return bench;
38+
}
39+
for (let i = bench.count(); i < 100; i++) {
40+
Benchmark.insert({
41+
"nr": i,
42+
"values": genTestData()
43+
})
44+
}
45+
46+
return Benchmark.find(qry, {limit: NUM_ENTRIES});
47+
}
48+
49+
Meteor.methods({
50+
'benchmark.recreate'() {
51+
// remove everything!
52+
Benchmark.remove({});
53+
getBenchmarkData();
54+
return true;
55+
},
56+
'benchmark.count'(i) {
57+
check(i, Match.Integer);
58+
return i+1;
59+
}
60+
});
61+
62+
if (Meteor.isServer) {
63+
Meteor.publish('benchmark', function() {
64+
return getBenchmarkData();
65+
});
66+
}
82.1 KB
Loading

example-server/private/test-pattern.txt

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

example-server/server/main.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
*/
2424

2525
import '../imports/api/friends.js';
26+
import '../imports/api/benchmark.js';
2627

2728
import { Friends } from '../imports/api/friends.js';
29+
import { Benchmark } from '../imports/api/benchmark.js';
2830

2931
Meteor.startup(() => {
3032
});

unity-project/Assets/Moulin/DDP/account/DdpAccount.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,37 +110,37 @@ private void HandleLogoutResult(MethodCall logoutCall) {
110110
}
111111
}
112112

113-
public async Task CreateUserAndLogin(string username, string password) {
113+
public void CreateUserAndLogin(string username, string password) {
114114
JSONObject loginPasswordObj = JSONObject.Create();
115115
loginPasswordObj.AddField("username", username);
116116
loginPasswordObj.AddField("password", GetPasswordObj(password));
117117

118-
MethodCall loginCall = await connection.CallAsync("createUser", loginPasswordObj);
118+
MethodCall loginCall = connection.Call("createUser", loginPasswordObj);
119119
loginCall.OnResult += HandleLoginResult;
120120
}
121121

122-
public async Task Login(string username, string password) {
122+
public void Login(string username, string password) {
123123
JSONObject userObj = JSONObject.Create();
124124
userObj.AddField("username", username);
125125

126126
JSONObject loginPasswordObj = JSONObject.Create();
127127
loginPasswordObj.AddField("user", userObj);
128128
loginPasswordObj.AddField("password", GetPasswordObj(password));
129129

130-
MethodCall loginCall = await connection.CallAsync("login", loginPasswordObj);
130+
MethodCall loginCall = connection.Call("login", loginPasswordObj);
131131
loginCall.OnResult += HandleLoginResult;
132132
}
133133

134-
public async Task ResumeSession(string token) {
134+
public void ResumeSession(string token) {
135135
JSONObject tokenObj = JSONObject.Create();
136136
tokenObj.AddField("resume", token);
137137

138-
MethodCall loginCall = await connection.CallAsync("login", tokenObj);
138+
MethodCall loginCall = connection.Call("login", tokenObj);
139139
loginCall.OnResult += HandleLoginResult;
140140
}
141141

142-
public async Task Logout() {
143-
MethodCall logoutCall = await connection.CallAsync("logout");
142+
public void Logout() {
143+
MethodCall logoutCall = connection.Call("logout");
144144
HandleLogoutResult(logoutCall);
145145
}
146146

unity-project/Assets/Moulin/DDP/ddp/DdpConnection.cs

Lines changed: 23 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,7 @@ public enum ConnectionState {
106106
private WebSocketConnection ws;
107107
private ConnectionState ddpConnectionState;
108108
private string sessionId;
109-
110-
private object subscriptionsLock = new object();
111-
private object methodCallsLock = new object();
112-
109+
113110
private Dictionary<string, Subscription> subscriptions = new Dictionary<string, Subscription>();
114111
private Dictionary<string, MethodCall> methodCalls = new Dictionary<string, MethodCall>();
115112

@@ -158,17 +155,13 @@ public void OnWebSocketOpen()
158155
{
159156
OnDebugMessage?.Invoke("Websocket open");
160157
Send(GetConnectMessage());
161-
lock (subscriptionsLock) {
162-
foreach (Subscription subscription in subscriptions.Values)
163-
{
164-
Send(GetSubscriptionMessage(subscription));
165-
}
158+
foreach (Subscription subscription in subscriptions.Values)
159+
{
160+
Send(GetSubscriptionMessage(subscription));
166161
}
167-
lock (methodCallsLock) {
168-
foreach (MethodCall methodCall in methodCalls.Values)
169-
{
170-
Send(GetMethodCallMessage(methodCall));
171-
}
162+
foreach (MethodCall methodCall in methodCalls.Values)
163+
{
164+
Send(GetMethodCallMessage(methodCall));
172165
}
173166
}
174167

@@ -184,14 +177,8 @@ private void OnWebSocketClose(bool wasClean) {
184177
if (wasClean) {
185178
ddpConnectionState = ConnectionState.CLOSED;
186179
sessionId = null;
187-
lock (subscriptionsLock)
188-
{
189-
subscriptions.Clear();
190-
}
191-
lock (methodCallsLock)
192-
{
193-
methodCalls.Clear();
194-
}
180+
subscriptions.Clear();
181+
methodCalls.Clear();
195182
OnDisconnected?.Invoke(this);
196183
} else {
197184
ddpConnectionState = ConnectionState.DISCONNECTED;
@@ -243,10 +230,7 @@ private void HandleMessage(JSONObject message) {
243230

244231
case MessageType.NOSUB: {
245232
string subscriptionId = message[Field.ID].str;
246-
lock (subscriptionsLock)
247-
{
248-
subscriptions.Remove(subscriptionId);
249-
}
233+
subscriptions.Remove(subscriptionId);
250234

251235
if (message.HasField(Field.ERROR)) {
252236
OnError?.Invoke(GetError(message[Field.ERROR]));
@@ -283,10 +267,7 @@ private void HandleMessage(JSONObject message) {
283267

284268
foreach (string subscriptionId in subscriptionIds) {
285269
Subscription subscription;
286-
lock (subscriptionsLock)
287-
{
288-
subscription = subscriptions[subscriptionId];
289-
}
270+
subscription = subscriptions[subscriptionId];
290271
if (subscription != null) {
291272
subscription.isReady = true;
292273
subscription.OnReady?.Invoke(subscription);
@@ -314,21 +295,14 @@ private void HandleMessage(JSONObject message) {
314295

315296
case MessageType.RESULT: {
316297
string methodCallId = message[Field.ID].str;
317-
MethodCall methodCall;
318-
lock (methodCallsLock)
319-
{
320-
methodCall = methodCalls[methodCallId];
321-
}
298+
MethodCall methodCall = methodCalls[methodCallId];
322299
if (methodCall != null) {
323300
if (message.HasField(Field.ERROR)) {
324301
methodCall.error = GetError(message[Field.ERROR]);
325302
}
326303
methodCall.result = message[Field.RESULT];
327304
if (methodCall.hasUpdated) {
328-
lock (methodCallsLock)
329-
{
330-
methodCalls.Remove(methodCallId);
331-
}
305+
methodCalls.Remove(methodCallId);
332306
}
333307
methodCall.hasResult = true;
334308
methodCall.OnResult?.Invoke(methodCall);
@@ -339,17 +313,10 @@ private void HandleMessage(JSONObject message) {
339313
case MessageType.UPDATED: {
340314
string[] methodCallIds = ToStringArray(message[Field.METHODS]);
341315
foreach (string methodCallId in methodCallIds) {
342-
MethodCall methodCall;
343-
lock (methodCallsLock)
344-
{
345-
methodCall = methodCalls[methodCallId];
346-
}
316+
MethodCall methodCall = methodCalls[methodCallId];
347317
if (methodCall != null) {
348318
if (methodCall.hasResult) {
349-
lock (methodCallsLock)
350-
{
351-
methodCalls.Remove(methodCallId);
352-
}
319+
methodCalls.Remove(methodCallId);
353320
}
354321
methodCall.hasUpdated = true;
355322
methodCall.OnUpdated?.Invoke(methodCall);
@@ -452,9 +419,9 @@ private string[] ToStringArray(JSONObject jo) {
452419
return result;
453420
}
454421

455-
private async Task SendAsync(string message) {
422+
private void Send(string message) {
456423
if (logMessages) OnDebugMessage?.Invoke("Send: " + message);
457-
await ws.Send(message);
424+
ws.Send(message);
458425
}
459426

460427
public ConnectionState GetConnectionState() {
@@ -494,69 +461,33 @@ void Dispose() {
494461
ws.Dispose();
495462
}
496463

497-
// send message without waiting for its result
498-
void Send(string message)
499-
{
500-
Task t = SendAsync(message);
501-
t.Wait();
502-
}
503-
504464
public Subscription Subscribe(string name, params JSONObject[] items)
505-
{
506-
Task<Subscription> sub = SubscribeAsync(name, items);
507-
// wait until message has been send
508-
sub.Wait();
509-
return sub.Result;
510-
}
511-
512-
public async Task<Subscription> SubscribeAsync(string name, params JSONObject[] items)
513465
{
514466
Subscription subscription = new Subscription()
515467
{
516468
id = "" + subscriptionId++,
517469
name = name,
518470
items = items
519471
};
520-
lock (subscriptions)
521-
{
522-
subscriptions[subscription.id] = subscription;
523-
}
524-
await SendAsync(GetSubscriptionMessage(subscription));
472+
subscriptions[subscription.id] = subscription;
473+
Send(GetSubscriptionMessage(subscription));
525474
return subscription;
526475
}
527476

528477
public void Unsubscribe(Subscription subscription) {
529478
Send(GetUnsubscriptionMessage(subscription));
530479
}
531480

532-
public async Task<MethodCall> CallAsync(string methodName, params JSONObject[] items)
533-
{
534-
MethodCall methodCall = new MethodCall()
535-
{
536-
id = "" + methodCallId++,
537-
methodName = methodName,
538-
items = items
539-
};
540-
lock (methodCallsLock)
541-
{
542-
methodCalls[methodCall.id] = methodCall;
543-
}
544-
await SendAsync(GetMethodCallMessage(methodCall));
545-
return methodCall;
546-
}
547-
548481
public MethodCall Call(string methodName, params JSONObject[] items) {
549482
MethodCall methodCall = new MethodCall() {
550483
id = "" + methodCallId++,
551484
methodName = methodName,
552485
items = items
553486
};
554-
lock (methodCallsLock)
555-
{
556-
methodCalls[methodCall.id] = methodCall;
557-
}
558-
Send(GetMethodCallMessage(methodCall));
559-
return methodCall;
487+
methodCalls[methodCall.id] = methodCall;
488+
Send(GetMethodCallMessage(methodCall));
489+
490+
return methodCall;
560491
}
561492

562493
void IDisposable.Dispose()

unity-project/Assets/Moulin/DDP/websocket/WebSocketConnection.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,15 @@ public virtual async Task ConnectAsync()
5454
throw new NotImplementedException();
5555
}
5656

57-
public virtual async Task Send(string message)
57+
public virtual async Task CloseAsync()
5858
{
5959
throw new NotImplementedException();
6060
}
61-
62-
public virtual async Task CloseAsync()
61+
#pragma warning restore 1998
62+
public virtual void Send(string message)
6363
{
6464
throw new NotImplementedException();
6565
}
66-
#pragma warning restore 1998
66+
6767
}
6868
}

0 commit comments

Comments
 (0)