mirror of
https://github.com/logos-messaging/docs.waku.org.git
synced 2026-01-05 14:23:06 +00:00
1 line
13 KiB
JavaScript
1 line
13 KiB
JavaScript
"use strict";(self.webpackChunkwaku_guide=self.webpackChunkwaku_guide||[]).push([[4214],{28453:(e,s,r)=>{r.d(s,{R:()=>i,x:()=>a});var t=r(96540);const n={},o=t.createContext(n);function i(e){const s=t.useContext(o);return t.useMemo(function(){return"function"==typeof e?e(s):{...s,...e}},[s,e])}function a(e){let s;return s=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:i(e.components),t.createElement(o.Provider,{value:s},e.children)}},95470:(e,s,r)=>{r.r(s),r.d(s,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>i,metadata:()=>t,toc:()=>d});const t=JSON.parse('{"id":"guides/js-waku/store-retrieve-messages","title":"Retrieve Messages Using Store Protocol","description":"This guide provides detailed steps to create a Light Node for retrieving and filtering historical messages using the Store protocol.","source":"@site/docs/guides/js-waku/store-retrieve-messages.md","sourceDirName":"guides/js-waku","slug":"/guides/js-waku/store-retrieve-messages","permalink":"/guides/js-waku/store-retrieve-messages","draft":false,"unlisted":false,"editUrl":"https://github.com/waku-org/docs.waku.org/tree/develop/docs/guides/js-waku/store-retrieve-messages.md","tags":[],"version":"current","lastUpdatedAt":null,"frontMatter":{"title":"Retrieve Messages Using Store Protocol","hide_table_of_contents":true},"sidebar":"guides","previous":{"title":"Send and Receive Messages Using Light Push and Filter","permalink":"/guides/js-waku/light-send-receive"},"next":{"title":"Encrypt, Decrypt, and Sign Your Messages","permalink":"/guides/js-waku/message-encryption"}}');var n=r(74848),o=r(28453);const i={title:"Retrieve Messages Using Store Protocol",hide_table_of_contents:!0},a=void 0,c={},d=[{value:"Create a light node",id:"create-a-light-node",level:2},{value:"Connect to store peers",id:"connect-to-store-peers",level:2},{value:"Choose a content topic",id:"choose-a-content-topic",level:2},{value:"Retrieve messages",id:"retrieve-messages",level:2},{value:"<code>queryWithOrderedCallback</code>",id:"querywithorderedcallback",level:3},{value:"<code>queryGenerator</code>",id:"querygenerator",level:3},{value:"Store query options",id:"store-query-options",level:2},{value:"<code>pageDirection</code>",id:"pagedirection",level:3},{value:"<code>cursor</code>",id:"cursor",level:3},{value:"<code>timeFilter</code>",id:"timefilter",level:3}];function l(e){const s={a:"a",admonition:"admonition",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)(s.p,{children:["This guide provides detailed steps to create a Light Node for retrieving and filtering historical messages using the ",(0,n.jsx)(s.a,{href:"/learn/concepts/protocols#store",children:"Store protocol"}),"."]}),"\n",(0,n.jsx)(s.h2,{id:"create-a-light-node",children:"Create a light node"}),"\n",(0,n.jsxs)(s.p,{children:["Use the ",(0,n.jsx)(s.code,{children:"createLightNode()"})," function to create a Light Node and interact with the Waku Network:"]}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-js",children:'import { createLightNode } from "@waku/sdk";\n\n// Create and start a Light Node\nconst node = await createLightNode({ defaultBootstrap: true });\nawait node.start();\n'})}),"\n",(0,n.jsx)(s.h2,{id:"connect-to-store-peers",children:"Connect to store peers"}),"\n",(0,n.jsxs)(s.p,{children:["Use the ",(0,n.jsx)(s.code,{children:"node.waitForPeers()"})," method to wait for the node to connect with Store peers:"]}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-js",children:'import { Protocols } from "@waku/sdk";\n\n// Wait for a successful peer connection\nawait node.waitForPeers([Protocols.Store]);\n'})}),"\n",(0,n.jsx)(s.p,{children:"You can also specify a dedicated Store peer to use for queries when creating the node. This is particularly useful when running your own Store node or when you want to use a specific Store node in the network:"}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-js",children:'const node = await createLightNode({ \n defaultBootstrap: true,\n store: {\n peer: "/ip4/1.2.3.4/tcp/1234/p2p/16Uiu2HAm..." // multiaddr or PeerId of your Store node\n }\n});\n'})}),"\n",(0,n.jsx)(s.p,{children:"If the specified Store peer is not available, the node will fall back to using random Store peers in the network."}),"\n",(0,n.jsx)(s.h2,{id:"choose-a-content-topic",children:"Choose a content topic"}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.a,{href:"/learn/concepts/content-topics",children:"Choose a content topic"})," for filtering the messages to retrieve and create a message ",(0,n.jsx)(s.code,{children:"decoder"}),":"]}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-js",children:'import { createDecoder } from "@waku/sdk";\n\n// Choose a content topic\nconst contentTopic = "/store-guide/1/message/proto";\n\n// Create a message decoder\nconst decoder = createDecoder(contentTopic);\n'})}),"\n",(0,n.jsx)(s.h2,{id:"retrieve-messages",children:"Retrieve messages"}),"\n",(0,n.jsxs)(s.p,{children:[(0,n.jsx)(s.code,{children:"@waku/sdk"})," provides the ",(0,n.jsx)(s.code,{children:"queryWithOrderedCallback()"})," and ",(0,n.jsx)(s.code,{children:"queryGenerator()"})," functions for querying ",(0,n.jsx)(s.code,{children:"Store"})," nodes and retrieving historical or missed messages. The responses from ",(0,n.jsx)(s.code,{children:"Store"})," nodes are paginated and require you to process each page sequentially."]}),"\n",(0,n.jsx)(s.h3,{id:"querywithorderedcallback",children:(0,n.jsx)(s.code,{children:"queryWithOrderedCallback"})}),"\n",(0,n.jsxs)(s.p,{children:["The ",(0,n.jsx)(s.code,{children:"store.queryWithOrderedCallback()"})," function provides a straightforward method for querying ",(0,n.jsx)(s.code,{children:"Store"})," nodes and processing messages in chronological order through a callback function. It accepts these parameters:"]}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"decoders"}),": List of ",(0,n.jsx)(s.code,{children:"decoders"})," that specify the ",(0,n.jsx)(s.code,{children:"content topic"})," to query for and their ",(0,n.jsx)(s.a,{href:"https://rfc.vac.dev/waku/standards/application/26/payload",children:"message decryption"})," methods."]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"callback"}),": The callback function for processing the retrieved messages."]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"options"})," (optional): ",(0,n.jsx)(s.a,{href:"/guides/js-waku/store-retrieve-messages#store-query-options",children:"Query options"})," to filter the retrieved messages."]}),"\n"]}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-js",children:"// Create the callback function\nconst callback = (wakuMessage) => {\n // Render the message/payload in your application\n console.log(wakuMessage);\n};\n\n// Query the Store peer\nawait node.store.queryWithOrderedCallback([decoder], callback);\n"})}),"\n",(0,n.jsx)(s.admonition,{type:"info",children:(0,n.jsxs)(s.p,{children:["The ",(0,n.jsx)(s.code,{children:"queryWithOrderedCallback()"})," function always returns the most recent messages in a page first."]})}),"\n",(0,n.jsx)(s.h3,{id:"querygenerator",children:(0,n.jsx)(s.code,{children:"queryGenerator"})}),"\n",(0,n.jsxs)(s.p,{children:["The ",(0,n.jsx)(s.code,{children:"store.queryGenerator()"})," function provides more control and flexibility over processing messages retrieved from ",(0,n.jsx)(s.code,{children:"Store"})," nodes through ",(0,n.jsx)(s.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncGenerator",children:"Async Generators"}),". It accepts these parameters:"]}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"decoders"}),": List of ",(0,n.jsx)(s.code,{children:"decoders"})," that specify the ",(0,n.jsx)(s.code,{children:"content topic"})," to query for and their ",(0,n.jsx)(s.a,{href:"https://rfc.vac.dev/waku/standards/application/26/payload",children:"message decryption"})," methods."]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"options"})," (optional): ",(0,n.jsx)(s.a,{href:"/guides/js-waku/store-retrieve-messages#store-query-options",children:"Query options"})," to filter the retrieved messages."]}),"\n"]}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-js",children:"// Create the store query\nconst storeQuery = node.store.queryGenerator([decoder]);\n\n// Process the messages\nfor await (const messagesPromises of storeQuery) {\n // Fulfil the messages promises\n const messages = await Promise.all(\n messagesPromises.map(async (p) => {\n const msg = await p;\n // Render the message/payload in your application\n console.log(msg);\n })\n );\n}\n"})}),"\n",(0,n.jsx)(s.admonition,{type:"info",children:(0,n.jsxs)(s.p,{children:["The ",(0,n.jsx)(s.code,{children:"queryGenerator()"})," function always returns the oldest messages in a page first."]})}),"\n",(0,n.jsx)(s.h2,{id:"store-query-options",children:"Store query options"}),"\n",(0,n.jsx)(s.h3,{id:"pagedirection",children:(0,n.jsx)(s.code,{children:"pageDirection"})}),"\n",(0,n.jsxs)(s.p,{children:["The ",(0,n.jsx)(s.code,{children:"pageDirection"})," option specifies the direction in which pages are retrieved:"]}),"\n",(0,n.jsxs)(s.ul,{children:["\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"BACKWARD"})," (default): Most recent page first."]}),"\n",(0,n.jsxs)(s.li,{children:[(0,n.jsx)(s.code,{children:"FORWARD"}),": Oldest page first."]}),"\n"]}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-js",children:'import { PageDirection } from "@waku/sdk";\n\n// Retrieve recent messages first\nconst queryOptions = {\n pageDirection: PageDirection.BACKWARD,\n};\n\n// Retrieve oldest messages first\nconst queryOptions = {\n pageDirection: PageDirection.FORWARD,\n};\n\n// Query the Store peer with options\nawait node.store.queryWithOrderedCallback([decoder], callback, options);\nconst storeQuery = node.store.queryGenerator([decoder, options]);\n'})}),"\n",(0,n.jsx)(s.h3,{id:"cursor",children:(0,n.jsx)(s.code,{children:"cursor"})}),"\n",(0,n.jsxs)(s.p,{children:["The ",(0,n.jsx)(s.code,{children:"cursor"})," option specifies the starting index for retrieving messages. For example, consider a query that retrieves the first page messages and then continues with the next page:"]}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-js",children:'import { waku } from "@waku/sdk";\n\n// Create the callback function\nconst messages = [];\nconst callback = (wakuMessage) => {\n messages.push(wakuMessage);\n // Return "true" to stop retrieving pages\n // Here, it retrieves only the first page\n return true;\n};\n\n// Retrieve the first page of messages\n// This retrieves all the messages if "return true" is not present\nawait node.store.queryWithOrderedCallback([decoder], callback);\n\n// Create the cursor\nconst lastMessage = messages[messages.length - 1];\nconst cursor = await waku.createCursor(lastMessage);\n\n// Retrieve the next page of messages\n// The message at the cursor index is excluded from the result\nawait node.store.queryWithOrderedCallback([decoder], callback, {\n cursor: cursor,\n});\nconsole.log(messages);\n'})}),"\n",(0,n.jsx)(s.admonition,{type:"info",children:(0,n.jsxs)(s.p,{children:["If you omit the ",(0,n.jsx)(s.code,{children:"cursor"})," option, the query will start from the beginning or end of the history, depending on the ",(0,n.jsx)(s.a,{href:"#pagedirection",children:"page direction"}),"."]})}),"\n",(0,n.jsx)(s.h3,{id:"timefilter",children:(0,n.jsx)(s.code,{children:"timeFilter"})}),"\n",(0,n.jsxs)(s.p,{children:["The ",(0,n.jsx)(s.code,{children:"timeFilter"})," option specifies a time frame to retrieve messages from. For example, consider a query that retrieves messages from the previous week:"]}),"\n",(0,n.jsx)(s.pre,{children:(0,n.jsx)(s.code,{className:"language-js",children:"// Get the time frame\nconst endTime = new Date();\nconst startTime = new Date();\nstartTime.setDate(endTime.getDate() - 7);\n\n// Retrieve a week of messages\nconst queryOptions = {\n timeFilter: {\n startTime,\n endTime,\n },\n};\n\n// Query the Store peer with options\nawait node.store.queryWithOrderedCallback([decoder], callback, options);\nconst storeQuery = node.store.queryGenerator([decoder, options]);\n"})}),"\n",(0,n.jsx)(s.admonition,{type:"info",children:(0,n.jsxs)(s.p,{children:["The ",(0,n.jsx)(s.code,{children:"timeFilter"})," option significantly reduces message retrieval performance. To optimise it, consider resuming message retrieval using a ",(0,n.jsx)(s.a,{href:"#cursor",children:"cursor"})," that starts from the last seen message."]})}),"\n",(0,n.jsx)(s.admonition,{title:"Congratulations!",type:"tip",children:(0,n.jsxs)(s.p,{children:["You have successfully retrieved and filtered historical messages on a Light Node using the ",(0,n.jsx)(s.code,{children:"Store"})," protocol. Have a look at the ",(0,n.jsx)(s.a,{href:"https://github.com/waku-org/js-waku-examples/tree/master/examples/store-js",children:"store-js"})," and ",(0,n.jsx)(s.a,{href:"https://github.com/waku-org/js-waku-examples/tree/master/examples/store-reactjs-chat",children:"store-reactjs-chat"})," examples for working demos."]})})]})}function h(e={}){const{wrapper:s}={...(0,o.R)(),...e.components};return s?(0,n.jsx)(s,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}}}]); |