From f9c24f878dcfea665de0bce1f949679b878c4d15 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 8 Nov 2024 00:31:25 +0100 Subject: [PATCH] return tag as well for linked nodes --- .../zomes/coordinator/generic_zome/src/api.rs | 63 +++++++++----- lib/src/index.ts | 87 +++++++++++++------ lib/src/types.ts | 20 +++-- ui/src/holochain-app.ts | 3 +- 4 files changed, 115 insertions(+), 58 deletions(-) diff --git a/dnas/generic_dna/zomes/coordinator/generic_zome/src/api.rs b/dnas/generic_dna/zomes/coordinator/generic_zome/src/api.rs index 0bd5dac..05d053f 100644 --- a/dnas/generic_dna/zomes/coordinator/generic_zome/src/api.rs +++ b/dnas/generic_dna/zomes/coordinator/generic_zome/src/api.rs @@ -18,6 +18,12 @@ pub enum NodeContent { Thing(Thing), } +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct NodeIdAndTag { + node_id: NodeId, + tag: Option>, +} + #[derive(Serialize, Deserialize, Clone, Debug)] pub struct LinkInput { pub direction: LinkDirection, @@ -346,22 +352,22 @@ pub fn delete_thing(input: DeleteThingInput) -> ExternResult<()> { } #[hdk_extern] -pub fn get_all_linked_node_ids(node_id: NodeId) -> ExternResult> { - let mut linked_node_ids: Vec = Vec::new(); +pub fn get_all_linked_node_ids(node_id: NodeId) -> ExternResult> { + let mut linked_node_ids: Vec = Vec::new(); let linked_thing_ids = get_linked_thing_ids(node_id.clone())?; - for thing_id in linked_thing_ids { + for (thing_id, tag) in linked_thing_ids { let node = NodeId::Thing(thing_id); - linked_node_ids.push(node); + linked_node_ids.push(NodeIdAndTag { node_id: node, tag }); } let linked_anchors = get_linked_anchors(node_id.clone())?; - for anchor in linked_anchors { + for (anchor, tag) in linked_anchors { let node = NodeId::Anchor(anchor); - linked_node_ids.push(node); + linked_node_ids.push(NodeIdAndTag { node_id: node, tag }); } let linked_agents = get_linked_agents(node_id)?; - for agent in linked_agents { + for (agent, tag) in linked_agents { let node = NodeId::Agent(agent); - linked_node_ids.push(node); + linked_node_ids.push(NodeIdAndTag { node_id: node, tag }); } Ok(linked_node_ids) } @@ -375,12 +381,12 @@ pub fn get_all_linked_nodes(node_id: NodeId) -> ExternResult> { linked_nodes.push(node); } let linked_anchors = get_linked_anchors(node_id.clone())?; - for anchor in linked_anchors { + for (anchor, _) in linked_anchors { let node = NodeContent::Anchor(anchor); linked_nodes.push(node); } let linked_agents = get_linked_agents(node_id)?; - for agent in linked_agents { + for (agent, _) in linked_agents { let node = NodeContent::Agent(agent); linked_nodes.push(node); } @@ -388,37 +394,50 @@ pub fn get_all_linked_nodes(node_id: NodeId) -> ExternResult> { } #[hdk_extern] -pub fn get_linked_agents(node_id: NodeId) -> ExternResult> { +pub fn get_linked_agents(node_id: NodeId) -> ExternResult>)>> { let base = linkable_hash_from_node_id(node_id)?; let links = get_links(GetLinksInputBuilder::try_new(base, LinkTypes::ToAgent)?.build())?; Ok(links .into_iter() - .map(|l| l.target.into_agent_pub_key()) - .filter_map(|a| a) + .map(|l| { + ( + l.target.into_agent_pub_key(), + deserialize_link_tag(l.tag.0).ok(), + ) + }) + .filter(|(maybe_agent, maybe_tag)| maybe_agent.is_some() && maybe_tag.is_some()) + .map(|(agent, tag)| (agent.unwrap(), tag.unwrap().tag)) .collect()) } #[hdk_extern] -pub fn get_linked_anchors(node_id: NodeId) -> ExternResult> { +pub fn get_linked_anchors(node_id: NodeId) -> ExternResult>)>> { let base = linkable_hash_from_node_id(node_id)?; let links = get_links(GetLinksInputBuilder::try_new(base, LinkTypes::ToAnchor)?.build())?; Ok(links .into_iter() - .map(|l| deserialize_link_tag(l.tag.0).ok()) - .filter_map(|c| c) - .map(|c| anchor_string_from_node_id(c.target_node_id)) - .filter_map(|a| a) + .filter_map(|l| deserialize_link_tag(l.tag.0).ok()) + .map(|c| (anchor_string_from_node_id(c.target_node_id), c.tag)) + .filter(|(maybe_anchor, _)| maybe_anchor.is_some()) + .map(|(anchor, tag)| (anchor.unwrap(), tag)) .collect()) } +/// Returns the linked thing ids together with the link tag #[hdk_extern] -pub fn get_linked_thing_ids(node_id: NodeId) -> ExternResult> { +pub fn get_linked_thing_ids(node_id: NodeId) -> ExternResult>)>> { let base = linkable_hash_from_node_id(node_id)?; let links = get_links(GetLinksInputBuilder::try_new(base, LinkTypes::ToThing)?.build())?; Ok(links .into_iter() - .map(|l| l.target.into_action_hash()) - .filter_map(|r| r) + .map(|l| { + ( + l.target.into_action_hash(), + deserialize_link_tag(l.tag.0).ok(), + ) + }) + .filter(|(maybe_action, maybe_tag)| maybe_action.is_some() && maybe_tag.is_some()) + .map(|(action, tag)| (action.unwrap(), tag.unwrap().tag)) .collect()) } @@ -440,7 +459,7 @@ pub fn get_linked_things(node_id: NodeId) -> ExternResult> { #[derive(Serialize, Deserialize, Clone, Debug)] pub struct NodeAndLinkedIds { pub content: NodeContent, - pub linked_node_ids: Vec, + pub linked_node_ids: Vec, } #[hdk_extern] diff --git a/lib/src/index.ts b/lib/src/index.ts index 8a58106..df94114 100644 --- a/lib/src/index.ts +++ b/lib/src/index.ts @@ -23,8 +23,10 @@ import { NodeAndLinkedIds, NodeContent, NodeId, + NodeIdAndTag, NodeLink, RemoteSignalInput, + Tag, Thing, ThingId, UpdateThingInput, @@ -50,7 +52,7 @@ declare global { export type NodeStoreContent = { content: NodeContent; - linkedNodeIds: NodeId[]; + linkedNodeIds: NodeIdAndTag[]; }; export type AsyncStatus = @@ -207,8 +209,8 @@ export class SimpleHolochain { allAgentsNodeStore.subscribe((val) => { if (val.status === "complete" && val.value.content.type === "Anchor") { this.allAgents = val.value.linkedNodeIds - .filter((nodeId) => nodeId.type === "Agent") - .map((nodeId) => nodeId.id); + .filter((nodeIdAndTag) => nodeIdAndTag.node_id.type === "Agent") + .map((nodeIdAndTag) => nodeIdAndTag.node_id.id) as AgentPubKey[]; console.log( "GOT AGENTS: ", this.allAgents.map((a) => encodeHashToBase64(a)) @@ -283,16 +285,16 @@ export class SimpleHolochain { case "LinksCreated": { console.log("Got LINKS_CREATED SIGNAL!!"); - signal.links.forEach(({ src, dst }) => { + signal.links.forEach(({ src, dst, tag }) => { 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) + const nodeExists = currentLinkedNodeIds.find((nodeIdAndTag) => + areNodeAndTagEqual({ node_id: dst, tag }, nodeIdAndTag) ); if (nodeExists) return store; - currentLinkedNodeIds.push(dst); + currentLinkedNodeIds.push({ node_id: dst, tag }); store.value.linkedNodeIds = currentLinkedNodeIds; } return store; @@ -308,13 +310,13 @@ export class SimpleHolochain { break; } case "LinksDeleted": { - signal.links.forEach(({ src, dst }) => { + signal.links.forEach(({ src, dst, tag }) => { 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) + (nodeIdAndTag) => !areNodeAndTagEqual({ node_id: dst, tag }, nodeIdAndTag) ); } return store; @@ -431,13 +433,13 @@ export class SimpleHolochain { }); } else { nodeStore.nodeStore.update((store) => { - let newLinkedNodeIds: NodeId[] = []; + let newLinkedNodeIds: NodeIdAndTag[] = []; if (store.status === "complete") { newLinkedNodeIds = store.value.linkedNodeIds; } - nodeAndLinkedIds.linked_node_ids.forEach((nodeId) => { - if (!containsNodeId(newLinkedNodeIds, nodeId)) { - newLinkedNodeIds.push(nodeId); + nodeAndLinkedIds.linked_node_ids.forEach((nodeIdAndTag) => { + if (!containsNodeIdAndTag(newLinkedNodeIds, nodeIdAndTag)) { + newLinkedNodeIds.push(nodeIdAndTag); } }); return { @@ -474,13 +476,13 @@ export class SimpleHolochain { }); } else { nodeStore.nodeStore.update((store) => { - let newLinkedNodeIds: NodeId[] = []; + let newLinkedNodeIds: NodeIdAndTag[] = []; if (store.status === "complete") { newLinkedNodeIds = store.value.linkedNodeIds; } - nodeAndLinkedIds.linked_node_ids.forEach((nodeId) => { - if (!containsNodeId(newLinkedNodeIds, nodeId)) { - newLinkedNodeIds.push(nodeId); + nodeAndLinkedIds.linked_node_ids.forEach((nodeIdAndTag) => { + if (!containsNodeIdAndTag(newLinkedNodeIds, nodeIdAndTag)) { + newLinkedNodeIds.push(nodeIdAndTag); } }); return { @@ -517,13 +519,13 @@ export class SimpleHolochain { }); } else { nodeStore.nodeStore.update((store) => { - let newLinkedNodeIds: NodeId[] = []; + let newLinkedNodeIds: NodeIdAndTag[] = []; if (store.status === "complete") { newLinkedNodeIds = store.value.linkedNodeIds; } - nodeAndLinkedIds.linked_node_ids.forEach((nodeId) => { - if (!containsNodeId(newLinkedNodeIds, nodeId)) { - newLinkedNodeIds.push(nodeId); + nodeAndLinkedIds.linked_node_ids.forEach((nodeIdAndTag) => { + if (!containsNodeIdAndTag(newLinkedNodeIds, nodeIdAndTag)) { + newLinkedNodeIds.push(nodeIdAndTag); } }); return { @@ -678,7 +680,7 @@ export class SimpleHolochain { * @param src * @returns */ - async getAllLinkedNodeIds(src: NodeId): Promise { + async getAllLinkedNodeIds(src: NodeId): Promise { return this.callZome("get_all_linked_node_ids", src); } @@ -698,7 +700,9 @@ export class SimpleHolochain { * @param src * @returns */ - async getLinkedAgents(src: NodeId): Promise { + async getLinkedAgents( + src: NodeId + ): Promise<[AgentPubKey, Tag | undefined][]> { return this.callZome("get_linked_agents", src); } @@ -708,7 +712,7 @@ export class SimpleHolochain { * @param src * @returns */ - async getLinkedAnchors(src: NodeId): Promise { + async getLinkedAnchors(src: NodeId): Promise<[string, Tag | undefined][]> { return this.callZome("get_linked_anchors", src); } @@ -719,7 +723,7 @@ export class SimpleHolochain { * @param src * @returns */ - async getLinkedThings(src: NodeId): Promise { + async getLinkedThings(src: NodeId): Promise<[Thing, Tag | undefined][]> { return this.callZome("get_linked_things", src); } @@ -822,11 +826,40 @@ function areNodesEqual(nodeId_a: NodeId, nodeId_b: NodeId): boolean { return false; } -function containsNodeId(arr: NodeId[], nodeId: NodeId): boolean { +function areNodeAndTagEqual( + nodeId_a: NodeIdAndTag, + nodeId_b: NodeIdAndTag +): boolean { + if (nodeId_a.node_id.type !== nodeId_b.node_id.type) return false; + if (nodeId_a.node_id.type === "Agent" && nodeId_b.node_id.type === "Agent") + return ( + encodeHashToBase64(nodeId_a.node_id.id) === + encodeHashToBase64(nodeId_b.node_id.id) && areUint8ArrayEqual(nodeId_a.tag, nodeId_b.tag) + ); + if (nodeId_a.node_id.type === "Thing" && nodeId_b.node_id.type === "Thing") + return ( + encodeHashToBase64(nodeId_a.node_id.id) === + encodeHashToBase64(nodeId_b.node_id.id) && areUint8ArrayEqual(nodeId_a.tag, nodeId_b.tag) + ); + if (nodeId_a.node_id.type === "Anchor" && nodeId_b.node_id.type === "Anchor") + return nodeId_a.node_id.id === nodeId_b.node_id.id && areUint8ArrayEqual(nodeId_a.tag, nodeId_b.tag); + return false; +} + +function containsNodeIdAndTag( + arr: NodeIdAndTag[], + nodeIdAndTag: NodeIdAndTag +): boolean { for (const id of arr) { - if (areNodesEqual(id, nodeId)) { + if (areNodeAndTagEqual(id, nodeIdAndTag)) { return true; } } return false; } + +function areUint8ArrayEqual(a, b) { + if (a.length != b.length) return false; + for (let i = 0; i < a.length; i++) if (a[i] != b[i]) return false; + return true; +} diff --git a/lib/src/types.ts b/lib/src/types.ts index 43355e9..238a2bd 100644 --- a/lib/src/types.ts +++ b/lib/src/types.ts @@ -69,11 +69,10 @@ export type SignalKind = link_type: string; }; - export type RemoteSignalInput = { - signal: GenericZomeSignal, - agents: AgentPubKey[], -} + signal: GenericZomeSignal; + agents: AgentPubKey[]; +}; /* dprint-ignore-start */ export type EntryTypes = { type: "Thing" } & ThingEntry; @@ -107,6 +106,13 @@ export type NodeId = id: AgentPubKey; }; +export type NodeIdAndTag = { + node_id: NodeId; + tag: Tag | undefined; +}; + +export type Tag = Uint8Array; + export type NodeContent = | { type: "Anchor"; @@ -193,6 +199,6 @@ export type CreateOrDeleteLinksInput = { }; export type NodeAndLinkedIds = { - content: NodeContent, - linked_node_ids: NodeId[], -} \ No newline at end of file + content: NodeContent; + linked_node_ids: NodeIdAndTag[]; +}; diff --git a/ui/src/holochain-app.ts b/ui/src/holochain-app.ts index 4291533..4825510 100644 --- a/ui/src/holochain-app.ts +++ b/ui/src/holochain-app.ts @@ -1,9 +1,8 @@ -import { ActionHash, AppClient, AppWebsocket, HolochainError } from "@holochain/client"; +import { HolochainError } from "@holochain/client"; import { createContext, provide } from "@lit/context"; import { css, html, LitElement } from "lit"; import { customElement, property, state } from "lit/decorators.js"; -import HolochainLogo from "./assets/holochainLogo.svg"; import { simpleHolochainContext } from "./contexts"; import { sharedStyles } from "./shared-styles"; import { SimpleHolochain } from "@holochain/simple-holochain";