Changeset - 094e6b84b291
[Not reviewed]
default
0 4 0
drewp@bigasterisk.com - 20 months ago 2023-05-29 20:20:46
drewp@bigasterisk.com
logging and refactor
4 files changed with 52 insertions and 35 deletions:
0 comments (0 inline, 0 general)
light9/web/AutoDependencies.ts
Show inline comments
 
@@ -30,12 +30,14 @@ export class AutoDependencies {
 
  handlerStack: Handler[];
 
  constructor() {
 
    // tree of all known Handlers (at least those with non-empty
 
    // patterns). Top node is not a handler.
 
    this.handlers = new Handler(null, "root");
 
    this.handlerStack = [this.handlers]; // currently running
 
    log("window.ad");
 
    (window as any).ad = this;
 
  }
 

	
 
  runHandler(func: HandlerFunc, label: string) {
 
    // what if we have this func already? duplicate is safe?
 
    if (label == null) {
 
      throw new Error("missing label");
 
@@ -50,44 +52,53 @@ export class AutoDependencies {
 
    }
 
    //console.time("handler #{label}")
 
    // todo: this may fire 1-2 times before the
 
    // graph is initially loaded, which is a waste. Try deferring it if we
 
    // haven't gotten the graph yet.
 
    this._rerunHandler(h, /*patch=*/ undefined);
 
    log(`new handler ${label} ran first time and requested ${h.patterns.length} pats`);
 
  }
 
  //console.timeEnd("handler #{label}")
 
  //@_logHandlerTree()
 

	
 
  _rerunHandler(handler: Handler, patch?: Patch) {
 
    handler.patterns = [];
 
    this.handlerStack.push(handler);
 
    try {
 
      if (handler.func === null) {
 
        throw new Error("tried to rerun root");
 
      }
 
      handler.func(patch);
 
    } catch (e) {
 
      log("error running handler: ", e);
 
      this.graphError.emit(String(e));
 
    } finally {
 
      // assuming here it didn't get to do all its queries, we could
 
      // add a *,*,*,* handler to call for sure the next time?
 
      // log('done. got: ', handler.patterns)
 
      this.handlerStack.pop();
 
    }
 
  }
 
  // handler might have no watches, in which case we could forget about it
 
  logHandlerTree() {
 
    log("handler tree:");
 
    var prn = function (h: Handler, depth: number) {
 
      let indent = "";
 
      for (let i = 0; i < depth; i++) {
 
        indent += "  ";
 
    const shorten = (x: Term | null) => {
 
      if (x === null) {
 
        return "null";
 
      }
 
      if (!Util.isNamedNode(x)) {
 
        return x.value;
 
      }
 
      log(`${indent} \"${h.label}\" ${h.patterns.length} pats`);
 
      Array.from(h.innerHandlers).map((c: any) => prn(c, depth + 1));
 
      return this.graph.shorten(x as NamedNode);
 
    };
 
    prn(this.handlers, 0);
 

	
 
    var prn = (h: Handler, indent: string) => {
 
      log(`${indent} 🤝 handler "${h.label}" ${h.patterns.length} pats`);
 
      for (let pat of h.patterns) {
 
        log(`${indent}   ⣝ s=${shorten(pat.subject)} p=${shorten(pat.predicate)} o=${shorten(pat.object)}`);
 
      }
 
      Array.from(h.innerHandlers).map((c: any) => prn(c, indent + "    "));
 
    };
 
    prn(this.handlers, "");
 
  }
 

	
 
  _handlerIsAffected(child: Handler, patchSubjs: Set<string>) {
 
    if (patchSubjs === null) {
 
      return true;
 
    }
light9/web/RdfdbSyncedGraph.ts
Show inline comments
 
import debug from "debug";
 
import { html, LitElement, css } from "lit";
 
import { LitElement, css, html } from "lit";
 
import { customElement, property } from "lit/decorators.js";
 
import { NamedNode } from "n3";
 
import { Patch } from "./patch";
 
import { SyncedGraph } from "./SyncedGraph";
 

	
 
const log = debug("syncedgraph-el");
 

	
 
// todo: consider if this has anything to contribute:
 
// https://github.com/webcomponents-cg/community-protocols/blob/main/proposals/context.md
 
let setTopGraph: (sg: SyncedGraph) => void;
 
(window as any).topSyncedGraph = new Promise<SyncedGraph>((res, rej) => {
 
  setTopGraph = res;
 
});
 

	
 
// Contains a SyncedGraph,
 
// displays a little status box,
 
// and emits 'changed' events with the graph and latest patch when it changes
 
// Contains a SyncedGraph. Displays as little status box.
 
// Put one element on your page and use getTopGraph everywhere.
 
@customElement("rdfdb-synced-graph")
 
export class RdfdbSyncedGraph extends LitElement {
 
  @property() graph: SyncedGraph;
 
  @property() status: string;
 
  @property() testGraph = false;
 
  static styles = [
 
@@ -34,36 +24,38 @@ export class RdfdbSyncedGraph extends Li
 
    `,
 
  ];
 
  render() {
 
    return html`graph: ${this.status}`;
 
  }
 

	
 
  onClear() {
 
    console.log("reset");
 
  }
 

	
 
  constructor() {
 
    super();
 
    this.status = "startup";
 
    const prefixes = new Map<string, string>([
 
      ["", "http://light9.bigasterisk.com/"],
 
      ["dev", "http://light9.bigasterisk.com/device/"],
 
      ["rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"],
 
      ["rdfs", "http://www.w3.org/2000/01/rdf-schema#"],
 
      ["xsd", "http://www.w3.org/2001/XMLSchema#"],
 
    ]);
 
    this.graph = new SyncedGraph(
 
      this.testGraph ? null : "/rdfdb/api/syncedGraph",
 
      this.testGraph ? "unused" : "/rdfdb/api/syncedGraph",
 
      prefixes,
 
      (s: string) => {
 
        this.status = s;
 
      },
 
      this.onClear.bind(this)
 
      }
 
    );
 
    setTopGraph(this.graph);
 
  }
 
}
 

	
 
// todo: consider if this has anything to contribute:
 
// https://github.com/webcomponents-cg/community-protocols/blob/main/proposals/context.md
 
let setTopGraph: (sg: SyncedGraph) => void;
 
(window as any).topSyncedGraph = new Promise<SyncedGraph>((res, rej) => {
 
  setTopGraph = res;
 
});
 

	
 
export async function getTopGraph(): Promise<SyncedGraph> {
 
  const s = (window as any).topSyncedGraph;
 
  return await s;
 
}
light9/web/SyncedGraph.ts
Show inline comments
 
@@ -28,14 +28,12 @@ export class SyncedGraph {
 

	
 
  constructor(
 
    // The /syncedGraph path of an rdfdb server.
 
    patchSenderUrl: string,
 
    // prefixes can be used in Uri(curie) calls. This mapping may grow during loadTrig calls.
 
    public prefixes: Map<string, string>,
 
    // called if we clear the graph
 
    private clearCb: any
 
    private setStatus: (status: string) => void
 
  ) {
 
    this.prefixFuncs = this.rebuildPrefixFuncs(prefixes);
 
    this.graph = new N3.Store();
 
    this.autoDeps = new AutoDependencies(this);
 
    this.clearGraph();
 
@@ -58,15 +56,12 @@ export class SyncedGraph {
 
  _clearGraphOnNewConnection() {
 
    // must not try send a patch to the server
 

	
 
    log("clearGraphOnNewConnection");
 
    this.clearGraph();
 
    log("clearGraphOnNewConnection done");
 
    if (this.clearCb != null) {
 
      return this.clearCb();
 
    }
 
  }
 

	
 
  private rebuildPrefixFuncs(prefixes: Map<string, string>) {
 
    const p = Object.create(null);
 
    prefixes.forEach((v: string, k: string) => (p[k] = v));
 

	
 
@@ -168,12 +163,13 @@ export class SyncedGraph {
 
    // This is the only method that writes to this.graph!
 
    log("patch from server [1]");
 
    this.cachedFloatValues.clear();
 
    this.cachedUriValues.clear();
 
    patch.applyToGraph(this.graph);
 
    log("applied patch locally", patch.summary());
 
    log('dump:\n'+patch.dump());
 
    this.autoDeps.graphChanged(patch);
 
  }
 

	
 
  getObjectPatch(s: N3.NamedNode, p: N3.NamedNode, newObject: N3.Quad_Object | null, g: N3.NamedNode): Patch {
 
    // make a patch which removes existing values for (s,p,*,c) and
 
    // adds (s,p,newObject,c). Values in other graphs are not affected.
light9/web/patch.ts
Show inline comments
 
@@ -70,12 +70,30 @@ export class Patch {
 
  }
 

	
 
  summary(): string {
 
    return "-" + this.dels.length + " +" + this.adds.length;
 
  }
 

	
 
  dump(): string {
 
    const lines: string[] = [];
 
    const s = (term: N3.Term): string => {
 
      if (term.termType=='Literal') return term.value;
 
      if (term.termType=='NamedNode') return term.value
 
        .replace("http://light9.bigasterisk.com/effect/","effect:")
 
        .replace("http://light9.bigasterisk.com/",":")
 
        .replace("http://www.w3.org/2000/01/rdf-schema#","rdfs:")
 
        .replace("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "rdf:")
 
      if (term.termType=='BlankNode') return '_:'+term.value;
 
      return term.id;
 
    };
 
    this.dels.forEach((d) => lines.push("- " + s(d.subject) + " " + s(d.predicate) + " " + s(d.object)));
 
    this.adds.forEach((d) => lines.push("+ " + s(d.subject) + " " + s(d.predicate) + " " + s(d.object)));
 
    lines.sort();
 
    return lines.join("\n");
 
  }
 

	
 
  async toJsonPatch(): Promise<string> {
 
    return new Promise((res, rej) => {
 
      const out: SyncgraphPatchMessage = { patch: { adds: "", deletes: "" } };
 

	
 
      const writeDels = (cb1: () => void) => {
 
        const writer = new Writer({ format: "N-Quads" });
0 comments (0 inline, 0 general)