const polls: Map = new Map() export function registerNewPoll(key, maxVotes, onComplete, onNoResult): void { polls.set(key, new Poll(maxVotes, onComplete, onNoResult)) console.log("created poll", key) } export function getNewPoll(maxVotes: number, onComplete: (result: T, votes: Map) => void, onNoResult: (votes: Map) => void) { return new Poll(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 { public currentVotes = 0; public votes = new Map() constructor(public readonly maxVotes: number, public onComplete: (result: any, votes: Map) => void, public onNoResult: (votes: Map) => 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() 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 }