Refactor core (#49)

This commit is contained in:
Szymon Szlachtowicz 2021-09-03 12:14:08 +02:00 committed by GitHub
parent 10632fa3e5
commit 427e2cb1bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 157 additions and 151 deletions

View File

@ -0,0 +1,73 @@
import { Waku } from 'js-waku'
import { JsonRpcSigner } from '@ethersproject/providers'
import { PollInitMsg } from '../models/PollInitMsg'
import { PollType } from '../types/PollType'
import { BigNumber, Wallet } from 'ethers'
import { WakuMessage } from 'js-waku'
import { TimedPollVoteMsg } from '../models/TimedPollVoteMsg'
import { DetailedTimedPoll } from '../models/DetailedTimedPoll'
import { createWaku } from '../utils/createWaku'
import { WakuVoting } from './WakuVoting'
export class WakuPolling extends WakuVoting {
protected constructor(appName: string, tokenAddress: string, waku: Waku) {
super(appName, tokenAddress, waku)
this.wakuMessages['pollInit'] = {
topic: `/${this.appName}/waku-polling/timed-polls-init/proto/`,
hashMap: {},
arr: [],
updateFunction: (msg: WakuMessage[]) =>
this.decodeMsgAndSetArray(
msg,
PollInitMsg.decode,
this.wakuMessages['pollInit'],
(e) => e.endTime > Date.now()
),
}
this.wakuMessages['pollVote'] = {
topic: `/${this.appName}/waku-polling/votes/proto/`,
hashMap: {},
arr: [],
updateFunction: (msg: WakuMessage[]) =>
this.decodeMsgAndSetArray(msg, TimedPollVoteMsg.decode, this.wakuMessages['pollVote']),
}
this.setObserver()
}
public static async create(appName: string, tokenAddress: string, waku?: Waku) {
const wakuPolling = new WakuPolling(appName, tokenAddress, await createWaku(waku))
return wakuPolling
}
public async createTimedPoll(
signer: JsonRpcSigner | Wallet,
question: string,
answers: string[],
pollType: PollType,
minToken?: BigNumber,
endTime?: number
) {
const pollInit = await PollInitMsg.create(signer, question, answers, pollType, minToken, endTime)
await this.sendWakuMessage(this.wakuMessages['pollInit'], pollInit)
}
public async sendTimedPollVote(
signer: JsonRpcSigner | Wallet,
pollId: string,
selectedAnswer: number,
tokenAmount?: BigNumber
) {
const pollVote = await TimedPollVoteMsg.create(signer, pollId, selectedAnswer, tokenAmount)
await this.sendWakuMessage(this.wakuMessages['pollVote'], pollVote)
}
public async getDetailedTimedPolls() {
return this.wakuMessages['pollInit'].arr.map(
(poll) =>
new DetailedTimedPoll(
poll,
this.wakuMessages['pollVote'].arr.filter((vote) => vote.pollId === poll.id)
)
)
}
}

View File

@ -0,0 +1,82 @@
import { Waku } from 'js-waku'
import { WakuMessage } from 'js-waku'
import { createWaku } from '../utils/createWaku'
type WakuMessageStore = {
topic: string
hashMap: { [id: string]: boolean }
arr: any[]
updateFunction: (msg: WakuMessage[]) => void
}
type WakuMessageStores = {
[messageType: string]: WakuMessageStore
}
export class WakuVoting {
protected appName: string
protected waku: Waku
public tokenAddress: string
protected wakuMessages: WakuMessageStores = {}
protected observers: { callback: (msg: WakuMessage) => void; topics: string[] }[] = []
protected constructor(appName: string, tokenAddress: string, waku: Waku) {
this.appName = appName
this.tokenAddress = tokenAddress
this.waku = waku
}
public static async create(appName: string, tokenAddress: string, waku?: Waku) {
return new WakuVoting(appName, tokenAddress, await createWaku(waku))
}
public cleanUp() {
this.observers.forEach((observer) => this.waku.relay.deleteObserver(observer.callback, observer.topics))
}
protected async setObserver() {
await Promise.all(
Object.values(this.wakuMessages).map(async (msgObj) => {
const storeMessages = await this.waku?.store.queryHistory([msgObj.topic])
if (storeMessages) {
msgObj.updateFunction(storeMessages)
}
this.waku.relay.addObserver((msg) => msgObj.updateFunction([msg]), [msgObj.topic])
this.observers.push({ callback: (msg) => msgObj.updateFunction([msg]), topics: [msgObj.topic] })
})
)
}
protected decodeMsgAndSetArray<T extends { id: string; timestamp: number }>(
messages: WakuMessage[],
decode: (payload: Uint8Array | undefined, timestamp: Date | undefined) => T | undefined,
msgObj: WakuMessageStore,
filterFunction?: (e: T) => boolean
) {
messages
.map((msg) => decode(msg.payload, msg.timestamp))
.sort((a, b) => ((a?.timestamp ?? new Date(0)) > (b?.timestamp ?? new Date(0)) ? 1 : -1))
.forEach((e) => {
if (e) {
if (filterFunction ? filterFunction(e) : true && !msgObj.hashMap?.[e.id]) {
msgObj.arr.unshift(e)
msgObj.hashMap[e.id] = true
}
}
})
}
protected async sendWakuMessage<T extends { encode: () => Uint8Array | undefined; timestamp: number }>(
msgObj: WakuMessageStore,
decodedMsg: T | undefined
) {
const payload = decodedMsg?.encode()
if (payload && decodedMsg) {
const wakuMessage = await WakuMessage.fromBytes(payload, msgObj.topic, {
timestamp: new Date(decodedMsg.timestamp),
})
await this.waku?.relay.send(wakuMessage)
msgObj.updateFunction([wakuMessage])
}
}
}

View File

@ -1,151 +1,4 @@
import { Waku } from 'js-waku'
import { JsonRpcSigner } from '@ethersproject/providers'
import { PollInitMsg } from './models/PollInitMsg'
import { PollType } from './types/PollType'
import { BigNumber, Wallet } from 'ethers'
import { WakuMessage, StoreCodec } from 'js-waku'
import { TimedPollVoteMsg } from './models/TimedPollVoteMsg'
import { DetailedTimedPoll } from './models/DetailedTimedPoll'
import { isTruthy } from './utils'
import { createWaku } from './utils/createWaku'
type WakuMessageStore = {
topic: string
hashMap: { [id: string]: boolean }
arr: any[]
updateFunction: (msg: WakuMessage[]) => void
}
type WakuMessageStores = {
[messageType: string]: WakuMessageStore
}
class WakuVoting {
protected appName: string
protected waku: Waku
public tokenAddress: string
protected wakuMessages: WakuMessageStores = {}
protected observers: { callback: (msg: WakuMessage) => void; topics: string[] }[] = []
protected constructor(appName: string, tokenAddress: string, waku: Waku) {
this.appName = appName
this.tokenAddress = tokenAddress
this.waku = waku
}
public static async create(appName: string, tokenAddress: string, waku?: Waku) {
return new WakuVoting(appName, tokenAddress, await createWaku(waku))
}
public cleanUp() {
this.observers.forEach((observer) => this.waku.relay.deleteObserver(observer.callback, observer.topics))
}
protected async setObserver(msgObj: WakuMessageStore) {
const storeMessages = await this.waku?.store.queryHistory([msgObj.topic])
if (storeMessages) {
msgObj.updateFunction(storeMessages)
}
this.waku.relay.addObserver((msg) => msgObj.updateFunction([msg]), [msgObj.topic])
this.observers.push({ callback: (msg) => msgObj.updateFunction([msg]), topics: [msgObj.topic] })
}
protected decodeMsgAndSetArray<T extends { id: string; timestamp: number }>(
messages: WakuMessage[],
decode: (payload: Uint8Array | undefined, timestamp: Date | undefined) => T | undefined,
msgObj: WakuMessageStore,
filterFunction?: (e: T) => boolean
) {
messages
.map((msg) => decode(msg.payload, msg.timestamp))
.sort((a, b) => ((a?.timestamp ?? new Date(0)) > (b?.timestamp ?? new Date(0)) ? 1 : -1))
.forEach((e) => {
if (e) {
if (filterFunction ? filterFunction(e) : true && !msgObj.hashMap?.[e.id]) {
msgObj.arr.unshift(e)
msgObj.hashMap[e.id] = true
}
}
})
}
protected async sendWakuMessage<T extends { encode: () => Uint8Array | undefined; timestamp: number }>(
msgObj: WakuMessageStore,
decodedMsg: T | undefined
) {
const payload = decodedMsg?.encode()
if (payload && decodedMsg) {
const wakuMessage = await WakuMessage.fromBytes(payload, msgObj.topic, {
timestamp: new Date(decodedMsg.timestamp),
})
await this.waku?.relay.send(wakuMessage)
msgObj.updateFunction([wakuMessage])
}
}
}
class WakuPolling extends WakuVoting {
protected constructor(appName: string, tokenAddress: string, waku: Waku) {
super(appName, tokenAddress, waku)
this.wakuMessages['pollInit'] = {
topic: `/${this.appName}/waku-polling/timed-polls-init/proto/`,
hashMap: {},
arr: [],
updateFunction: (msg: WakuMessage[]) =>
this.decodeMsgAndSetArray(
msg,
PollInitMsg.decode,
this.wakuMessages['pollInit'],
(e) => e.endTime > Date.now()
),
}
this.wakuMessages['pollVote'] = {
topic: `/${this.appName}/waku-polling/votes/proto/`,
hashMap: {},
arr: [],
updateFunction: (msg: WakuMessage[]) =>
this.decodeMsgAndSetArray(msg, TimedPollVoteMsg.decode, this.wakuMessages['pollVote']),
}
}
public static async create(appName: string, tokenAddress: string, waku?: Waku) {
const wakuPolling = new WakuPolling(appName, tokenAddress, await createWaku(waku))
wakuPolling.setObserver(wakuPolling.wakuMessages['pollInit'])
wakuPolling.setObserver(wakuPolling.wakuMessages['pollVote'])
return wakuPolling
}
public async createTimedPoll(
signer: JsonRpcSigner | Wallet,
question: string,
answers: string[],
pollType: PollType,
minToken?: BigNumber,
endTime?: number
) {
const pollInit = await PollInitMsg.create(signer, question, answers, pollType, minToken, endTime)
await this.sendWakuMessage(this.wakuMessages['pollInit'], pollInit)
}
public async sendTimedPollVote(
signer: JsonRpcSigner | Wallet,
pollId: string,
selectedAnswer: number,
tokenAmount?: BigNumber
) {
const pollVote = await TimedPollVoteMsg.create(signer, pollId, selectedAnswer, tokenAmount)
await this.sendWakuMessage(this.wakuMessages['pollVote'], pollVote)
}
public async getDetailedTimedPolls() {
return this.wakuMessages['pollInit'].arr.map(
(poll) =>
new DetailedTimedPoll(
poll,
this.wakuMessages['pollVote'].arr.filter((vote) => vote.pollId === poll.id)
)
)
}
}
import { WakuPolling } from './classes/WakuPolling'
import { WakuVoting } from './classes/WakuVoting'
export { WakuVoting, WakuPolling }

View File

@ -3,7 +3,6 @@ import { BigNumber, utils, Wallet } from 'ethers'
import { JsonRpcSigner } from '@ethersproject/providers'
import protons, { PollInit } from 'protons'
import { createSignedMsg } from '../utils/createSignedMsg'
import { recoverTypedSignature_v4 } from 'eth-sig-util'
import { verifySignature } from '../utils/verifySignature'
const proto = protons(`

View File

@ -3,7 +3,6 @@ import { JsonRpcSigner } from '@ethersproject/providers'
import protons, { TimedPollVote } from 'protons'
import { Wallet } from 'ethers'
import { createSignedMsg } from '../utils/createSignedMsg'
import { recoverTypedSignature_v4 } from 'eth-sig-util'
import { verifySignature } from '../utils/verifySignature'
const proto = protons(`