Skip to content

Commit

Permalink
Monitor = Coroutine
Browse files Browse the repository at this point in the history
  • Loading branch information
elierotenberg committed Aug 18, 2017
1 parent 547fb4a commit a8d5336
Show file tree
Hide file tree
Showing 14 changed files with 945 additions and 1,374 deletions.
17 changes: 0 additions & 17 deletions .babelrc

This file was deleted.

81 changes: 81 additions & 0 deletions async-context-ui/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
const blessed = require('blessed');
const blessedContrib = require('blessed-contrib');

const mapObject = (obj, fn) => {
const res = {};
Object.keys(obj).forEach(k => (res[k] = fn(obj[k], k)));
return res;
};

const mapArrayToObject = (arr, fn) => {
const res = {};
arr.forEach(originalVal => {
const [k, v] = fn(originalVal);
res[k] = v;
});
};

const toTreeDataResource = ({
resourceId,
type,
contextId,
parentResourceId,
childrenResources,
}) => [
resourceId,
{
name: `Resource (type = ${type}, resourceId = ${resourceId}, parentResourceId = ${parentResourceId}, contextId = ${contextId})`,
children: mapArrayToObject(childrenResources, toTreeDataResource),
},
];

const toTreeData = ({ trackedContexts }) => ({
extended: true,
children: mapObject(
trackedContexts,
({ name, contextId, parentContextId, childrenResources }) => ({
name: `Context (name = ${name}, contextId = ${contextId}, parentContextId = ${parentContextId})`,
children: mapArrayToObject(childrenResources, toTreeDataResource),
}),
),
});

class ContextMonitorUI {
constructor(monitor, period) {
this.monitor = monitor;
this.period = period;
this.interval = null;
this.screen = null;
this.grid = null;
this.tree = null;

this.render = this.render.bind(this);
}

start() {
if (this.interval !== null) {
throw new Error('Already started');
}

this.screen = blessed.screen();

this.tree = blessedContrib.tree();
this.screen.append(this.tree);
this.screen.key(['C-c'], () => process.exit(0));
this.tree.focus();

this.interval = setInterval(this.render, this.period);
}

stop() {
clearInterval(this.interval);
this.screen.destroy();
}

render() {
this.tree.setData(toTreeData(this.monitor.toJS()));
this.screen.render();
}
}

module.exports = ContextMonitorUI;
41 changes: 41 additions & 0 deletions async-context/Coroutine.example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
process.on('unhandledRejection', err => {
throw err;
});

const Monitor = require('./Monitor');
const Coroutine = require('./Coroutine');

const monitor = new Monitor();

const sleep = delay => new Promise(resolve => setTimeout(resolve, delay));

const initFoo = async () => {
await sleep(100);
Coroutine.context.foo = 'bar';
};

const initFizz = async () => {
await sleep(300);
Coroutine.context.fizz = 'buzz';
};

const logContext = () => Monitor.log({ context: Coroutine.context });

// const coroutine = new Coroutine(async fn, monitor)
// await coroutine(props);

Coroutine.spawn(
async () => {
logContext();
await initFoo();
logContext();
await Coroutine.spawn(initFizz);
logContext();
return Coroutine.context.foo + Coroutine.context.fizz;
},
{
foo: 'hello',
fizz: 'world',
},
monitor,
).then(output => console.log({ output }));
92 changes: 92 additions & 0 deletions async-context/Coroutine.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
const EventEmitter = require('./EventEmitter');
const inspectable = require('./inspectable');

let currentCoroutine = null;

const runMicroTask = fn => Promise.resolve().then(fn);

const Coroutine = inspectable(
class Coroutine extends EventEmitter {
static get context() {
return currentCoroutine.context;
}

static spawn(...args) {
return new this(...args).join();
}

static toJS() {
return currentCoroutine.toJS();
}

constructor(
fn,
context = currentCoroutine.context,
monitor = currentCoroutine.monitor,
) {
super();
this._fn = fn;
this.monitor = monitor;
this.context = context;

this._parentNode = this.monitor.getCurrentNode();
this._parentCoroutine = currentCoroutine;
this._node = null;
this._nodes = new Set();

this._onMonitorAddNode = this._onMonitorAddNode.bind(this);
this._onMonitorRemoveNode = this._onMonitorRemoveNode.bind(this);
this._start = this._start.bind(this);

this._promise = runMicroTask(this._start);
}

toJS() {
return {
listeners: super.toJS().listeners,
nodes: Array.from(this._nodes, inspectable.toJS),
context: inspectable.toJS(this.context),
};
}

join() {
return this._promise;
}

emit(...args) {
super.emit('*', ...args);
super.emit(...args);
return this;
}

async _start() {
this._node = this.monitor.getCurrentNode();
this.monitor.addListener('addNode', this._onMonitorAddNode);
this.monitor.addListener('removeNode', this._onMonitorRemoveNode);
try {
return await runMicroTask(this._fn);
} finally {
this.monitor.removeListener('removeListener', this._onMonitorAddNode);
this.monitor.removeListener(
'removeListener',
this._onMonitorRemoveNode,
);
}
}

_onMonitorAddNode(node) {
if (this.monitor.isAncestorNode(this._node, node)) {
this._nodes.add(node);
currentCoroutine = this;
}
}

_onMonitorRemoveNode(node) {
this._nodes.delete(node);
}
},
);

Coroutine.spawn = Coroutine.spawn.bind(Coroutine);

module.exports = Coroutine;
24 changes: 24 additions & 0 deletions async-context/EventEmitter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const BaseEventEmitter = require('events');
const inspectable = require('./inspectable');

const EventEmitter = inspectable(
class extends BaseEventEmitter {
emit(...args) {
super.emit('*', ...args);
super.emit(...args);
}

toJS() {
return {
listeners: this.eventNames()
.map(eventName => [eventName, this.listeners(eventName)])
.reduce((obj, [v, k]) => {
obj[k] = inspectable.toJS(v);
return obj;
}, {}),
};
}
},
);

module.exports = EventEmitter;
8 changes: 8 additions & 0 deletions async-context/Monitor.example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const Monitor = require('./Monitor');

const monitor = new Monitor();
monitor.on('*', (event, ...args) => Monitor.log([event, args]));

process.nextTick(() => {
setTimeout(() => void 0);
});
Loading

0 comments on commit a8d5336

Please sign in to comment.