-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
L2l #1
base: master
Are you sure you want to change the base?
L2l #1
Changes from 11 commits
54cdceb
53382b5
41ff294
ccbb70e
963906e
b784ddd
44c12b2
fed0fc4
9d730ce
098aa62
58f8ae4
7227b50
a7043bf
e6c8acc
f9b3382
ad87b88
4e34871
cf33cc0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import L2LClient from "lively.2lively/client.js"; | ||
import { string, num, promise, fun } from "lively.lang"; | ||
|
||
export class Channel { | ||
constructor(senderRecvrA, onReceivedMethodA, senderRecvrB, onReceivedMethodB){ | ||
if (!senderRecvrA) throw new Error("no sender / receiver a!"); | ||
if (!senderRecvrB) throw new Error("no sender / receiver b!"); | ||
if (typeof senderRecvrA[onReceivedMethodA] !== "function") throw new Error(`sender a has no receive method ${onReceivedMethodA}!`); | ||
if (typeof senderRecvrB[onReceivedMethodB] !== "function") throw new Error(`sender b has no receive method ${onReceivedMethodB}!`); | ||
this.senderRecvrA = senderRecvrA; | ||
this.senderRecvrA.l2lclient ? {} : this.senderRecvrA.l2lclient = Channel.makeL2LClient() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this structure? Why not simply an if instead of a tertiary with an emtpy object? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Corrected with ifs |
||
this.onReceivedMethodA = onReceivedMethodA; | ||
this.onReceivedMethodB = onReceivedMethodB; | ||
this.senderRecvrB = senderRecvrB; | ||
this.senderRecvrB.l2lclient ? {} : this.senderRecvrB.l2lclient = Channel.makeL2LClient() | ||
this.queueAtoB = []; | ||
this.queueBtoA = []; | ||
this.delayAtoB = 0; | ||
this.delayBtoA = 0; | ||
this.online = false; | ||
this.lifetime = 100; | ||
// this._watchdogProcess = null | ||
this.goOnline(); | ||
} | ||
|
||
static makeL2LClient(hostname,port, namespace,io){ | ||
var client = L2LClient.forceNew({}) | ||
return client | ||
} | ||
|
||
registerReceive(client,method){ | ||
var l2l = client.l2lclient; | ||
l2l.addService("lively.sync", (tracker, msg, ackFn, sender) => { | ||
method(msg.data) | ||
}); | ||
} | ||
|
||
async getSessions(senderA,senderB,ackFn){ | ||
var l2lA = senderA.l2lclient, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you define There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed |
||
l2lB = senderB.l2lclient | ||
var returnVal = 'incomplete'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed |
||
l2lB.sendTo(l2lB.trackerId,'listRoom',{roomName: l2lB.socketId.split('#')[1]},(a) => {ackFn(a)}) | ||
} | ||
toString() { | ||
return `<channel ${this.senderRecvrA}.${this.onReceivedMethodA} – ${this.senderRecvrB}.${this.onReceivedMethodB}>` | ||
} | ||
|
||
isOnline() { return this.online; } | ||
|
||
goOffline() { | ||
console.log(this) | ||
this.online = false; | ||
|
||
var l2lA = this.senderRecvrA.l2lclient, | ||
l2lB = this.senderRecvrB.l2lclient | ||
if(!l2lA){ console.log('l2lA Missing');return''} | ||
if(!l2lB){ console.log('l2lB Missing');return''} | ||
l2lA.sendTo(l2lA.trackerId,'leaveRoom',{roomName: l2lB.socketId.split('#')[1]}) | ||
|
||
if (this.senderRecvrA && this.senderRecvrA.l2lclient) { | ||
this.senderRecvrA.l2lclient.remove() | ||
console.log('senderRecvrA disconnected') | ||
|
||
} else { | ||
console.log('senderRecvrA not disconnected'); | ||
} | ||
|
||
if (this.senderRecvrB && this.senderRecvrB.l2lclient) { | ||
this.getSessions(this.senderRecvrA,this.senderRecvrB,(a)=> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use async/awai as much as possible. It makes code much more readable than callback style |
||
if(a.data.length <= 1){ | ||
l2lB.sendTo(l2lB.trackerId,'leaveRoom',{roomName: l2lB.socketId.split('#')[1]}) | ||
l2lB.remove(); | ||
} else { | ||
console.log('senderRecvrB not disconnected'); | ||
} | ||
}) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't the procedure for cleaning up l2lA and l2lB be the same? it seems strange that you have to query for getSessions to disconnect b? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's because I need to make sure it's the last thing in the room before it disconnects, since it's the master. |
||
|
||
} | ||
|
||
async goOnline() { | ||
var l2lA = this.senderRecvrA.l2lclient, | ||
l2lB = this.senderRecvrB.l2lclient | ||
await l2lA.whenRegistered(300) | ||
await l2lB.whenRegistered(300) | ||
|
||
this.registerReceive(this.senderRecvrA,this.senderRecvrA.receiveOpsFromMaster) | ||
this.registerReceive(this.senderRecvrB,this.senderRecvrB.receiveOpsFromClient) | ||
|
||
l2lA.sendTo(l2lA.trackerId,'joinRoom',{roomName: l2lB.socketId.split('#')[1]}) | ||
l2lB.sendTo(l2lB.trackerId,'joinRoom',{roomName: l2lB.socketId.split('#')[1]}) | ||
this.online = true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to wait for acknowledgment for joining the rooms to be sure we are really only? In other words, what happens when joinRoom fails? I cannot find error handling somewhere |
||
this.watchdogProcess(); | ||
} | ||
|
||
watchdogProcess() { | ||
if (!this.isOnline() || this._watchdogProcess) return; | ||
|
||
this._watchdogProcess = setTimeout(() => { | ||
this._watchdogProcess = null; | ||
if (this.queueAtoB.length) this.send([], this.senderRecvrA); | ||
else if (this.queueBtoA.length) this.send([], this.senderRecvrB); | ||
else return; | ||
}, 800 + num.random(50)); | ||
} | ||
|
||
isEmpty() { | ||
return !this.queueBtoA.length && !this.queueAtoB.length; | ||
} | ||
|
||
waitForDelivery() { | ||
} | ||
|
||
componentsForSender(sender) { | ||
} | ||
|
||
send(content, sender) { | ||
|
||
|
||
return this.deliver(sender); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "deliver" was used in the local channel to implement the details of send, here it is empty so a send actually does nothing? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had just emptied it with the intention of filling it with code particular to the l2l version, so this should be resolved with inheritance now |
||
} | ||
|
||
deliver(sender) { | ||
} | ||
|
||
|
||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,9 @@ import { disconnect, disconnectAll, connect } from "lively.bindings"; | |
import { buildTestWorld, destroyTestWorld } from "./helper.js"; | ||
import { Client } from "../client.js"; | ||
import { Master } from "../master.js"; | ||
|
||
import { Channel as L2LChannel } from "../l2lchannel.js"; | ||
import L2LClient from "lively.2lively/client.js"; | ||
import L2LTracker from "lively.2lively/tracker.js"; | ||
|
||
// System.decanonicalize("mocha-es6", "http://localhost:9011/lively.sync/tests/sync-test.js") | ||
// var env1, env2, env3, | ||
|
@@ -85,6 +87,98 @@ describe("messaging between master and client", () => { | |
|
||
}); | ||
|
||
|
||
|
||
describe("lively2lively backchannel tests", function() { | ||
this.timeout(1*1000) | ||
before(async() =>{ | ||
testingClient = await L2LClient.forceNew({}); | ||
await testingClient.whenRegistered(300); | ||
}) | ||
after(async() => { | ||
await testingClient.remove(); | ||
}) | ||
beforeEach(async () => setup(2)); | ||
afterEach(async () => teardown()); | ||
|
||
it("ensure clients have l2l clients", async () => { | ||
|
||
var {world1, masterWorld, client1, master} = state; | ||
var testChannel = new L2LChannel(client1, "receiveOpsFromMaster", master, "receiveOpsFromClient") | ||
|
||
expect((testChannel.senderRecvrA.l2lclient) && (testChannel.senderRecvrA.l2lclient instanceof L2LClient)).equals(true,'client A not L2LClient') | ||
expect((testChannel.senderRecvrB.l2lclient) && (testChannel.senderRecvrB.l2lclient instanceof L2LClient)).equals(true,'client B not L2LClient') | ||
|
||
await testChannel.senderRecvrA.l2lclient.whenRegistered(300) | ||
await testChannel.senderRecvrB.l2lclient.whenRegistered(300) | ||
|
||
window.testChannel = testChannel; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you clean up debug code? Leaving globals and such around might lead to strange effects There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed |
||
console.log(testChannel); | ||
window.testChannel = testChannel; | ||
|
||
testChannel.goOffline(); | ||
}) | ||
|
||
it('ensure clients can share a master', async () => { | ||
// return | ||
var {world1, masterWorld, client1, client2, master} = state; | ||
var testChannel = new L2LChannel(client1, "receiveOpsFromMaster", master, "receiveOpsFromClient") | ||
window.testChannel = testChannel | ||
expect((testChannel.senderRecvrA.l2lclient) && (testChannel.senderRecvrA.l2lclient instanceof L2LClient)).equals(true,'client A not L2LClient') | ||
expect((testChannel.senderRecvrB.l2lclient) && (testChannel.senderRecvrB.l2lclient instanceof L2LClient)).equals(true,'client B not L2LClient') | ||
|
||
await testChannel.senderRecvrA.l2lclient.whenRegistered(300) | ||
await testChannel.senderRecvrB.l2lclient.whenRegistered(300) | ||
|
||
var channelId = testChannel.senderRecvrB.l2lclient.socketId.split('#')[1] | ||
|
||
var testChannel2 = new L2LChannel(client2, "receiveOpsFromMaster", master, "receiveOpsFromClient") | ||
window.testChannel2 = testChannel2 | ||
expect((testChannel2.senderRecvrA.l2lclient) && (testChannel2.senderRecvrA.l2lclient instanceof L2LClient)).equals(true,'client A not L2LClient') | ||
expect((testChannel2.senderRecvrB.l2lclient) && (testChannel2.senderRecvrB.l2lclient instanceof L2LClient)).equals(true,'client B not L2LClient') | ||
|
||
await testChannel2.senderRecvrA.l2lclient.whenRegistered(300) | ||
await testChannel2.senderRecvrB.l2lclient.whenRegistered(300) | ||
|
||
expect(testChannel2.senderRecvrB === testChannel.senderRecvrB).equals(true,'Clients have different masters') | ||
|
||
testChannel.goOffline(); | ||
testChannel2.goOffline(); | ||
}) | ||
|
||
it('ensure clients can communicate across channel', async () => { | ||
var {world1, masterWorld, client1, master} = state; | ||
var client1Buffer = [] | ||
var masterBuffer = [] | ||
var payload = "Test for lively.sync messaging" | ||
var ack = 'received' | ||
function masterCheck(item){ | ||
masterBuffer.push(item) | ||
} | ||
function ackFn(item){ | ||
client1Buffer.push(item) | ||
client1.l2lclient.sendTo(master.l2lclient.id,'lively.sync',{payload: ack}) | ||
} | ||
client1.receiveOpsFromMaster = ackFn; | ||
master.receiveOpsFromClient = masterCheck; | ||
|
||
var testChannel = new L2LChannel(client1, "receiveOpsFromMaster", master, "receiveOpsFromClient") | ||
await testChannel.senderRecvrA.l2lclient.whenRegistered(300) | ||
await testChannel.senderRecvrB.l2lclient.whenRegistered(300) | ||
|
||
// testChannel.registerReceive(client1,client1.receiveOpsFromMaster) | ||
// testChannel.registerReceive(master,master.receiveOpsFromClient) | ||
master.l2lclient.sendTo(client1.l2lclient.id,'lively.sync',{payload: payload}) | ||
await promise.waitFor(200, () => client1Buffer.length >= 1); | ||
await promise.waitFor(200, () => masterBuffer.length >= 1); | ||
testChannel.goOffline(); | ||
expect(client1Buffer[0].payload).equals(payload,'payload not correct') | ||
expect(masterBuffer[0].payload).equals(ack,'payload not correct') | ||
}) | ||
|
||
}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. None of those tests actually runs lively.sync. How would the tests ""messaging between master and client - single op" and "syncing master with two clients - simple prop" look like when using l2l? |
||
|
||
|
||
describe("syncing master with two clients", function() { | ||
|
||
// this.timeout(5*1000); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason to copy the channel implementation from channel.js? Does subclassing work? Or just configuring the original channel with a variable backend? (l2l vs local)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved with inheritance