Code Examples for Reading 18
Download
You can also download a ZIP file containing this code.
drinksfridge.ts
import assert from 'assert';
import { MessagePort } from 'worker_threads';
/** Record type for DrinksFridge's reply messages. */
export type FridgeResult = {
drinksTakenOrAdded: number, // number of drinks removed from fridge (if >0) or added to fridge (if <0)
drinksLeftInFridge: number
};
/**
* A mutable type representing a refrigerator containing drinks.
*/
export class DrinksFridge {
private drinksInFridge: number = 0;
// Abstraction function:
// AF(drinksInFridge, port) = a refrigerator containing `drinksInFridge` drinks
// that takes requests from and sends replies to `port`
// Rep invariant:
// drinksInFridge >= 0
/**
* Make a DrinksFridge that will listen for requests and generate replies.
*
* @param port port to receive requests from and send replies to
*/
public constructor(
private readonly port: MessagePort
) {
this.checkRep();
}
private checkRep(): void {
assert(this.drinksInFridge >= 0);
}
/** Start handling drink requests. */
public start(): void {
this.port.addListener('message', (n: number) => {
const reply: FridgeResult = this.handleDrinkRequest(n);
this.port.postMessage(reply);
});
}
/** @param n number of drinks requested from the fridge (if >0),
or to load into the fridge (if <0) */
private handleDrinkRequest(n: number): FridgeResult {
const change = Math.min(n, this.drinksInFridge);
this.drinksInFridge -= change;
this.checkRep();
return { drinksTakenOrAdded: change, drinksLeftInFridge: this.drinksInFridge };
}
}
loadfridge.ts
import assert from 'assert';
import { Worker, isMainThread, parentPort } from 'worker_threads';
import { DrinksFridge, FridgeResult } from './drinksfridge.js';
//
// Create and use a drinks fridge.
//
/** Runs on the main thread. */
function main() {
const worker = new Worker('./dist/loadfridge.js');
worker.addListener('message', (result: FridgeResult) => {
console.log('result from worker', result);
});
worker.postMessage(-42);
worker.postMessage(2);
// abruptly end the program, including the worker, after a short time
setTimeout(() => process.exit(0), 1000);
}
/** Runs in a worker. */
function worker() {
assert(parentPort);
new DrinksFridge(parentPort).start();
}
if (isMainThread) {
main();
} else {
worker();
}
server.ts
import express, { Request, Response } from 'express';
import { timeout } from './timeout.js';
import { StatusCodes } from 'http-status-codes';
import asyncHandler from 'express-async-handler';
const app = express();
const PORT = 8000;
app.listen(PORT);
console.log('now listening at http://localhost:' + PORT);
// GET /echo?greeting=<string>
//
// response is a greeting including <string>
app.get('/echo', (request: Request, response: Response) => {
const greeting = request.query['greeting'];
response
.status(StatusCodes.OK)
.type('text')
.send(greeting + ' to you too!');
});
// GET /wait
//
// waits for 5 seconds before finishing response
app.get('/wait', async (request: Request, response: Response) => {
await timeout(5000);
response
.status(StatusCodes.OK)
.type('text')
.send('done');
});
// GET /bad
//
// always produces an error output
app.get('/bad', (request: Request, response: Response) => {
throw new Error('oof');
});
// GET /wait-bad
//
// waits 1 second, then produces an error output
app.get('/wait-bad', asyncHandler(async (request: Request, response: Response) => {
await timeout(1000);
throw new Error('oof');
}));