Improve wakuMessage query performance (#13)
This commit is contained in:
parent
8cca55ccd5
commit
54e1ca8ca2
|
@ -9,12 +9,39 @@ import { TimedPollVoteMsg } from './models/TimedPollVoteMsg'
|
||||||
import TimedPollVote from './utils/proto/TimedPollVote'
|
import TimedPollVote from './utils/proto/TimedPollVote'
|
||||||
import { DetailedTimedPoll } from './models/DetailedTimedPoll'
|
import { DetailedTimedPoll } from './models/DetailedTimedPoll'
|
||||||
|
|
||||||
|
function decodeWakuMessages<T>(
|
||||||
|
messages: WakuMessage[] | null | undefined,
|
||||||
|
decoder: { decode: (payload: Uint8Array | undefined, timestamp: Date | undefined) => T | undefined }
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
messages
|
||||||
|
?.map((msg) => decoder.decode(msg.payload, msg.timestamp))
|
||||||
|
.filter((poll: T | undefined): poll is T => !!poll) ?? []
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function receiveNewWakuMessages(lastTimestamp: number, topic: string, waku: Waku | undefined) {
|
||||||
|
const messages = await waku?.store.queryHistory({ contentTopics: [topic] })
|
||||||
|
|
||||||
|
if (messages) {
|
||||||
|
messages.sort((a, b) => (a.timestamp && b.timestamp && a.timestamp?.getTime() < b.timestamp?.getTime() ? 1 : -1))
|
||||||
|
const lastMessageIndex = messages.findIndex((message) => message.timestamp?.getTime() === lastTimestamp)
|
||||||
|
const newMessages = lastMessageIndex === -1 ? messages : messages.slice(0, lastMessageIndex)
|
||||||
|
return newMessages
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
class WakuVoting {
|
class WakuVoting {
|
||||||
private appName: string
|
private appName: string
|
||||||
private waku: Waku | undefined
|
private waku: Waku | undefined
|
||||||
public tokenAddress: string
|
public tokenAddress: string
|
||||||
private pollInitTopic: string
|
private pollInitTopic: string
|
||||||
private timedPollVoteTopic: string
|
private timedPollVoteTopic: string
|
||||||
|
|
||||||
|
private timedPollInitMessages: PollInitMsg[] = []
|
||||||
|
private timedPollVotesMessages: TimedPollVoteMsg[] = []
|
||||||
|
|
||||||
private static async createWaku() {
|
private static async createWaku() {
|
||||||
const waku = await Waku.create()
|
const waku = await Waku.create()
|
||||||
const nodes = await getStatusFleetNodes()
|
const nodes = await getStatusFleetNodes()
|
||||||
|
@ -64,13 +91,14 @@ class WakuVoting {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getTimedPolls() {
|
private async getTimedPolls() {
|
||||||
const messages = await this.waku?.store.queryHistory({ contentTopics: [this.pollInitTopic] })
|
const lastTimestamp = this.timedPollInitMessages?.[0]?.timestamp ?? 0
|
||||||
return (
|
|
||||||
messages
|
const newMessages = await receiveNewWakuMessages(lastTimestamp, this.pollInitTopic, this.waku)
|
||||||
?.filter((e): e is WakuMessage & { payload: Uint8Array } => !!e?.payload)
|
const newPollInitMessages = decodeWakuMessages(newMessages, PollInit)
|
||||||
.map((msg) => PollInit.decode(msg.payload, msg.timestamp))
|
if (newPollInitMessages.length > 0) {
|
||||||
.filter((poll): poll is PollInitMsg => !!poll) ?? []
|
this.timedPollInitMessages = [...newPollInitMessages, ...this.timedPollInitMessages]
|
||||||
)
|
}
|
||||||
|
return this.timedPollInitMessages
|
||||||
}
|
}
|
||||||
|
|
||||||
public async sendTimedPollVote(
|
public async sendTimedPollVote(
|
||||||
|
@ -92,13 +120,14 @@ class WakuVoting {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getTimedPollsVotes() {
|
private async getTimedPollsVotes() {
|
||||||
const messages = await this.waku?.store.queryHistory({ contentTopics: [this.timedPollVoteTopic] })
|
const lastTimestamp = this.timedPollVotesMessages?.[0]?.timestamp ?? 0
|
||||||
return (
|
|
||||||
messages
|
const newMessages = await receiveNewWakuMessages(lastTimestamp, this.timedPollVoteTopic, this.waku)
|
||||||
?.filter((e): e is WakuMessage & { payload: Uint8Array } => !!e?.payload)
|
const newVoteMessages = decodeWakuMessages(newMessages, TimedPollVote)
|
||||||
.map((msg) => TimedPollVote.decode(msg.payload, msg.timestamp))
|
if (newVoteMessages.length > 0) {
|
||||||
.filter((poll): poll is TimedPollVoteMsg => !!poll) ?? []
|
this.timedPollVotesMessages = [...newVoteMessages, ...this.timedPollVotesMessages]
|
||||||
)
|
}
|
||||||
|
return this.timedPollVotesMessages
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getDetailedTimedPolls() {
|
public async getDetailedTimedPolls() {
|
||||||
|
|
|
@ -39,7 +39,7 @@ export function createSignMsgParams(message: Message) {
|
||||||
|
|
||||||
if (message.tokenAmount) {
|
if (message.tokenAmount) {
|
||||||
msgParams.message = { ...msgParams.message, tokenAmount: message.tokenAmount.toString() }
|
msgParams.message = { ...msgParams.message, tokenAmount: message.tokenAmount.toString() }
|
||||||
msgParams.types.Mail.push({ name: 'minToken', type: 'uint256' })
|
msgParams.types.Mail.push({ name: 'tokenAmount', type: 'uint256' })
|
||||||
}
|
}
|
||||||
return msgParams
|
return msgParams
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,10 +48,13 @@ export function encode(pollInit: PollInitMsg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function decode(
|
export function decode(
|
||||||
payload: Uint8Array,
|
payload: Uint8Array | undefined,
|
||||||
timestamp: Date | undefined,
|
timestamp: Date | undefined,
|
||||||
recoverFunction?: ({ data, sig }: { data: any; sig: string }) => string
|
recoverFunction?: ({ data, sig }: { data: any; sig: string }) => string
|
||||||
) {
|
) {
|
||||||
|
if (!payload) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const msg = proto.PollInit.decode(payload)
|
const msg = proto.PollInit.decode(payload)
|
||||||
if (!timestamp || timestamp.getTime() != msg.timestamp) {
|
if (!timestamp || timestamp.getTime() != msg.timestamp) {
|
||||||
|
|
|
@ -33,10 +33,13 @@ export function encode(timedPollVote: TimedPollVoteMsg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function decode(
|
export function decode(
|
||||||
payload: Uint8Array,
|
payload: Uint8Array | undefined,
|
||||||
timestamp: Date | undefined,
|
timestamp: Date | undefined,
|
||||||
recoverFunction?: ({ data, sig }: { data: any; sig: string }) => string
|
recoverFunction?: ({ data, sig }: { data: any; sig: string }) => string
|
||||||
) {
|
) {
|
||||||
|
if (!payload) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const msg = proto.TimedPollVote.decode(payload)
|
const msg = proto.TimedPollVote.decode(payload)
|
||||||
if (!timestamp || timestamp.getTime() != msg.timestamp) {
|
if (!timestamp || timestamp.getTime() != msg.timestamp) {
|
||||||
|
|
|
@ -16,11 +16,15 @@ export function Poll({ poll, wakuVoting, signer }: PollProps) {
|
||||||
const [selectedAnswer, setSelectedAnswer] = useState(0)
|
const [selectedAnswer, setSelectedAnswer] = useState(0)
|
||||||
const [tokenAmount, setTokenAmount] = useState(0)
|
const [tokenAmount, setTokenAmount] = useState(0)
|
||||||
const [address, setAddress] = useState('')
|
const [address, setAddress] = useState('')
|
||||||
|
const [userInVoters, setUserInVoters] = useState(false)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
signer.getAddress().then((e) => setAddress(e))
|
signer.getAddress().then((e) => setAddress(e))
|
||||||
}, [signer])
|
}, [signer])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setUserInVoters(!!poll.votesMessages.find((vote) => vote.voter === address))
|
||||||
|
}, [poll])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PollWrapper>
|
<PollWrapper>
|
||||||
<PollTitle>
|
<PollTitle>
|
||||||
|
@ -28,7 +32,7 @@ export function Poll({ poll, wakuVoting, signer }: PollProps) {
|
||||||
<PollTypeWrapper>{poll.poll.pollType === PollType.WEIGHTED ? 'WEIGHTED' : 'NON WEIGHTED'}</PollTypeWrapper>
|
<PollTypeWrapper>{poll.poll.pollType === PollType.WEIGHTED ? 'WEIGHTED' : 'NON WEIGHTED'}</PollTypeWrapper>
|
||||||
</PollTitle>
|
</PollTitle>
|
||||||
<PollAnswersWrapper>
|
<PollAnswersWrapper>
|
||||||
{!poll.votesMessages.find((vote) => vote.voter === address) && (
|
{!userInVoters && (
|
||||||
<div>
|
<div>
|
||||||
<div onChange={(e) => setSelectedAnswer(Number.parseInt((e.target as any).value ?? 0))}>
|
<div onChange={(e) => setSelectedAnswer(Number.parseInt((e.target as any).value ?? 0))}>
|
||||||
{poll.poll.answers.map((answer, idx) => {
|
{poll.poll.answers.map((answer, idx) => {
|
||||||
|
@ -51,7 +55,7 @@ export function Poll({ poll, wakuVoting, signer }: PollProps) {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{poll.votesMessages.find((vote) => vote.voter === address) && (
|
{userInVoters && (
|
||||||
<div>
|
<div>
|
||||||
Results
|
Results
|
||||||
{poll.answers.map((answer, idx) => {
|
{poll.answers.map((answer, idx) => {
|
||||||
|
@ -65,6 +69,7 @@ export function Poll({ poll, wakuVoting, signer }: PollProps) {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</PollAnswersWrapper>
|
</PollAnswersWrapper>
|
||||||
|
{!userInVoters && (
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (wakuVoting) {
|
if (wakuVoting) {
|
||||||
|
@ -80,6 +85,7 @@ export function Poll({ poll, wakuVoting, signer }: PollProps) {
|
||||||
{' '}
|
{' '}
|
||||||
Vote
|
Vote
|
||||||
</button>
|
</button>
|
||||||
|
)}
|
||||||
</PollWrapper>
|
</PollWrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ export function PollList({ wakuVoting, signer }: PollListProps) {
|
||||||
if (wakuVoting) {
|
if (wakuVoting) {
|
||||||
setPolls(await wakuVoting.getDetailedTimedPolls())
|
setPolls(await wakuVoting.getDetailedTimedPolls())
|
||||||
}
|
}
|
||||||
}, 1000)
|
}, 5000)
|
||||||
return () => clearInterval(interval)
|
return () => clearInterval(interval)
|
||||||
}, [wakuVoting])
|
}, [wakuVoting])
|
||||||
|
|
||||||
|
|
|
@ -30,9 +30,9 @@ function Example({ appName }: ExampleProps) {
|
||||||
provider.send('eth_requestAccounts', [])
|
provider.send('eth_requestAccounts', [])
|
||||||
}, [])
|
}, [])
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<Wrapper onClick={() => showNewPollBox && setShowNewPollBox(false)}>
|
||||||
{showNewPollBox && (
|
{showNewPollBox && (
|
||||||
<NewPollBoxWrapper>
|
<NewPollBoxWrapper onClick={(e) => e.stopPropagation()}>
|
||||||
<NewPollBox>
|
<NewPollBox>
|
||||||
<NewPollBoxTitle>
|
<NewPollBoxTitle>
|
||||||
Question
|
Question
|
||||||
|
@ -83,7 +83,7 @@ function Example({ appName }: ExampleProps) {
|
||||||
</NewPollBox>
|
</NewPollBox>
|
||||||
</NewPollBoxWrapper>
|
</NewPollBoxWrapper>
|
||||||
)}
|
)}
|
||||||
<button onClick={() => setShowNewPollBox(true)}>New Poll </button>
|
<button onClick={() => setShowNewPollBox(true)}>New Poll</button>
|
||||||
<PollList wakuVoting={wakuVoting} signer={signer} />
|
<PollList wakuVoting={wakuVoting} signer={signer} />
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue