From 1066372371b4537264777859224bbcc499bb53bc Mon Sep 17 00:00:00 2001
From: Ladd Hoffman
Date: Thu, 5 Jan 2023 14:21:45 -0600
Subject: [PATCH] Add support for flowchart diagrams alongside sequence
---
forum-network/src/classes/action.js | 4 +-
forum-network/src/classes/actor.js | 21 +++--
forum-network/src/classes/bench.js | 6 +-
forum-network/src/classes/box.js | 14 ++-
forum-network/src/classes/business.js | 6 +-
forum-network/src/classes/expert.js | 20 ++---
forum-network/src/classes/forum-node.js | 6 +-
forum-network/src/classes/forum.js | 19 ++--
forum-network/src/classes/graph.js | 30 ++-----
forum-network/src/classes/post-content.js | 11 ++-
forum-network/src/classes/scene.js | 92 ++++++++++++--------
forum-network/src/classes/validation-pool.js | 10 +--
forum-network/src/index.html | 1 +
forum-network/src/tests/availability.html | 8 +-
forum-network/src/tests/debounce.html | 33 +++++++
forum-network/src/tests/flowchart.html | 39 +++++++++
forum-network/src/tests/forum-network.html | 2 +-
forum-network/src/tests/forum.html | 21 +++--
forum-network/src/tests/graph.html | 33 +++++++
forum-network/src/tests/validation-pool.html | 19 ++--
forum-network/src/util.js | 23 ++---
21 files changed, 270 insertions(+), 148 deletions(-)
create mode 100644 forum-network/src/tests/debounce.html
create mode 100644 forum-network/src/tests/flowchart.html
create mode 100644 forum-network/src/tests/graph.html
diff --git a/forum-network/src/classes/action.js b/forum-network/src/classes/action.js
index 7f559bc..4eb9a61 100644
--- a/forum-network/src/classes/action.js
+++ b/forum-network/src/classes/action.js
@@ -4,9 +4,9 @@ export class Action {
this.scene = scene;
}
- log(src, dest, msg, obj, symbol = '->>') {
+ async log(src, dest, msg, obj, symbol = '->>') {
const logObj = false;
- this.scene.log(
+ await this.scene.sequence.log(
`${src.name} ${symbol} ${dest.name} : ${this.name} ${msg ?? ''} ${
logObj && obj ? JSON.stringify(obj) : ''
}`,
diff --git a/forum-network/src/classes/actor.js b/forum-network/src/classes/actor.js
index 2aa1496..139213b 100644
--- a/forum-network/src/classes/actor.js
+++ b/forum-network/src/classes/actor.js
@@ -5,7 +5,6 @@ export class Actor {
this.callbacks = new Map();
this.status = this.scene.addDisplayValue(`${this.name} status`);
this.status.set('New');
- this.scene.log(`participant ${this.name}`);
this.values = new Map();
this.active = 0;
this.scene.registerActor(this);
@@ -13,31 +12,31 @@ export class Actor {
activate() {
this.active += 1;
- this.scene.log(`activate ${this.name}`);
+ this.scene.sequence.log(`activate ${this.name}`, false);
}
- deactivate() {
+ async deactivate() {
if (!this.active) {
throw new Error(`${this.name} is not active, can not deactivate`);
}
this.active -= 1;
- this.scene.log(`deactivate ${this.name}`);
+ await this.scene.sequence.log(`deactivate ${this.name}`);
}
- send(dest, action, detail) {
- action.log(this, dest, detail ? JSON.stringify(detail) : '');
- dest.recv(this, action, detail);
+ async send(dest, action, detail) {
+ await action.log(this, dest, detail ? JSON.stringify(detail) : '');
+ await dest.recv(this, action, detail);
return this;
}
- recv(src, action, detail) {
+ async recv(src, action, detail) {
const cb = this.callbacks.get(action.name);
if (!cb) {
throw new Error(
`[${this.scene.name} actor ${this.name} does not have a callback registered for ${action.name}`,
);
}
- cb(src, detail);
+ await cb(src, detail);
return this;
}
@@ -56,7 +55,7 @@ export class Actor {
return this;
}
- setValue(label, value) {
+ async setValue(label, value) {
if (typeof value === 'number') {
value = value.toFixed(2);
}
@@ -66,7 +65,7 @@ export class Actor {
this.values.set(label, displayValue);
}
if (value !== displayValue.get()) {
- this.scene.log(`note over ${this.name} : ${label} = ${value}`);
+ await this.scene.sequence.log(`note over ${this.name} : ${label} = ${value}`);
}
displayValue.set(value);
return this;
diff --git a/forum-network/src/classes/bench.js b/forum-network/src/classes/bench.js
index 59fa8ad..679fc10 100644
--- a/forum-network/src/classes/bench.js
+++ b/forum-network/src/classes/bench.js
@@ -18,8 +18,6 @@ export class Bench extends Actor {
this.actions = {
createValidationPool: new Action('create validation pool', scene),
};
-
- this.activate();
}
listValidationPools() {
@@ -56,7 +54,7 @@ export class Bench extends Actor {
.reduce((acc, cur) => (acc += cur), 0);
}
- initiateValidationPool({
+ async initiateValidationPool({
postId,
fee,
duration,
@@ -84,7 +82,7 @@ export class Bench extends Actor {
this.scene,
);
this.validationPools.set(validationPool.id, validationPool);
- this.actions.createValidationPool.log(this, validationPool);
+ await this.actions.createValidationPool.log(this, validationPool);
validationPool.activate();
return validationPool;
}
diff --git a/forum-network/src/classes/box.js b/forum-network/src/classes/box.js
index a03dcd1..cb3af73 100644
--- a/forum-network/src/classes/box.js
+++ b/forum-network/src/classes/box.js
@@ -1,11 +1,15 @@
import { DisplayValue } from './display-value.js';
+import { CryptoUtil } from './crypto.js';
export class Box {
constructor(name, parentEl, elementType = 'div') {
this.name = name;
this.el = document.createElement(elementType);
+ this.el.id = `box_${CryptoUtil.randomUUID().replaceAll('-', '').slice(0, 8)}`;
this.el.classList.add('box');
- this.el.setAttribute('box-name', name);
+ if (name) {
+ this.el.setAttribute('box-name', name);
+ }
if (parentEl) {
parentEl.appendChild(this.el);
}
@@ -27,8 +31,7 @@ export class Box {
}
addBox(name, elementType) {
- const box = new Box(name, null, elementType);
- this.el.appendChild(box.el);
+ const box = new Box(name, this.el, elementType);
return box;
}
@@ -46,11 +49,6 @@ export class Box {
return this.el.innerText;
}
- setId(id) {
- this.el.id = (id || this.name).replace(/ /g, '');
- return this;
- }
-
getId() {
return this.el.id;
}
diff --git a/forum-network/src/classes/business.js b/forum-network/src/classes/business.js
index 6dbb104..37753af 100644
--- a/forum-network/src/classes/business.js
+++ b/forum-network/src/classes/business.js
@@ -33,7 +33,7 @@ export class Business extends Actor {
async submitRequest(fee, content) {
const request = new Request(fee, content);
this.requests.set(request.id, request);
- this.actions.assignWork.log(this, this.availability);
+ await this.actions.assignWork.log(this, this.availability);
this.worker = await this.availability.assignWork(request.id);
return request.id;
}
@@ -54,13 +54,13 @@ export class Business extends Actor {
requestId,
workEvidence,
});
- this.actions.submitPost.log(this, this.forum);
+ await this.actions.submitPost.log(this, this.forum);
const postId = await this.forum.addPost(reputationPublicKey, post);
// Initiate a validation pool for this work evidence.
// Validation pool supports secret ballots but we aren't using that here, since we want
// the post to be attributable to the reputation holder.
- this.actions.initiateValidationPool.log(this, this.bench);
+ await this.actions.initiateValidationPool.log(this, this.bench);
const pool = await this.bench.initiateValidationPool({
postId,
fee: request.fee,
diff --git a/forum-network/src/classes/expert.js b/forum-network/src/classes/expert.js
index 312585e..39b8483 100644
--- a/forum-network/src/classes/expert.js
+++ b/forum-network/src/classes/expert.js
@@ -1,5 +1,4 @@
import { Actor } from './actor.js';
-
import { Action } from './action.js';
import { PostMessage } from './message.js';
import { CryptoUtil } from './crypto.js';
@@ -25,7 +24,6 @@ export class Expert extends Actor {
// this.reputationPublicKey = await CryptoUtil.exportKey(this.reputationKey.publicKey);
this.reputationPublicKey = this.name;
this.status.set('Initialized');
- this.activate();
return this;
}
@@ -33,19 +31,19 @@ export class Expert extends Actor {
// TODO: Include fee
const postMessage = new PostMessage({ post, stake });
await postMessage.sign(this.reputationKey);
- this.actions.submitPostViaNetwork.log(this, forumNode, null, { id: post.id });
+ await this.actions.submitPostViaNetwork.log(this, forumNode, null, { id: post.id });
// For now, directly call forumNode.receiveMessage();
await forumNode.receiveMessage(JSON.stringify(postMessage.toJSON()));
}
async submitPost(forum, postContent) {
// TODO: Include fee
- this.actions.submitPost.log(this, forum);
+ await this.actions.submitPost.log(this, forum);
return forum.addPost(this.reputationPublicKey, postContent);
}
async submitPostWithFee(bench, forum, postContent, poolOptions) {
- this.actions.submitPost.log(this, forum);
+ await this.actions.submitPost.log(this, forum);
const postId = await forum.addPost(this.reputationPublicKey, postContent);
const pool = await this.initiateValidationPool(bench, { ...poolOptions, postId, anonymous: false });
return { postId, pool };
@@ -59,12 +57,12 @@ export class Expert extends Actor {
} else {
poolOptions.signingPublicKey = this.reputationPublicKey;
}
- this.actions.initiateValidationPool.log(
+ await this.actions.initiateValidationPool.log(
this,
bench,
`(fee: ${poolOptions.fee})`,
);
- const pool = bench.initiateValidationPool(poolOptions);
+ const pool = await bench.initiateValidationPool(poolOptions);
this.validationPools.set(pool.id, poolOptions);
return pool;
}
@@ -82,7 +80,7 @@ export class Expert extends Actor {
}
// TODO: encrypt vote
// TODO: sign message
- this.actions.castVote.log(
+ await this.actions.castVote.log(
this,
validationPool,
`(${position ? 'for' : 'against'}, stake: ${stake}, anonymous: ${anonymous})`,
@@ -95,12 +93,12 @@ export class Expert extends Actor {
async revealIdentity(validationPool) {
const { signingPublicKey } = this.validationPools.get(validationPool.id);
// TODO: sign message
- this.actions.revealIdentity.log(this, validationPool);
+ await this.actions.revealIdentity.log(this, validationPool);
validationPool.revealIdentity(signingPublicKey, this.reputationPublicKey);
}
async registerAvailability(availability, stake) {
- this.actions.registerAvailability.log(this, availability, `(stake: ${stake})`);
+ await this.actions.registerAvailability.log(this, availability, `(stake: ${stake})`);
await availability.register(this.reputationPublicKey, stake);
}
@@ -111,7 +109,7 @@ export class Expert extends Actor {
}
async submitWork(business, requestId, evidence, { tokenLossRatio, duration }) {
- this.actions.submitWork.log(this, business);
+ await this.actions.submitWork.log(this, business);
return business.submitWork(this.reputationPublicKey, requestId, evidence, { tokenLossRatio, duration });
}
}
diff --git a/forum-network/src/classes/forum-node.js b/forum-network/src/classes/forum-node.js
index e09b6fa..1528cd3 100644
--- a/forum-network/src/classes/forum-node.js
+++ b/forum-network/src/classes/forum-node.js
@@ -34,7 +34,7 @@ export class ForumNode extends Actor {
.filter((forumNode) => forumNode.keyPair.publicKey !== this.keyPair.publicKey);
for (const forumNode of otherForumNodes) {
// For now just call receiveMessage on the target node
- this.actions.peerMessage.log(this, forumNode, null, message.content);
+ await this.actions.peerMessage.log(this, forumNode, null, message.content);
await forumNode.receiveMessage(JSON.stringify(message.toJSON()));
}
}
@@ -61,7 +61,7 @@ export class ForumNode extends Actor {
try {
await Message.verify(messageJson);
} catch (e) {
- this.actions.processMessage.log(this, this, 'invalid signature', messageJson, '-x');
+ await this.actions.processMessage.log(this, this, 'invalid signature', messageJson, '-x');
console.log(`${this.name}: received message with invalid signature`);
return;
}
@@ -87,7 +87,7 @@ export class ForumNode extends Actor {
if (!post.id) {
post.id = CryptoUtil.randomUUID();
}
- this.actions.storePost.log(this, this, null, { authorId, post, stake });
+ await this.actions.storePost.log(this, this, null, { authorId, post, stake });
this.forumView.addPost(authorId, post.id, post, stake);
}
diff --git a/forum-network/src/classes/forum.js b/forum-network/src/classes/forum.js
index 74cc183..36a2b31 100644
--- a/forum-network/src/classes/forum.js
+++ b/forum-network/src/classes/forum.js
@@ -13,6 +13,7 @@ class Post extends Actor {
this.authorPublicKey = authorPublicKey;
this.value = 0;
this.citations = postContent.citations;
+ this.title = postContent.title;
this.totalCitationWeight = this.citations.reduce((total, { weight }) => total += weight, 0);
if (this.totalCitationWeight > params.revaluationLimit) {
throw new Error('Post total citation weight exceeds revaluation limit '
@@ -23,8 +24,8 @@ class Post extends Actor {
}
}
- setPostValue(value) {
- this.setValue('value', value);
+ async setPostValue(value) {
+ await this.setValue('value', value);
this.value = value;
}
@@ -39,7 +40,7 @@ class Post extends Actor {
export class Forum extends Actor {
constructor(name, scene) {
super(name, scene);
- this.posts = new Graph();
+ this.posts = new Graph(scene);
this.actions = {
addPost: new Action('add post', scene),
};
@@ -47,9 +48,9 @@ export class Forum extends Actor {
async addPost(authorId, postContent) {
const post = new Post(this, authorId, postContent);
- this.actions.addPost.log(this, post);
- this.posts.addVertex(post.id, post);
- for (const { postId: citedPostId, weight } of postContent.citations) {
+ await this.actions.addPost.log(this, post);
+ this.posts.addVertex(post.id, post, post.title);
+ for (const { postId: citedPostId, weight } of post.citations) {
this.posts.addEdge('citation', post.id, citedPostId, { weight });
}
return post.id;
@@ -63,7 +64,7 @@ export class Forum extends Actor {
return this.posts.getVertices();
}
- propagateValue(postId, increment, depth = 0) {
+ async propagateValue(postId, increment, depth = 0) {
if (depth > params.maxPropagationDepth) {
return [];
}
@@ -78,7 +79,7 @@ export class Forum extends Actor {
// Increment the value of the given post
const postValue = post.getPostValue();
- post.setPostValue(postValue + increment);
+ await post.setPostValue(postValue + increment);
// Award reputation to post author
console.log('reward for post author', post.authorPublicKey, increment);
@@ -86,7 +87,7 @@ export class Forum extends Actor {
// Recursively distribute reputation to citations, according to weights
for (const { postId: citedPostId, weight } of post.citations) {
- addRewards(this.propagateValue(citedPostId, weight * increment, depth + 1));
+ addRewards(await this.propagateValue(citedPostId, weight * increment, depth + 1));
}
return rewards;
diff --git a/forum-network/src/classes/graph.js b/forum-network/src/classes/graph.js
index 303c2c1..84bbd74 100644
--- a/forum-network/src/classes/graph.js
+++ b/forum-network/src/classes/graph.js
@@ -1,6 +1,3 @@
-import mermaid from 'https://unpkg.com/mermaid@9.2.2/dist/mermaid.esm.min.mjs';
-import { debounce } from '../util.js';
-
export class Vertex {
constructor(data) {
this.data = data;
@@ -29,13 +26,14 @@ export class Edge {
export class CategorizedEdges {}
export class Graph {
- constructor() {
+ constructor(scene) {
+ this.scene = scene;
this.vertices = new Map();
this.edgeLabels = new Map();
this.nextVertexId = 0;
}
- addVertex(id, data) {
+ addVertex(id, data, label) {
// Support simple case of auto-incremented numeric ids
if (typeof id === 'object') {
data = id;
@@ -46,6 +44,9 @@ export class Graph {
}
const vertex = new Vertex(data);
this.vertices.set(id, vertex);
+ if (this.scene.flowchart) {
+ this.scene.flowchart.log(`${id}[${label ?? id}]`);
+ }
return this;
}
@@ -83,6 +84,9 @@ export class Graph {
this.setEdge(label, from, to, edge);
this.getVertex(from).edges.from.push(edge);
this.getVertex(to).edges.to.push(edge);
+ if (this.scene.flowchart) {
+ this.scene.flowchart.log(`${from} --> ${to}`);
+ }
return this;
}
@@ -101,20 +105,4 @@ export class Graph {
countVertices() {
return this.vertices.size;
}
-
- async renderGraph() {
- const render = async () => {
- const dateStart = new Date();
- const graph = await mermaid.mermaidAPI.render(
- this.seqDiagramElement.getId(),
- this.logBox.getInnerText(),
- );
- this.seqDiagramBox.setInnerHTML(graph);
- if (!this.dateLastRender) {
- this.dateLastRender = new Date();
- }
- this.dateLastRender = dateStart;
- };
- debounce(render, 100);
- }
}
diff --git a/forum-network/src/classes/post-content.js b/forum-network/src/classes/post-content.js
index f85e32f..8512f3f 100644
--- a/forum-network/src/classes/post-content.js
+++ b/forum-network/src/classes/post-content.js
@@ -28,18 +28,27 @@ export class PostContent {
return this;
}
+ setTitle(title) {
+ this.title = title;
+ return this;
+ }
+
toJSON() {
return {
content: this.content,
citations: this.citations.map((citation) => citation.toJSON()),
...(this.id ? { id: this.id } : {}),
+ title: this.title,
};
}
- static fromJSON({ id, content, citations }) {
+ static fromJSON({
+ id, content, citations, title,
+ }) {
const post = new PostContent(content);
post.citations = citations.map((citation) => Citation.fromJSON(citation));
post.id = id;
+ post.title = title;
return post;
}
}
diff --git a/forum-network/src/classes/scene.js b/forum-network/src/classes/scene.js
index a8db134..7e4be90 100644
--- a/forum-network/src/classes/scene.js
+++ b/forum-network/src/classes/scene.js
@@ -3,24 +3,47 @@ import { Actor } from './actor.js';
import { Action } from './action.js';
import { debounce } from '../util.js';
+class MermaidDiagram {
+ constructor(box) {
+ this.box = box;
+ this.container = this.box.addBox('Container');
+ this.element = this.box.addBox('Element');
+ this.renderBox = this.box.addBox('Render');
+ this.box.addBox('Spacer').setInnerHTML(' ');
+ this.logBox = this.box.addBox('Log');
+ }
+
+ async log(msg, render = true) {
+ this.logBox.addBox().setInnerHTML(msg).monospace();
+ if (render) {
+ await this.render();
+ }
+ return this;
+ }
+
+ async render() {
+ const render = async () => {
+ const innerText = this.logBox.getInnerText();
+ const graph = await mermaid.mermaidAPI.render(
+ this.element.getId(),
+ innerText,
+ );
+ this.renderBox.setInnerHTML(graph);
+ };
+ await debounce(render, 100);
+ }
+}
+
export class Scene {
constructor(name, rootBox) {
this.name = name;
this.box = rootBox.addBox(name);
- this.titleBox = this.box.addBox().setInnerHTML(name);
+ this.titleBox = this.box.addBox('Title').setInnerHTML(name);
this.box.addBox('Spacer').setInnerHTML(' ');
- this.displayValuesBox = this.box.addBox(`${this.name}-values`);
+ this.displayValuesBox = this.box.addBox('Values');
this.box.addBox('Spacer').setInnerHTML(' ');
this.actors = new Set();
- this.seqDiagramContainer = this.box.addBox(
- `${this.name}-seq-diagram-container`,
- );
- this.seqDiagramElement = this.box
- .addBox(`${this.name}-seq-diagram-element`)
- .setId();
- this.seqDiagramBox = this.box.addBox(`${this.name}-seq-diagram`);
- this.box.addBox('Spacer').setInnerHTML(' ');
- this.logBox = this.box.addBox(`${this.name}-log`);
+
mermaid.mermaidAPI.initialize({
startOnLoad: false,
theme: 'base',
@@ -28,18 +51,37 @@ export class Scene {
darkMode: true,
primaryColor: '#2a5b6c',
primaryTextColor: '#b6b6b6',
+ // lineColor: '#349cbd',
+ lineColor: '#57747d',
+ signalColor: '#57747d',
+ // signalColor: '#349cbd',
noteBkgColor: '#516f77',
noteTextColor: '#cecece',
activationBkgColor: '#1d3f49',
activationBorderColor: '#569595',
- signalColor: '#57747d',
},
});
- this.dateLastRender = null;
}
- addActor(name) {
+ withSequenceDiagram() {
+ const box = this.box.addBox('Sequence diagram');
+ this.sequence = new MermaidDiagram(box);
+ this.sequence.log('sequenceDiagram', false);
+ return this;
+ }
+
+ withFlowchart(direction = 'BT') {
+ const box = this.box.addBox('Flowchart');
+ this.flowchart = new MermaidDiagram(box);
+ this.flowchart.log(`graph ${direction}`, false);
+ return this;
+ }
+
+ async addActor(name) {
const actor = new Actor(name, this);
+ if (this.sequence) {
+ await this.scene.sequence.log(`participant ${name}`);
+ }
return actor;
}
@@ -57,12 +99,6 @@ export class Scene {
return dv;
}
- log(msg) {
- this.logBox.addBox().setInnerHTML(msg).monospace();
- this.renderSequenceDiagram();
- return this;
- }
-
deactivateAll() {
for (const actor of this.actors.values()) {
while (actor.active) {
@@ -70,20 +106,4 @@ export class Scene {
}
}
}
-
- async renderSequenceDiagram() {
- const render = async () => {
- const dateStart = new Date();
- const graph = await mermaid.mermaidAPI.render(
- this.seqDiagramElement.getId(),
- this.logBox.getInnerText(),
- );
- this.seqDiagramBox.setInnerHTML(graph);
- if (!this.dateLastRender) {
- this.dateLastRender = new Date();
- }
- this.dateLastRender = dateStart;
- };
- debounce(render, 100);
- }
}
diff --git a/forum-network/src/classes/validation-pool.js b/forum-network/src/classes/validation-pool.js
index 0c2a4c0..84fc053 100644
--- a/forum-network/src/classes/validation-pool.js
+++ b/forum-network/src/classes/validation-pool.js
@@ -193,12 +193,12 @@ export class ValidationPool extends Actor {
if (quorumMet) {
this.setStatus(`Resolved - ${result ? 'Won' : 'Lost'}`);
- this.scene.log(`note over ${this.name} : ${result ? 'Win' : 'Lose'}`);
+ this.scene.sequence.log(`note over ${this.name} : ${result ? 'Win' : 'Lose'}`);
this.applyTokenLocking();
- this.distributeTokens(result);
+ await this.distributeTokens(result);
} else {
this.setStatus('Resolved - Quorum not met');
- this.scene.log(`note over ${this.name} : Quorum not met`);
+ this.scene.sequence.log(`note over ${this.name} : Quorum not met`);
}
this.deactivate();
@@ -206,7 +206,7 @@ export class ValidationPool extends Actor {
return result;
}
- distributeTokens({ votePasses }) {
+ async distributeTokens({ votePasses }) {
const rewards = new Map();
const addReward = (id, value) => rewards.set(id, (rewards.get(id) ?? 0) + value);
@@ -231,7 +231,7 @@ export class ValidationPool extends Actor {
if (votePasses && !!this.forum) {
// Recurse through forum to determine reputation effects
- const forumReputationEffects = this.forum.propagateValue(this.postId, this.tokensMinted);
+ const forumReputationEffects = await this.forum.propagateValue(this.postId, this.tokensMinted);
for (const [id, value] of forumReputationEffects) {
addReward(id, value);
}
diff --git a/forum-network/src/index.html b/forum-network/src/index.html
index fb3d946..96eafef 100644
--- a/forum-network/src/index.html
+++ b/forum-network/src/index.html
@@ -14,5 +14,6 @@
Debounce
Availability
Forum
+ Flowchart
+
+
+
+
+
+
diff --git a/forum-network/src/tests/availability.html b/forum-network/src/tests/availability.html
index bcda9f5..0ffce02 100644
--- a/forum-network/src/tests/availability.html
+++ b/forum-network/src/tests/availability.html
@@ -56,13 +56,13 @@
const updateDisplayValues = async () => {
for (const expert of experts) {
- expert.setValue(
+ await expert.setValue(
"rep",
bench.reputations.getTokens(expert.reputationPublicKey)
);
}
- bench.setValue("total rep", bench.getTotalReputation());
- await scene.renderSequenceDiagram();
+ await bench.setValue("total rep", bench.getTotalReputation());
+ await scene.sequence.render();
};
const updateDisplayValuesAndDelay = async () => {
@@ -77,7 +77,7 @@
request = await expert.getAssignedWork(availability, business);
if (request) {
worker = expert;
- worker.actions.getAssignedWork.log(worker, availability);
+ await worker.actions.getAssignedWork.log(worker, availability);
worker.activate();
break;
}
diff --git a/forum-network/src/tests/debounce.html b/forum-network/src/tests/debounce.html
new file mode 100644
index 0000000..f1aff20
--- /dev/null
+++ b/forum-network/src/tests/debounce.html
@@ -0,0 +1,33 @@
+
+
+
diff --git a/forum-network/src/tests/flowchart.html b/forum-network/src/tests/flowchart.html
new file mode 100644
index 0000000..1330faa
--- /dev/null
+++ b/forum-network/src/tests/flowchart.html
@@ -0,0 +1,39 @@
+
+
+
diff --git a/forum-network/src/tests/forum-network.html b/forum-network/src/tests/forum-network.html
index 9ff7814..4e528a7 100644
--- a/forum-network/src/tests/forum-network.html
+++ b/forum-network/src/tests/forum-network.html
@@ -43,7 +43,7 @@
await window.forumNode2.processNextMessage();
await window.forumNode3.processNextMessage();
- await window.scene.renderSequenceDiagram();
+ await window.scene.sequence.render();
}, 100);
// const blockchain = new Blockchain();
diff --git a/forum-network/src/tests/forum.html b/forum-network/src/tests/forum.html
index 11faa2f..c17bd37 100644
--- a/forum-network/src/tests/forum.html
+++ b/forum-network/src/tests/forum.html
@@ -23,9 +23,9 @@
const rootElement = document.getElementById("forum-test");
const rootBox = new Box("rootBox", rootElement).flex();
- const scene = (window.scene = new Scene("Forum test", rootBox).log(
- "sequenceDiagram"
- ));
+ const scene = (window.scene = new Scene("Forum test", rootBox));
+ scene.withSequenceDiagram();
+ scene.withFlowchart();
const experts = (window.experts = []);
const newExpert = async () => {
@@ -44,13 +44,12 @@
const updateDisplayValues = async () => {
for (const expert of experts) {
- expert.setValue(
+ await expert.setValue(
"rep",
bench.reputations.getTokens(expert.reputationPublicKey)
);
}
- bench.setValue("total rep", bench.getTotalReputation());
- await scene.renderSequenceDiagram();
+ await bench.setValue("total rep", bench.getTotalReputation());
};
const updateDisplayValuesAndDelay = async (delayMs) => {
@@ -63,7 +62,7 @@
const { postId: postId1, pool: pool1 } = await expert1.submitPostWithFee(
bench,
forum,
- new PostContent({ hello: "there" }),
+ new PostContent({ hello: "there" }).setTitle("Post 1"),
{
fee: 10,
duration: 1000,
@@ -81,7 +80,9 @@
const { postId: postId2, pool: pool2 } = await expert2.submitPostWithFee(
bench,
forum,
- new PostContent({ hello: "to you as well" }).addCitation(postId1, 0.5),
+ new PostContent({ hello: "to you as well" })
+ .setTitle("Post 2")
+ .addCitation(postId1, 0.5),
{
fee: 10,
duration: 1000,
@@ -99,7 +100,9 @@
const { pool: pool3 } = await expert3.submitPostWithFee(
bench,
forum,
- new PostContent({ hello: "y'all" }).addCitation(postId2, 0.5),
+ new PostContent({ hello: "y'all" })
+ .setTitle("Post 3")
+ .addCitation(postId2, 0.5),
{
fee: 10,
duration: 1000,
diff --git a/forum-network/src/tests/graph.html b/forum-network/src/tests/graph.html
new file mode 100644
index 0000000..d905ce2
--- /dev/null
+++ b/forum-network/src/tests/graph.html
@@ -0,0 +1,33 @@
+
+
+
diff --git a/forum-network/src/tests/validation-pool.html b/forum-network/src/tests/validation-pool.html
index c018e61..c5cb21e 100644
--- a/forum-network/src/tests/validation-pool.html
+++ b/forum-network/src/tests/validation-pool.html
@@ -17,9 +17,8 @@
const rootElement = document.getElementById("validation-pool");
const rootBox = new Box("rootBox", rootElement).flex();
- const scene = (window.scene = new Scene("Validation Pool test", rootBox).log(
- "sequenceDiagram"
- ));
+ const scene = (window.scene = new Scene("Validation Pool test", rootBox));
+ await scene.withSequenceDiagram();
const expert1 = (window.expert1 = await new Expert(
"Expert1",
scene
@@ -31,21 +30,21 @@
const bench = (window.bench = new Bench(undefined, "Bench", scene));
const updateDisplayValues = async () => {
- expert1.setValue(
+ await expert1.setValue(
"rep",
bench.reputations.getTokens(expert1.reputationPublicKey)
);
- expert2.setValue(
+ await expert2.setValue(
"rep",
bench.reputations.getTokens(expert2.reputationPublicKey)
);
- bench.setValue("total rep", bench.getTotalReputation());
+ await bench.setValue("total rep", bench.getTotalReputation());
// With params.lockingTimeExponent = 0 and params.activeVoterThreshold = null,
// these next 3 propetries are all equal to total rep
- // bench.setValue('available rep', bench.getTotalAvailableReputation());
- // bench.setValue('active rep', bench.getTotalActiveReputation());
- // bench.setValue('active available rep', bench.getTotalActiveAvailableReputation());
- await scene.renderSequenceDiagram();
+ // await bench.setValue('available rep', bench.getTotalAvailableReputation());
+ // await bench.setValue('active rep', bench.getTotalActiveReputation());
+ // await bench.setValue('active available rep', bench.getTotalActiveAvailableReputation());
+ await scene.sequence.render();
};
updateDisplayValues();
diff --git a/forum-network/src/util.js b/forum-network/src/util.js
index a44dd7c..3422ba8 100644
--- a/forum-network/src/util.js
+++ b/forum-network/src/util.js
@@ -1,17 +1,20 @@
-const timeouts = new Map();
+const timers = new Map();
-export const debounce = (fn, delay) => {
- const key = fn.toString();
- if (!timeouts.get(key)) {
- timeouts.set(key, setTimeout(async () => {
- timeouts.delete(key);
- await fn();
- }, delay));
+export const debounce = async (fn, delayMs) => {
+ const timer = timers.get(fn);
+ if (timer) {
+ return timer.result;
}
+ const result = await fn();
+ timers.set(fn, { result });
+ setTimeout(() => {
+ timers.delete(fn);
+ }, delayMs);
+ return result;
};
-export const delay = async (ms) => {
+export const delay = async (delayMs) => {
await new Promise((resolve) => {
- setTimeout(resolve, ms);
+ setTimeout(resolve, delayMs);
});
};