90 lines
2.5 KiB
TypeScript
90 lines
2.5 KiB
TypeScript
const polls: Map<string, Poll> = new Map<string, Poll>()
|
|
|
|
export function registerNewPoll(key, maxVotes, onComplete, onNoResult): void {
|
|
polls.set(key, new Poll(maxVotes, onComplete, onNoResult))
|
|
console.log("created poll", key)
|
|
}
|
|
|
|
export function getNewPoll<T>(maxVotes: number, onComplete: (result: T, votes: Map<string, T>) => void, onNoResult: (votes: Map<string, T>) => void) {
|
|
return new Poll<T>(maxVotes, onComplete, onNoResult)
|
|
}
|
|
|
|
export function voteInPoll(key, voterId, vote): void {
|
|
if (polls.has(key)) {
|
|
const poll = polls.get(key)
|
|
poll.vote(`${voterId}`, vote)
|
|
const result = poll.isMajorityReached()
|
|
if (result) {
|
|
poll.onComplete(result, poll.votes)
|
|
delete polls[key]
|
|
console.log("vote finished", key, result)
|
|
} else if (poll.currentVotes === poll.maxVotes) {
|
|
poll.onNoResult(poll.votes)
|
|
delete polls[key]
|
|
console.log("vote inconclusive", key)
|
|
}
|
|
}
|
|
}
|
|
|
|
function isMajorityReached_dep(poll): any {
|
|
const minimumConsensus = Math.ceil(poll.maxVotes * 0.5)
|
|
const voteTally = {}
|
|
for (const vote in poll.votes) {
|
|
if (vote != null) {
|
|
if (voteTally.hasOwnProperty(poll.votes[vote])) {
|
|
voteTally[poll.votes[vote]]++
|
|
} else {
|
|
voteTally[poll.votes[vote]] = 1
|
|
}
|
|
}
|
|
if (voteTally[poll.votes[vote]] >= minimumConsensus) {
|
|
return vote
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
class Poll<T> {
|
|
public currentVotes = 0;
|
|
public votes = new Map<string, T>()
|
|
constructor(public readonly maxVotes: number, public onComplete: (result: any, votes: Map<string, T>) => void, public onNoResult: (votes: Map<string, T>) => void) {
|
|
|
|
}
|
|
|
|
vote(voterId: string, vote: T): void {
|
|
this.currentVotes++
|
|
this.votes.set(voterId, vote)
|
|
this.checkVotes()
|
|
}
|
|
|
|
skipVote(voterId: string): void {
|
|
this.currentVotes++
|
|
this.checkVotes()
|
|
}
|
|
|
|
private checkVotes(): void {
|
|
const minimumConsensus = Math.ceil(this.maxVotes * 0.5)
|
|
const voteTally = new Map<T, number>()
|
|
this.votes.forEach((vote, voter) => {
|
|
// Allow for null votes, can't have a null key in a map
|
|
const normalizedVote = vote == null ? new T() : vote
|
|
if (voteTally.has(normalizedVote)) {
|
|
voteTally.set(normalizedVote, voteTally.get(normalizedVote) + 1)
|
|
} else {
|
|
voteTally.set(normalizedVote, 1)
|
|
}
|
|
if (voteTally.get(normalizedVote) >= minimumConsensus) {
|
|
this.onComplete(vote, this.votes)
|
|
}
|
|
})
|
|
if (this.currentVotes === this.maxVotes) {
|
|
this.onNoResult(this.votes)
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
registerNewPoll,
|
|
voteInPoll
|
|
}
|