Mercurial > code > home > repos > streamed-graph
annotate src/SourceGraph.ts @ 139:cf642d395be4
new simpler Patch class; fancier 'hide' view config support
author | drewp@bigasterisk.com |
---|---|
date | Mon, 08 May 2023 13:05:20 -0700 |
parents | a8939c717015 |
children |
rev | line source |
---|---|
128 | 1 import { JsonLdParser } from "jsonld-streaming-parser"; |
2 import { Parser, Store } from "n3"; | |
3 import { SubEvent } from "sub-events"; | |
139
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
4 import { Patch, PatchDirection } from "./Patch"; |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
5 |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
6 type JsonLdData = Object; |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
7 |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
8 interface CombinedPatchBody { |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
9 adds?: JsonLdData; |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
10 deletes?: JsonLdData; |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
11 } |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
12 interface CombinedPatchEvent { |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
13 patch: CombinedPatchBody; |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
14 } |
128 | 15 |
16 // Possibly-changing graph for one source. Maintains its own dataset. | |
17 // Read-only. | |
18 // | |
19 // Rename to RemoteGraph? RemoteStore? SyncedStore? PatchableGraph? | |
20 export class SourceGraph { | |
21 store: Store; // const; do not rebuild | |
22 isCurrent: boolean = false; | |
23 sourceGraphChanged: SubEvent<Patch> = new SubEvent(); | |
24 constructor(public url: string /* immutable */) { | |
25 this.store = new Store(); | |
26 } | |
27 | |
28 dispose() {} | |
29 | |
30 // Call this first, after you've subscribed to `sourceGraphChanged`. This call may | |
31 // synchronously fire change events. | |
32 // | |
33 async reloadRdf() { | |
34 const resp = await fetch(this.url); | |
139
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
35 this.clearStore(); |
128 | 36 const ctype = resp.headers.get("content-type"); |
37 if (ctype?.startsWith("text/event-stream")) { | |
38 await this.reloadEventStream(); | |
39 } else { | |
40 await this.reloadSimpleFile(resp); | |
41 } | |
42 } | |
43 | |
139
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
44 private clearStore() { |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
45 this.store.removeMatches(null, null, null, null); |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
46 } |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
47 |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
48 async makePatchFromParsed( |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
49 dir: PatchDirection, |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
50 jsonLdObj: Object | undefined |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
51 ): Promise<Patch> { |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
52 const p = new Patch(dir); |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
53 if (jsonLdObj === undefined) { |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
54 return p; |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
55 } |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
56 const parser = new JsonLdParser(); |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
57 |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
58 parser.write(JSON.stringify(jsonLdObj)); |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
59 parser.end(); |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
60 |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
61 await p.streamImport(parser); |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
62 return p; |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
63 } |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
64 |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
65 private applyPatch(p: Patch) { |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
66 if (p.isEmpty()){ |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
67 return; |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
68 } |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
69 p.applyToStore(this.store); |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
70 if (this.sourceGraphChanged.getStat().unnamed == 0) { |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
71 console.warn("no listeners to this sourceGraphChanged event"); |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
72 } |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
73 this.sourceGraphChanged.emit(p); |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
74 } |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
75 |
128 | 76 private async reloadEventStream(): Promise<void> { |
77 return new Promise((res, rej) => { | |
78 const ev = new EventSource(this.url); | |
79 | |
139
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
80 // old-style fullGraph. I now think it would be better to send plain |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
81 // adds and for this SourceGraph to emptyGraph when there's a new connection. |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
82 ev.addEventListener("fullGraph", async (ev) => { |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
83 this.clearStore(); |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
84 const p = new Patch(PatchDirection.ADD); |
128 | 85 const parser = new JsonLdParser(); |
139
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
86 parser.write(ev.data); |
128 | 87 parser.end(); |
88 | |
89 await p.streamImport(parser); | |
139
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
90 p.applyToStore(this.store); |
128 | 91 this.isCurrent = true; |
92 this.sourceGraphChanged.emit(p); | |
139
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
93 res(); |
128 | 94 }); |
139
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
95 |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
96 // this is for old-style dels-then-adds patches |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
97 ev.addEventListener("patch", async (ev) => { |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
98 // this is reentrant- patches might be able to get applied out of order! |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
99 |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
100 const patchMsg: CombinedPatchEvent = JSON.parse((ev as any).data); |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
101 |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
102 const p0 = await this.makePatchFromParsed( |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
103 PatchDirection.DEL, |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
104 patchMsg.patch.deletes |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
105 ); |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
106 const p1 = await this.makePatchFromParsed( |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
107 PatchDirection.ADD, |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
108 patchMsg.patch.adds |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
109 ); |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
110 |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
111 this.applyPatch(p0); |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
112 this.applyPatch(p1); |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
113 |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
114 this.isCurrent = true; |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
115 }); |
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
116 // here, add listeners for new-style add/del patches |
128 | 117 }); |
118 } | |
119 | |
120 private async reloadSimpleFile(resp: Response) { | |
121 const bodyText = await resp.text(); | |
139
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
122 const p = new Patch(PatchDirection.ADD); |
128 | 123 const parser = new Parser({ format: "application/trig" }); |
124 await new Promise<void>((res, rej) => { | |
125 parser.parse(bodyText, (error, quad, prefixes) => { | |
126 if (error) { | |
127 console.log("parse ~ error:", error); | |
128 rej(error); | |
129 return; | |
130 } | |
131 if (quad) { | |
139
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
132 p.quads.push(quad); |
128 | 133 } else { |
134 res(); | |
135 } | |
136 }); | |
137 }); | |
139
cf642d395be4
new simpler Patch class; fancier 'hide' view config support
drewp@bigasterisk.com
parents:
137
diff
changeset
|
138 this.applyPatch(p); |
128 | 139 this.isCurrent = true; |
140 } | |
141 | |
142 quadCount(): number { | |
143 return this.store.countQuads(null, null, null, null); | |
144 } | |
145 } |