rhizome/src/example-app.ts

116 lines
3.5 KiB
TypeScript
Raw Normal View History

2024-12-21 21:16:18 -06:00
// We can start to use deltas to express relational data in a given context
import express from "express";
import { bindPublish, } from "./pub-sub";
2024-12-22 09:13:44 -06:00
import { deltasAccepted, deltasProposed, runDeltas } from "./deltas";
import { Entity } from "./object-layer";
import { Collection } from "./collection-layer";
2024-12-21 21:16:18 -06:00
import { bindReply, runRequestHandlers } from "./request-reply";
2024-12-22 09:13:44 -06:00
import { askAllPeersForDeltas, subscribeToSeeds } from "./peers";
2024-12-21 21:16:18 -06:00
import { ENABLE_HTTP_API, HTTP_API_ADDR, HTTP_API_PORT } from "./config";
// As an app we want to be able to write and read data.
// The data is whatever shape we define it to be in a given context.
// So we want access to an API that is integrated with our declarations of
// e.g. entities and their properties.
// This implies at least one layer on top of the underlying primitive deltas.
type UserProperties = {
id?: string;
name: string;
nameLong?: string;
email?: string;
age: number;
};
class Users {
2024-12-22 09:13:44 -06:00
db = new Collection();
2024-12-21 21:16:18 -06:00
create(properties: UserProperties): Entity {
// We provide undefined for the id, to let the database generate it
// This call returns the id
const user = this.db.put(undefined, properties);
console.log(`Users.create(${user.id}, ${JSON.stringify(properties)}`);
return user;
}
upsert(properties: UserProperties): Entity {
const user = this.db.put(properties.id, properties);
console.log(`Users.upsert(${user.id}, ${JSON.stringify(properties)}`);
return user;
}
getOne(id: string): Entity | undefined {
return this.db.get(id);
}
getIds(): string[] {
return this.db.getIds();
}
}
(async () => {
2024-12-22 09:13:44 -06:00
const users = new Users();
2024-12-21 21:16:18 -06:00
2024-12-22 09:13:44 -06:00
const app = express()
2024-12-21 21:16:18 -06:00
app.get("/ids", (req: express.Request, res: express.Response) => {
res.json({ ids: users.getIds()});
});
2024-12-22 09:13:44 -06:00
app.get("/deltas", (req: express.Request, res: express.Response) => {
// TODO: streaming
res.json(deltasAccepted);
});
app.get("/deltas/count", (req: express.Request, res: express.Response) => {
// TODO: streaming
res.json(deltasAccepted.length);
});
2024-12-21 21:16:18 -06:00
if (ENABLE_HTTP_API) {
app.listen(HTTP_API_PORT, HTTP_API_ADDR, () => {
console.log(`HTTP API bound to http://${HTTP_API_ADDR}:${HTTP_API_PORT}`);
});
}
await bindPublish();
await bindReply();
runDeltas();
runRequestHandlers();
2024-12-22 09:13:44 -06:00
await new Promise((resolve) => setTimeout(resolve, 500));
2024-12-21 21:16:18 -06:00
subscribeToSeeds();
2024-12-22 09:13:44 -06:00
await new Promise((resolve) => setTimeout(resolve, 500));
askAllPeersForDeltas();
await new Promise((resolve) => setTimeout(resolve, 1000));
2024-12-21 21:16:18 -06:00
2024-12-22 09:13:44 -06:00
setInterval(() => {
console.log('deltasProposed count', deltasProposed.length,
'deltasAccepted count', deltasAccepted.length);
}, 5000)
2024-12-21 21:16:18 -06:00
const taliesin = users.upsert({
2024-12-22 09:13:44 -06:00
// id: 'taliesin-1',
2024-12-21 21:16:18 -06:00
name: 'Taliesin',
nameLong: 'Taliesin (Ladd)',
age: Math.floor(Math.random() * 1000)
});
2024-12-22 09:13:44 -06:00
users.db.onUpdate((u: Entity) => {
console.log('User updated:', u);
});
users.db.onCreate((u: Entity) => {
console.log('New user!:', u);
2024-12-21 21:16:18 -06:00
});
// TODO: Allow configuration regarding read/write concern i.e.
// if we perform a read immediately do we see the value we wrote?
// Intuition says yes, we want that-- but how do we expose the propagation status?
const result = users.getOne(taliesin.id);
const matches: boolean = JSON.stringify(result) === JSON.stringify(taliesin);
console.log(`Result ${matches ? 'matches' : 'does not match'} expected.` +
`\n\nExpected \n${JSON.stringify(taliesin)}` +
`\nReceived\n${JSON.stringify(result)}`);
})();