Skip to content

Commit

Permalink
added a verbose flag for outputting more draw info
Browse files Browse the repository at this point in the history
- refactored things to accomodate for it
- added some more tests
  • Loading branch information
CluEleSsUK committed Nov 7, 2023
1 parent efb0fee commit 6829716
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 34 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Choose an item from a file or input stream using drand
`cat /some/path/to/file | dchoose --count 2`
or
`dchoose --count 2 --file /some/path/to/file`
or
`echo -e "heads\ntails" | dchoose`

## Parameters
* `-c, --count`
Expand Down
30 changes: 18 additions & 12 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7199,22 +7199,23 @@ function hashInput(input) {

// src/main.ts
async function main(params) {
printWinners(params, await draw(params));
}
async function draw(params) {
const { values, count, drandURL } = params;
if (count === 0) {
process.exit(0);
return { round: 0, randomness: "", winners: [] };
}
if (values.length <= count) {
printWinners(values);
process.exit(0);
return { round: 0, randomness: "", winners: values };
}
let randomness;
if (params.randomness) {
randomness = params.randomness;
} else {
randomness = await fetchDrandRandomness(drandURL);
const winners2 = select(count, values, Buffer.from(params.randomness, "hex"));
return { round: 0, randomness: params.randomness, winners: winners2 };
}
const [round, randomness] = await fetchDrandRandomness(drandURL);
const winners = select(count, values, Buffer.from(randomness, "hex"));
printWinners(winners);
return { round, randomness, winners };
}
async function fetchDrandRandomness(drandURL) {
const drandClient = new import_drand_client.HttpChainClient(new import_drand_client.HttpCachingChain(drandURL));
Expand All @@ -7224,12 +7225,16 @@ async function fetchDrandRandomness(drandURL) {
if (beacon.round !== nextRound) {
continue;
}
return beacon.randomness;
return [nextRound, beacon.randomness];
}
throw Error("this should never have happened");
}
function printWinners(winners) {
winners.forEach((winner) => console.log(winner));
function printWinners(params, output2) {
if (!params.verbose) {
output2.winners.forEach((winner) => console.log(winner));
} else {
console.log(JSON.stringify(output2));
}
}

// src/params.ts
Expand All @@ -7255,6 +7260,7 @@ function parseParams(opts) {
count: Number.parseInt(opts.count),
drandURL: opts.drandUrl,
randomness: opts.randomness,
verbose: opts.verbose,
values
};
}
Expand All @@ -7276,7 +7282,7 @@ function isValidURL(inputURL) {
}

// src/index.ts
program.option("-f,--file <file>", "a file you wish to use for selection; alternatively, you can pass options via stdin", "").option("-u,--drand-url <url>", "the URL you're using for drand randomness", "https://api.drand.sh/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971").option("-c,--count <number>", "the number of items you wish to draw", "1").option("-r,--randomness <hex>", "custom randomness, if you wish to repeat historical draws", "");
program.option("-f,--file <file>", "a file you wish to use for selection; alternatively, you can pass options via stdin", "").option("-u,--drand-url <url>", "the URL you're using for drand randomness", "https://api.drand.sh/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971").option("-c,--count <number>", "the number of items you wish to draw", "1").option("-r,--randomness <hex>", "custom randomness, if you wish to repeat historical draws", "").option("-v,--verbose", "the tool will output more details about the draw than just the winners");
program.parse(process.argv);
main(parseParamsAndExit(program.opts()));
/*! Bundled license information:
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ program
.option("-u,--drand-url <url>", "the URL you're using for drand randomness", "https://api.drand.sh/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971")
.option("-c,--count <number>", "the number of items you wish to draw", "1")
.option("-r,--randomness <hex>", "custom randomness, if you wish to repeat historical draws", "")
.option("-v,--verbose", "the tool will output more details about the draw than just the winners")

// including the arguments
program.parse(process.argv)
Expand Down
38 changes: 26 additions & 12 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,40 @@ export type CLIParams = {
drandURL: string
randomness?: string
values: Array<string>
verbose: boolean
}

export async function main(params: CLIParams) {
printWinners(params, await draw(params))
}

type DrawResult = {
round: number
randomness: string
winners: Array<string>
}

export async function draw(params: CLIParams): Promise<DrawResult> {
const {values, count, drandURL} = params
if (count === 0) {
process.exit(0)
return {round: 0, randomness: "", winners: []}
}

if (values.length <= count) {
printWinners(values)
process.exit(0)
return {round: 0, randomness: "", winners: values}
}

let randomness: string
if (params.randomness) {
randomness = params.randomness
} else {
randomness = await fetchDrandRandomness(drandURL)
const winners = select(count, values, Buffer.from(params.randomness, "hex"))
return {round: 0, randomness: params.randomness, winners}
}

const [round, randomness] = await fetchDrandRandomness(drandURL)
const winners = select(count, values, Buffer.from(randomness, "hex"))
printWinners(winners)
return {round, randomness, winners}
}

async function fetchDrandRandomness(drandURL: string): Promise<string> {
async function fetchDrandRandomness(drandURL: string): Promise<[number, string]> {
const drandClient = new HttpChainClient(new HttpCachingChain(drandURL))
const nextRound = roundAt(Date.now(), await drandClient.chain().info()) + 1
const abort = new AbortController()
Expand All @@ -40,11 +50,15 @@ async function fetchDrandRandomness(drandURL: string): Promise<string> {
continue
}

return beacon.randomness
return [nextRound, beacon.randomness]
}
throw Error("this should never have happened")
}

function printWinners(winners: Array<string>) {
winners.forEach(winner => console.log(winner))
function printWinners(params: CLIParams, output: DrawResult) {
if (!params.verbose) {
output.winners.forEach(winner => console.log(winner))
} else {
console.log(JSON.stringify(output))
}
}
1 change: 1 addition & 0 deletions src/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export function parseParams(opts: OptionValues): CLIParams | string {
count: Number.parseInt(opts.count),
drandURL: opts.drandUrl,
randomness: opts.randomness,
verbose: opts.verbose,
values,
}
}
Expand Down
86 changes: 76 additions & 10 deletions test/main.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,77 @@
import {test} from "@jest/globals"
import {main} from "../src/main"
import {describe, it, expect} from "@jest/globals"
import {draw, main} from "../src/main"

test("make sure it doesn't blow up", async () => {
const params = {
count: 1,
values: ["a", "b", "c"],
drandURL: "https://api.drand.sh/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971"
}
await main(params)
})
describe("draws", () => {
describe("main function", () => {
it("verbose shouldn't blow up", async () => {
const params = {
count: 1,
values: ["a", "b", "c"],
drandURL: "https://api.drand.sh/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971",
verbose: false,
}
await main(params)
})
it("non-verbose shouldn't blow up", async () => {
const params = {
count: 1,
values: ["a", "b", "c"],
drandURL: "https://api.drand.sh/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971",
verbose: false,
}
await main(params)
})
})
describe("draw function", () => {
it("should return no values for 0 count", async () => {
const params = {
count: 0,
values: ["a", "b", "c"],
drandURL: "https://api.drand.sh/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971",
verbose: true,
}
const result = await draw(params)
expect(result.round).toEqual(0)
expect(result.winners).toEqual([])
expect(result.randomness).toEqual("")
})
it("should return all the values for a count less than the number of values", async () => {
const params = {
count: 5,
values: ["a", "b", "c"],
drandURL: "https://api.drand.sh/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971",
verbose: true,
}
const result = await draw(params)
expect(result.round).toEqual(0)
expect(result.winners).toEqual(params.values)
expect(result.randomness).toEqual("")
})
it("should return the same result each time for custom randomness", async () => {
const params = {
count: 1,
values: ["a", "b", "c"],
randomness: "5af934e9a82fcbc0f7d9cb7be197f6a9f74e10a49227f3dc72ed0686f7ab85f2",
drandURL: "https://api.drand.sh/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971",
verbose: true,
}
const result = await draw(params)
expect(result.round).toEqual(0)
expect(result.randomness).toEqual(params.randomness)

const result2 = await draw(params)
expect(result).toEqual(result2)
})
it("should return a non-zero round for real randomness", async () => {
const params = {
count: 1,
values: ["a", "b", "c"],
drandURL: "https://api.drand.sh/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971",
verbose: true,
}
const result = await draw(params)
expect(result.round).toBeGreaterThan(1)
expect(result.winners).toHaveLength(params.count)
})
})
})

0 comments on commit 6829716

Please sign in to comment.