Skip to content

Commit

Permalink
added logic to emit signals and update store accordingly
Browse files Browse the repository at this point in the history
  • Loading branch information
matthme committed Nov 4, 2024
1 parent 6ceb6fb commit 3764df2
Show file tree
Hide file tree
Showing 8 changed files with 432 additions and 132 deletions.
234 changes: 169 additions & 65 deletions dnas/generic_dna/zomes/coordinator/generic_zome/src/api.rs

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions dnas/generic_dna/zomes/coordinator/generic_zome/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,40 @@ pub fn init() -> ExternResult<InitCallbackResult> {
Ok(InitCallbackResult::Pass)
}

#[derive(Serialize, Deserialize, Debug)]
pub struct NodeLink {
src: NodeId,
dst: NodeId,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Thing {
pub id: ActionHash,
pub content: String,
pub creator: AgentPubKey,
pub created_at: Timestamp,
pub updated_at: Option<Timestamp>,
}

/// Don't modify this enum if you want the scaffolding tool to generate appropriate signals for your entries and links
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "type")]
pub enum Signal {
ThingCreated {
thing: Thing,
},
ThingUpdated {
thing: Thing,
},
ThingDeleted {
id: ActionHash,
},
LinksCreated {
links: Vec<NodeLink>,
},
LinksDeleted {
links: Vec<NodeLink>,
},
LinkCreated {
action: SignedActionHashed,
link_type: LinkTypes,
Expand Down
8 changes: 8 additions & 0 deletions dnas/generic_dna/zomes/integrity/generic_zome/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ pub enum LinkTypes {
ToAnchor,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(tag = "type", content = "id")]
pub enum NodeId {
Agent(AgentPubKey),
Anchor(String),
Thing(ActionHash),
}

// Validation you perform during the genesis process. Nobody else on the network performs it, only you.
// There *is no* access to network calls in this callback
#[hdk_extern]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use hdi::prelude::*;

use crate::NodeId;

#[derive(Serialize, Deserialize, SerializedBytes, Debug)]
pub struct LinkTagContent {
pub tag: Option<Vec<u8>>,
Expand All @@ -11,7 +13,7 @@ pub struct LinkTagContent {
// For links to anchors we store the anchor string as well to be able
// to retrieve the anchor string that they're pointing to directly
// from the link
pub anchor: Option<String>,
pub target_node_id: NodeId,
}

pub fn serialize_link_tag(link_tag_content: LinkTagContent) -> ExternResult<Vec<u8>> {
Expand Down
130 changes: 120 additions & 10 deletions lib/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export * from "./types";

import {
derived,
get,
Readable,
Unsubscriber,
Writable,
Expand All @@ -47,11 +48,12 @@ export type AsyncStatus<T> =

const DEFAULT_POLLING_FREQUENCY = 10000;
export class NodeStore {
client: SimpleHolochain;
nodeId: NodeId;
private client: SimpleHolochain;
private nodeId: NodeId;

private subscribers: number[] = [];
private nodeStore: Writable<AsyncStatus<NodeStoreContent>> = writable({

nodeStore: Writable<AsyncStatus<NodeStoreContent>> = writable({
status: "pending",
});

Expand Down Expand Up @@ -98,16 +100,22 @@ export class NodeStore {
);

let linkedNodeIds = await this.client.getAllLinkedNodeIds(this.nodeId);
console.log("@pollStore: Linked node ids: ", linkedNodeIds);

if (this.nodeId.type === "Thing") {
const latestThing = await this.client.getThing(this.nodeId.id);
if (!latestThing) {
this.nodeStore.set({
status: "error",
error: `Failed to get Thing record for thing with id ${encodeHashToBase64(
this.nodeId.id
)}`,
});
const currentThing = get(this.nodeStore);
// If it is already complete, we assume that the Thing arrived through emit_signal
// otherwise we set it to "error"
if (currentThing.status !== "complete") {
this.nodeStore.set({
status: "error",
error: `Failed to get Thing record for thing with id ${encodeHashToBase64(
this.nodeId.id
)}`,
});
}
return;
}
const content: NodeContent = {
Expand Down Expand Up @@ -182,6 +190,89 @@ export class SimpleHolochain {
this.roleName = roleName;
this.zomeName = zomeName;
// TODO set up signal listener. Potentially emit signal to conductor
this.zomeClient.onSignal(async (signal) => {
switch (signal.type) {
case "ThingCreated": {
// ignore since things are probably mostly discovered through anchors and then the thing will be polled
const nodeStore = this.nodeStore({
type: "Thing",
id: signal.thing.id,
});
nodeStore.nodeStore.update((content) => {
if (content.status === "complete") {
content.value.content.content = signal.thing;
return content;
}
return {
status: "complete",
value: {
content: { type: "Thing", content: signal.thing },
linkedNodeIds: [],
},
};
});
break;
}
case "ThingUpdated": {
const nodeStore = this.nodeStore({
type: "Thing",
id: signal.thing.id,
});
nodeStore.nodeStore.update((content) => {
if (content.status === "complete") {
content.value.content.content = signal.thing;
return content;
}
return {
status: "complete",
value: {
content: { type: "Thing", content: signal.thing },
linkedNodeIds: [],
},
};
});
break;
}
case "ThingDeleted": {
break;
}
case "LinksCreated": {
console.log("Got LINKS_CREATED SIGNAL!!");

signal.links.forEach(({ src, dst }) => {
const nodeStore = this.nodeStore(src);
nodeStore.nodeStore.update((store) => {
if (store.status === "complete") {
const currentLinkedNodeIds = store.value.linkedNodeIds;
const nodeExists = currentLinkedNodeIds.find((nodeId) =>
areNodesEqual(dst, nodeId)
);
if (nodeExists) return store;
currentLinkedNodeIds.push(dst);
store.value.linkedNodeIds = currentLinkedNodeIds;
}
return store;
});
});
break;
}
case "LinksDeleted": {
signal.links.forEach(({ src, dst }) => {
const nodeStore = this.nodeStore(src);
nodeStore.nodeStore.update((store) => {
if (store.status === "complete") {
const currentLinkedNodeIds = store.value.linkedNodeIds;
store.value.linkedNodeIds = currentLinkedNodeIds.filter(
(nodeId) => !areNodesEqual(dst, nodeId)
);
}
return store;
});
});
break;
}
}
});
}

static async connect(options: AppWebsocketConnectionOptions = {}) {
Expand All @@ -194,7 +285,7 @@ export class SimpleHolochain {
return new SimpleHolochain(client, zomeClient);
}

nodeStore(nodeId: NodeId): NodeStore {
private nodeStore(nodeId: NodeId): NodeStore {
switch (nodeId.type) {
case "Agent": {
const agentId = encodeHashToBase64(nodeId.id);
Expand All @@ -219,6 +310,14 @@ export class SimpleHolochain {
}
}

subscribeToNode(
nodeId: NodeId,
cb: (value: AsyncStatus<NodeStoreContent>) => any
): Unsubscriber {
const nodeStore = this.nodeStore(nodeId);
return nodeStore.subscribe(cb);
}

/**
* Creates a "Thing", i.e. an arbitrary piece of content in the DHT. You are responsible
* yourself for making sure that the content adheres to the format you want
Expand Down Expand Up @@ -420,3 +519,14 @@ function linkInputToRustFormat(linkInput: LinkInput): LinkInputRust {
tag: linkInput.tag,
};
}

function areNodesEqual(nodeId_a: NodeId, nodeId_b: NodeId): boolean {
if (nodeId_a.type !== nodeId_b.type) return false;
if (nodeId_a.type === "Agent" && nodeId_b.type === "Agent")
return encodeHashToBase64(nodeId_a.id) === encodeHashToBase64(nodeId_b.id);
if (nodeId_a.type === "Thing" && nodeId_b.type === "Thing")
return encodeHashToBase64(nodeId_a.id) === encodeHashToBase64(nodeId_b.id);
if (nodeId_a.type === "Anchor" && nodeId_b.type === "Anchor")
return nodeId_a.id === nodeId_b.id;
return false;
}
Loading

0 comments on commit 3764df2

Please sign in to comment.