Skip to content

Commit 2a9c497

Browse files
committed
feat(rune): documentation, serialization
1 parent 0b713ad commit 2a9c497

File tree

9 files changed

+196
-67
lines changed

9 files changed

+196
-67
lines changed

docs/backend.md

Lines changed: 178 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,52 +2,196 @@
22

33
> TODO: update
44
5+
# Cyb local backend
6+
7+
Cyb plays singinficat role in cyber infrastructure. The app reconstruct self-sufficient backend+frontend pattern inside the browser.
8+
In big view app consist from 3 parts:
9+
510
```mermaid
611
graph TD;
12+
App["Frontend\n(main thread)"]-.proxy.->Backend["Backend\n(shared worker)"];
13+
App-.proxy.->Db["Graph Db\n(shared worker)"];
14+
Backend-.proxy.->Db;
15+
App<-.message\nchannels.->Backend;
16+
```
717

8-
subgraph frontend["frontend(main thread)"]
9-
App["Frontend"]-->Hook["useBackend()"];
10-
Hook-->methods("startSync()\nloadIpfs()\n...\nisReady\nipfsError\n...");
11-
Hook-.broadcast channel\n(any worker).->reducer["redux(state)"]
12-
Hook-.save history from app.->defferedDbApiFront[/"DefferedDbApi(proxy)"/]
13-
Hook--osenseApi["senseApi"];
14-
Hook--oipfsApiFront[/"ipfsApi(proxy)"/];
15-
senseApi--odbApi[/"dbApi(proxy)"/];
16-
end
18+
To reduce overload of main thread we have created 2 separate shared workers, where all the stuff is hosted. Bi-interraction between all layers occurs using proxy(comlink abstraction) or directly using broadcast channels.
1719

18-
dbApi<-.message channel.->dbWorker["dbApi"];
19-
subgraph dbWorkerGraph["cyb~db(worker)"]
20-
dbWorker<-.bindings(webApi).->cozodb{{"CozoDb(wasm)"}}
21-
end
20+
## Db
2221

23-
defferedDbApiFront-.->defferedDbApi;
24-
ipfsApiFront<-.->ipfsApi;
25-
subgraph backgroundWorker["cyb~backend(worker)"]
26-
subgraph sync["sync service"]
27-
ipfsNode["ipfs node"];
28-
links;
29-
transactions;
22+
Db worker is pretty simple it it's host only local relational-graph-vector database - [[cozo]].
23+
Cozo provide bazing fast access to brain and ipfs data in relational form and also in vector format, processing by [ml]embedder.
24+
25+
```mermaid
26+
graph TD;
27+
subgraph rune["cozo db"]
28+
db_meta_orm[["meta orm"]]-.->db;
3029
end
31-
sync--oparticleResolver[["Particle resolver"]]
32-
particleResolver--oqueue;
33-
particleResolver--odbProxyWorker;
34-
sync--oipfsApi;
35-
sync--odbProxyWorker[/"dbApi(proxy)"/];
36-
defferedDbApi[["defferedDbApi"]]-->dbProxyWorker;
37-
queue-->defferedDbApi;
38-
ipfsApi--oqueue[["queue"]];
39-
ipfsApi--onode["node"];
40-
queue--balancer-->node;
41-
node--embedded-->helia;
42-
node--rpc-->kubo;
43-
node--embedded-->js-ipfs;
30+
```
31+
32+
### Entities
33+
34+
- brain:
35+
- particles
36+
- embeddings
37+
- links
38+
- transactions
39+
- community
40+
- sense:
41+
42+
- sync items + update status
43+
44+
- system:
45+
- config
46+
- queue messages
47+
48+
## Backend
49+
50+
Backend worker is more complicated it contains significant elements of cyb architecture:
51+
52+
```mermaid
53+
graph TD;
54+
subgraph Backend["backend(shared worker)"]
55+
4456
subgraph ipfs["ipfs implementations"]
4557
helia;
4658
kubo;
4759
js-ipfs;
4860
end
4961
50-
dbProxyWorker<-.message channel.->dbWorker
62+
subgraph queues["message brokers"]
63+
ipfs_queue["ipfs load balancer"];
64+
queue["data processing queue aka bus"];
65+
end
66+
67+
subgraph rune["rune"]
68+
vm["virtual machine"]--ovm_bingen{{"cyb bindings"}};
69+
end
70+
71+
subgraph sense["sense"]
72+
link_sync["link sync"];
73+
msg_sync["message sync"];
74+
swarm_sync["swarm sync"];
75+
end
76+
77+
subgraph ml["ML transformers"]
78+
feature_extractor["embedder"];
79+
end
80+
81+
end
82+
```
83+
84+
### Ipfs module
85+
86+
Represented with IpfsApi at frontend layer, but also have direct access for some edge cases
87+
88+
- Uses module that encapsulate different Ipfs implementations(kubo, helia, js-ipfs(obsolete))
89+
- cache content(local storage & cozo)
90+
- preserve redundancy
91+
- Ipfs queue, process all requests to ipfs, prioritize, cancel non-actual requests and organize content pipeline
92+
- responsible for:
93+
- ipfs load balancing(limit of requests)
94+
- request prioritizing(actual requests first)
95+
- fault processing(switch fetch policy)
96+
- post processing(**inline rune vm** into pipeline)
97+
98+
```mermaid
99+
graph LR
100+
user(ipfsApi\nenqueue particle) --> q[["queue\n(balancer)"]] --> node[/"ipfs"/] -- found --> rune[rune vm] -- mutation | content --> cache["cache"] --> app(app\ncontent)
101+
node -. not found\n(retry | error) .-> q
102+
```
103+
104+
## Bus
105+
106+
Represented with some helpers and used for cases when blaancer is needed, some services not initialized yet(deffered actions), or long calculations is requered(ml inference, ipfs requests):
107+
108+
- particle, request ipfs, save; calc embedding
109+
- link, deffered save
110+
- message persistence is protected by db store
111+
112+
```mermaid
113+
graph TD;
114+
sender{{"enqueue(...)"}} -.message bus.-> bus
115+
subgraph task["task manager"]
116+
bus[["queue listener"]];
117+
118+
bus-.task.->db("store\ndata")--odb1["dbApi"];
119+
bus-.task.->ml("calculate\nembedding")--oml1["mlApi"];
120+
bus-.task.->ipfs("request ipfs\nlow-priority")--oi["ipfsApi"]
121+
end
122+
```
123+
124+
## Sense
125+
126+
Represented by SenseApi + subscription to broadcast channel at fronted layer. Provide continious update of cyberlinks related to my brain and my swarm, recieving on chain messages etc.:
127+
128+
- Particles service (pooling)
129+
- Transactions service (pooling + websocket)
130+
- My friends service (pooling)
131+
- Ipfs service(pooling)
132+
133+
All data and update status is stored into db, when some new data is recieved that triggers notification for frontendю
134+
135+
```mermaid
136+
graph TD;
137+
db[["dbApi"]];
138+
bus[["particle queue"]];
139+
140+
subgraph sense["sync service"]
141+
notification("notification service")
142+
143+
particles[["particle service"]]--onotification;
144+
transactions[["transaction service"]]--onotification;
145+
myfriend[["my friends service"]]--onotification;
146+
147+
particles -.loop.-> particles;
148+
transactions -.loop.-> transactions;
149+
myfriend -.loop.-> myfriend;
150+
end
151+
152+
153+
subgraph blockchain["blockchain"]
154+
lcd[["lcd"]]
155+
websockets("websockets")
156+
indexer[["indexer"]]
157+
end
158+
159+
subgraph app["frontend"]
160+
redux["redux"]
161+
sender{{"senseApi"}};
162+
end
163+
164+
notification -.message.-> redux;
165+
sender -.proxy.-> db;
166+
sense -.proxy.-> db;
167+
sense -.message.-> bus;
168+
bus -.proxy.-> db;
169+
170+
sense <-.request\nsubscriptin.->blockchain;
171+
172+
```
173+
174+
## Rune
175+
176+
Rune VM execution is pipelined thru special abstraction called entrypoints. VM have bindings to all app parts: DB, transformers, signer, blockchain api, ipfs and also includes context of the entrypoint.(see. [[scripting]] for detailed description).
177+
178+
## ML transformers
179+
180+
Represented my mlApi. Uses inference from local ML models hosted inside browser.
181+
182+
- future extractor. BERT-like model to trnsform text-to-embeddings.
183+
184+
```mermaid
185+
graph TD;
186+
subgraph ml["transformers"]
187+
embedder["embedder"];
188+
end
189+
190+
subgraph dbApi["dbApi"]
191+
db[["DB"]];
51192
end
193+
mlApi["mlApi"];
52194
195+
mlApi--odb;
196+
mlApi--oembedder;
53197
```

src/pages/robot/Soul/Soul.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,15 +104,13 @@ function Soul() {
104104
outputRef.current?.scrollIntoView({ behavior: 'smooth' });
105105

106106
addToLog([`🚧 Execute your '${funcName}'.`]);
107-
console.log('---------test', code, funcName, funcParams);
108107
rune
109108
?.run(code, {
110109
execute: true,
111110
funcName,
112111
funcParams,
113112
})
114113
.then((result) => {
115-
console.log('---------test result', result);
116114
const isOk = !result.diagnosticsOutput && !result.error;
117115
highlightErrors(codeMirrorRef!.current, result.diagnostics, styles);
118116
if (!isOk) {

src/services/backend/channels/BackendQueueChannel/BackendQueueChannel.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,10 @@ class BackendQueueChannelListener {
5757
private async saveParticles(content: IPFSContent) {
5858
const dbApi = await this.getDeffredDbApi();
5959
const entity = mapParticleToEntity(content);
60-
await dbApi.putParticles(entity);
61-
await enqueueParticleEmbeddingMaybe(content);
60+
const result = await dbApi.putParticles(entity);
61+
if (result.ok) {
62+
await enqueueParticleEmbeddingMaybe(content);
63+
}
6264
// console.log('---saveParticles done', content);
6365
}
6466

src/services/backend/services/DbApi/DbApi.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ class DbApiWrapper {
159159
const entitites = dtoListToEntity(
160160
Array.isArray(particles) ? particles : [particles]
161161
);
162-
await this.db!.executePutCommand('particle', entitites);
162+
return this.db!.executePutCommand('particle', entitites);
163163
}
164164

165165
public async getParticlesRaw(fields: string[]) {

src/services/backend/services/sync/services/ParticlesResolverQueue/ParticlesResolverQueue.ts

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ class ParticlesResolverQueue {
103103

104104
deps.getEmbeddingInstance$?.subscribe((f) => {
105105
this.getEmbedding = f;
106-
console.log('------PRQ getEmbedding SET', typeof f);
107106
// if embedding function is provided, retriger the queue
108107
if (this.queue.size > 0) {
109108
this._syncQueue$.next(this.queue);
@@ -136,23 +135,6 @@ class ParticlesResolverQueue {
136135
}
137136

138137
await enqueueParticleEmbeddingMaybe(result);
139-
// const [contentType, data] = await getContentToEmbed(result);
140-
141-
// if (contentType === 'text') {
142-
// if (this.canEmbed && data) {
143-
// this.saveEmbedding(id, data);
144-
// } else {
145-
// this.enqueue([
146-
// {
147-
// id,
148-
// data,
149-
// priority: QueuePriority.LOW,
150-
// jobType: SyncQueueJobType.embedding,
151-
// },
152-
// ]);
153-
// }
154-
// }
155-
156138
return true;
157139
})
158140
.catch(() => false);
@@ -166,7 +148,6 @@ class ParticlesResolverQueue {
166148
const vec = await this.getEmbedding!(text);
167149

168150
const result = await this.db!.putEmbedding(cid, vec);
169-
// console.log('------saveEmbedding ', vec, text, result.ok);
170151
}
171152

172153
return true;

src/services/backend/workers/background/worker.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,9 @@ const createBackgroundWorkerApi = () => {
111111
const progressItem = {
112112
status,
113113
message,
114-
done: ['done', 'ready', 'error'].some((s) => s === status),
114+
done: ['ready', 'error'].some((s) => s === status),
115115
};
116-
console.log('progress_callback', name, progressData);
116+
// console.log('progress_callback', name, progressData);
117117

118118
if (progress) {
119119
progressItem.progress = Math.round(progress);
@@ -232,7 +232,6 @@ const createBackgroundWorkerApi = () => {
232232
};
233233

234234
const getEmbedding = async (text: string) => {
235-
console.log('-------getEmbb', typeof mlInstances.featureExtractor);
236235
const output = await mlInstances.featureExtractor(text, {
237236
pooling: 'mean',
238237
normalize: true,

src/services/scripting/rune/default/particle.rn

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ pub async fn personal_processor(cid, content_type, content) {
100100
return content_result(content.replace(`${token_name}@NOW`, `Current ${token_name} price is ${json[token_name][vs_currency]} ${vs_currency}`))
101101
}
102102

103-
// anything else - pass as is
104-
pass()
103+
// anything else
104+
content = content.replace("хуй", "🌽").replace("хуя", "🌽").replace("хуе", "🌽");
105+
106+
content_result(content)
105107
}

src/services/scripting/rune/runtime.rn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub fn cid_result(cid) {
1111
}
1212

1313
pub fn content_result(content) {
14+
// #{ "content": json::to_string(content)?, "action": "content_result" }
1415
#{ "content": content, "action": "content_result" }
1516
}
1617

src/utils/string.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,19 @@ export function replaceQuotes(string: string) {
99
export function serializeString(input: string): string {
1010
return input
1111
.replace(/\\/g, '\\\\') // Escape backslashes
12-
.replace(/"/g, '\\"') // Escape double quotes
12+
.replace(/"/g, "\\''") // Escape double quotes
1313
.replace(/'/g, "\\'") // Escape single quotes
1414
.replace(/\n/g, '\\n') // Escape newlines
15-
.replace(/\r/g, '\\r'); // Escape carriage returns
15+
.replace(/\r/g, '\\r') // Escape carriage returns
16+
.replace(/#/g, '\\!!'); // Escape - that's comment in cozo
1617
}
1718

1819
export function deserializeString(serialized: string): string {
1920
return serialized
2021
.replace(/\\r/g, '\r') // Unescape carriage returns
2122
.replace(/\\n/g, '\n') // Unescape newlines
2223
.replace(/\\'/g, "'") // Unescape single quotes
23-
.replace(/\\"/g, '"') // Unescape double quotes
24-
.replace(/\\\\/g, '\\'); // Unescape backslashes
24+
.replace(/\\''/g, '"') // Unescape double quotes
25+
.replace(/\\\\/g, '\\') // Unescape backslashes
26+
.replace(/\\!!/g, '#'); // Unescape # cozo comment
2527
}

0 commit comments

Comments
 (0)