package redisactivity import ( "crypto/sha256" "encoding/hex" "strconv" ) const redisKeyPrefix = "pp:{activity}:" type keyspace struct { prefix string records string unique string idkeys string expiry string available string owners string ownerExpiry string drainTickets string epoch string inventory string stateInventory string workerSessions string workerSessionExpiry string workerSnapshots string workerSnapshotExpiry string workerRuntime string workerRuntimeExpiry string workerOutcomes string healthDue string healthUnhealthy string healthEgressDue string healthTargetDue string healthQueued string healthLeases string healthTasks string healthTaskExpiry string healthRefTask string } func newKeyspace(namespace string) keyspace { prefix := redisKeyPrefix + namespace return keyspace{ prefix: prefix, records: prefix + ":records", unique: prefix + ":unique", idkeys: prefix + ":idkeys", expiry: prefix + ":expiry", available: prefix + ":available", owners: prefix + ":owners", ownerExpiry: prefix + ":owner-expiry", drainTickets: prefix + ":drain-tickets", epoch: prefix + ":epoch", inventory: prefix + ":inventory", stateInventory: prefix + ":state-inventory", workerSessions: prefix + ":worker-sessions", workerSessionExpiry: prefix + ":worker-session-expiry", workerSnapshots: prefix + ":worker-snapshots", workerSnapshotExpiry: prefix + ":worker-snapshot-expiry", workerRuntime: prefix + ":worker-runtime", workerRuntimeExpiry: prefix + ":worker-runtime-expiry", workerOutcomes: prefix + ":worker-outcomes", healthDue: prefix + ":health-due", healthUnhealthy: prefix + ":health-unhealthy", healthEgressDue: prefix + ":health-egress-due", healthTargetDue: prefix + ":health-target-due", healthQueued: prefix + ":health-queued", healthLeases: prefix + ":health-leases", healthTasks: prefix + ":health-tasks", healthTaskExpiry: prefix + ":health-task-expiry", healthRefTask: prefix + ":health-ref-task", } } func (keys keyspace) checkerLeases(checkerID string) string { return keys.prefix + ":health-checker-leases:" + digestToken(checkerID) } func (keys keyspace) upstreamTasks(upstreamID string) string { return keys.prefix + ":health-upstream-tasks:" + digestToken(upstreamID) } func stateInventoryField(upstreamID, state string) string { return strconv.Itoa(len(upstreamID)) + ":" + upstreamID + ":" + state } func (keys keyspace) idempotency(clientID, idempotencyKey string) string { return keys.prefix + ":idem:" + digestParts(clientID, idempotencyKey) } func (keys keyspace) operation(operationID string) string { return keys.prefix + ":op:" + digestToken(operationID) } // targetHealth stores short-lived TARGET check state separately from the // proxy record. The proxy ID is hashed so neither endpoint identity nor target // profile information appears in a Redis key name. func (keys keyspace) targetHealth(proxyID string) string { return keys.prefix + ":target-health:" + digestToken(proxyID) } func (keys keyspace) protocol(value string) string { return keys.facet("protocol", value) } func (keys keyspace) region(value string) string { return keys.facet("region", value) } func (keys keyspace) carrier(value string) string { return keys.facet("carrier", value) } func (keys keyspace) upstream(value string) string { return keys.facet("upstream", value) } func (keys keyspace) owned(value string) string { return keys.facet("owned", value) } func (keys keyspace) workerOwned(workerID string) string { return keys.facet("worker-owned", workerID) } func (keys keyspace) workerDraining(workerID string) string { return keys.facet("worker-draining", workerID) } func (keys keyspace) facet(name, value string) string { return keys.prefix + ":" + name + ":" + digestToken(value) } func digestToken(value string) string { return digestParts(value) } func digestParts(values ...string) string { digest := sha256.New() for _, value := range values { _, _ = digest.Write([]byte(strconv.Itoa(len(value)))) _, _ = digest.Write([]byte{':'}) _, _ = digest.Write([]byte(value)) } return hex.EncodeToString(digest.Sum(nil)) }