-
Notifications
You must be signed in to change notification settings - Fork 226
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial version of registrar service.
Outanding issues: - no tests - no iteration - it uses `get` rather than simple property lookup
- Loading branch information
1 parent
2874829
commit ca3092b
Showing
2 changed files
with
84 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Copyright (C) 2019 Agoric, under Apache License 2.0 | ||
|
||
import harden from "@agoric/harden"; | ||
import { insist } from "../../util/insist"; | ||
import { generateSparseInts } from "../../util/sparseInts"; | ||
|
||
// Example REPL imnvocations | ||
// home.registrar~.register('handoff', home.handoffService) | ||
// for (let i = 0; i < 3000; i++) { home.registrar~.register('handoff', home.handoffService); } | ||
|
||
// Generated keys must end with _ and digits. | ||
const keyFormat = new RegExp('.*_[0-9]+'); | ||
|
||
function makeRegistrar(systemVersion, seed = 0) { | ||
// TODO make a better token algorithm. | ||
const useCounts = new Map(); | ||
const contents = new Map(); | ||
const sparseInts = generateSparseInts(seed); | ||
|
||
const registrar = harden({ | ||
// Register the value | ||
register(name, value) { | ||
const realName = name.toLowerCase(); | ||
const useCount = (useCounts.get(realName) || 0) + 1; | ||
useCounts.set(realName, useCount); | ||
const depth = Math.max(4, Math.floor(Math.log10(useCount) + 1.6)); | ||
const uniqueString = sparseInts.next().value.toString(); | ||
const keyString = uniqueString.slice(-depth).padStart(depth, '0'); | ||
// console.log(`RAND ${useCount} ${uniqueString} ${keyString}`); | ||
const key = `${realName}_${keyString}`; | ||
// if it was a random keyString, then we need to detect collision | ||
insist(!contents.has(key), 'Generated name must not collide'); | ||
contents.set(key, value); | ||
return key; | ||
}, | ||
get(key, version = null) { | ||
insist(typeof key === 'string')`\ | ||
Key must be string ${key}`; | ||
insist(keyFormat.test(key))`\ | ||
Key must end with _<digits> ${key}` | ||
if (version) { | ||
insist(version === systemVersion)`\ | ||
Key is from incompatible version: ${version} should be ${systemVersion}`; | ||
} | ||
return contents.get(key); | ||
}, | ||
keys() { | ||
return contents.keys(); | ||
}, | ||
}); | ||
|
||
return registrar; | ||
} | ||
|
||
export { makeRegistrar }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Copyright (C) 2019 Agoric, under Apache License 2.0 | ||
|
||
import harden from '@agoric/harden'; | ||
import { insist } from "./insist"; | ||
|
||
// Generator function to produce a stream of positive integers that are | ||
// sparsely scattered across the number space. This supports IDs that | ||
// are guessable, but for example mistyping a correct ID is unlikely to | ||
// mistakenly match another generated ID. | ||
function* generateSparseInts(seed) { | ||
// This is a linear-feedback shift register with computed startState. | ||
// Thus, it is totally deterministic, but at least looks a little random | ||
// and so can be used for e.g., colors in a game or the gallery | ||
|
||
/* eslint-disable no-bitwise */ | ||
const mask = 0xffffffff; | ||
const startState = Math.floor(seed * mask) ^ 0xdeadbeef; | ||
let lfsr = startState; | ||
while (true) { | ||
lfsr ^= lfsr >>> 7; | ||
lfsr ^= (lfsr << 9) & mask; | ||
lfsr ^= lfsr >>> 13; | ||
const rand = (Math.floor(lfsr) % 0x800000) + 0x7fffff; | ||
yield rand; | ||
} | ||
/* eslint-enable no-bitwise */ | ||
} | ||
harden(generateSparseInts); | ||
export { generateSparseInts }; |