Skip to content

Commit

Permalink
controlled message sending for meet/probe/loop
Browse files Browse the repository at this point in the history
  • Loading branch information
michielbdejong committed Mar 4, 2024
1 parent 980bb82 commit ab9e8e5
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 10 deletions.
34 changes: 32 additions & 2 deletions __tests__/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,15 @@ describe('triangle', () => {
});
it('Alice is friends with Bob', () => {
expect(alice.getFriends()).toEqual([ 'Bob' ]);
});
it('Alice has an AliceBob probe for Bob', () => {
expect(alice.getProbes()).toEqual({
AliceBob: { Bob: true }
});
});
it('Alice has no loops', () => {
expect(alice.getLoops()).toEqual([]);
});
it('Bob is friends with Alice', () => {
expect(bob.getFriends()).toEqual([ 'Alice' ]);
expect(bob.getProbes()).toEqual({
Expand All @@ -77,6 +82,9 @@ describe('triangle', () => {
BobCharlie: { Bob: true }
});
});
it('Alice has no loops', () => {
expect(alice.getLoops()).toEqual([]);
});
it('Bob is friends with Alice and Charlie', () => {
expect(bob.getFriends()).toEqual([ 'Alice', 'Charlie' ]);
expect(bob.getProbes()).toEqual({
Expand Down Expand Up @@ -105,8 +113,15 @@ describe('triangle', () => {
BobCharlie: { Bob: true, Charlie: true },
CharlieAlice: { Bob: true, Charlie: true }
});

});
it('Alice has 3 loops', () => {
expect(alice.getLoops().sort()).toEqual([
'AliceBob',
'BobCharlie',
'CharlieAlice'
].sort());
});

it('Bob is friends with Alice and Charlie', () => {
expect(bob.getFriends()).toEqual([ 'Alice', 'Charlie' ]);
expect(bob.getProbes()).toEqual({
Expand All @@ -115,13 +130,28 @@ describe('triangle', () => {
CharlieAlice: { Alice: true, Charlie: true }
});
});
it('Bob has 3 loops', () => {
expect(bob.getLoops().sort()).toEqual([
'CharlieAlice',
'BobCharlie',
'AliceBob'
].sort());
});

it('Charlie is friends with Bob and Alice', () => {
expect(charlie.getFriends()).toEqual([ 'Bob', 'Alice' ]);
expect(charlie.getProbes()).toEqual({
AliceBob: { Alice: true, Bob: true },
BobCharlie: { Alice: true, Bob: true },
CharlieAlice: { Alice: true, Bob: true }
});
});
});
it('Charlie has 3 loops', () => {
expect(charlie.getLoops().sort()).toEqual([
'AliceBob',
'BobCharlie',
'CharlieAlice'
].sort());
});
}); // Charlie meets Alice
}); // Bob meets Charlie
Expand Down
14 changes: 14 additions & 0 deletions src/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,17 @@ export class Probe extends Message {
return this.id;
}
}

export class Loop extends Message {
private id: string;
constructor(sender: Salmon, id: string) {
super(sender);
this.id = id;
}
getMessageType(): string {
return 'loop';
}
getId(): string {
return this.id;
}
}
52 changes: 44 additions & 8 deletions src/salmon.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Message, Meet, Probe } from "./messages.js";
import { Message, Meet, Probe, Loop } from "./messages.js";
import { genRanHex } from "./util.js";

// Salmon nodes always send all the probes they can to all their friends.
Expand All @@ -10,7 +10,10 @@ export class Salmon {
private probes: {
[id: string]: { [name: string]: boolean }
} = {};
constructor(name: string) {
private loops: {
[id: string]: boolean
} = {};
constructor(name: string) {
this.name = name;
}
private addFriend(other: Salmon): void {
Expand All @@ -31,15 +34,28 @@ export class Salmon {
this.probes[probeForNewLink] = {};
}
Object.values(this.friends).forEach(friend => {
this.probes[probeForNewLink][friend.getName()] = true;
friend.receiveMessage(new Probe(this, probeForNewLink))
if (typeof this.probes[probeForNewLink][friend.getName()] === 'undefined') {
this.probes[probeForNewLink][friend.getName()] = true;
friend.receiveMessage(new Probe(this, probeForNewLink));
return;
}
if (this.loops[probeForNewLink]) {
console.log(`new probe apparently looped back`);
return;
}
/* istanbul ignore next */
throw new Error(`unexpected!`);
});

// send existing probes to new friend
Object.entries(this.probes).forEach(([id, probes]) => {
if (typeof probes[other.getName()] === 'undefined') {
this.probes[id][other.getName()] = true;
other.receiveMessage(new Probe(this, id));
if (this.loops[id]) {
console.log(`existing probe apparently looped back`);
} else {
if (typeof probes[other.getName()] === 'undefined') {
this.probes[id][other.getName()] = true;
other.receiveMessage(new Probe(this, id));
}
}
});
}
Expand All @@ -52,6 +68,9 @@ export class Salmon {
getProbes(): { [id: string]: { [name: string]: boolean } } {
return this.probes;
}
getLoops(): string[] {
return Object.keys(this.loops);
}
receiveMessage(message: Message): void {
console.log(`${this.name} receives message from ${message.getSender().getName()}`, message);
if (message.getMessageType() === `meet`) {
Expand All @@ -73,7 +92,11 @@ export class Salmon {
if (typeof this.probes[probeMessage.getId()] === 'undefined') {
this.probes[probeMessage.getId()] = {};
} else {
console.log(`LOOP DETECTED!: ${this.name} already has probe ${probeMessage.getId()} from ${Object.keys(this.probes[probeMessage.getId()]).join(' and ')}`);
console.log(`LOOP DETECTED!: ${this.name} already has probe ${probeMessage.getId()} from (or sent to) ${Object.keys(this.probes[probeMessage.getId()]).join(' and ')}`);
this.loops[probeMessage.getId()] = true;
Object.keys(this.probes[probeMessage.getId()]).forEach(name => {
this.friends[name].receiveMessage(new Loop(this, probeMessage.getId()));
});
}
this.probes[probeMessage.getId()][message.getSender().getName()] = true;

Expand All @@ -85,6 +108,19 @@ export class Salmon {
}
});
// this.addFriend(message.getSender());
} else if (message.getMessageType() === `loop`) {
const loopMessage = message as Loop;
if (!this.loops[loopMessage.getId()]) {
console.log(`${this.name} received loop message about ${loopMessage.getId()} from ${message.getSender().getName()}`);
Object.keys(this.probes[loopMessage.getId()]).forEach(name => {
if (name !== message.getSender().getName()) {
this.friends[name].receiveMessage(new Loop(this, loopMessage.getId()));
}
});
this.loops[loopMessage.getId()] = true;
} else {
console.log(`LOOP ${loopMessage.getId()} IS NOT NEW TO ME`);
}
}
}
}

0 comments on commit ab9e8e5

Please sign in to comment.