Remove legacy V1 code and clean up unused remnants

- Delete unused bloom.ts module (leftover from topic-based discovery)
- Remove maxTopicsPerOffer configuration (no longer used)
- Remove unused info field from Offer types
- Simplify generateOfferHash() to only hash SDP (remove topics param)
- Update outdated comments referencing deprecated features
- Remove backward compatibility topics field from answer responses

This completes the migration to V2 service-based architecture by
removing all remnants of the V1 topic-based system.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-06 12:06:02 +01:00
parent 5622867411
commit 52cf734858
9 changed files with 12 additions and 91 deletions

View File

@@ -546,8 +546,7 @@ export function createApp(storage: Storage, config: Config) {
offerId: offer.id, offerId: offer.id,
answererId: offer.answererPeerId, answererId: offer.answererPeerId,
sdp: offer.answerSdp, sdp: offer.answerSdp,
answeredAt: offer.answeredAt, answeredAt: offer.answeredAt
topics: [] // V2 doesn't use topics, but client expects this field
})) }))
}, 200); }, 200);
} catch (err) { } catch (err) {

View File

@@ -1,66 +0,0 @@
/**
* Bloom filter utility for testing if peer IDs might be in a set
* Used to filter out known peers from discovery results
*/
export class BloomFilter {
private bits: Uint8Array;
private size: number;
private numHashes: number;
/**
* Creates a bloom filter from a base64 encoded bit array
*/
constructor(base64Data: string, numHashes: number = 3) {
// Decode base64 to Uint8Array (works in both Node.js and Workers)
const binaryString = atob(base64Data);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
this.bits = bytes;
this.size = this.bits.length * 8;
this.numHashes = numHashes;
}
/**
* Test if a peer ID might be in the filter
* Returns true if possibly in set, false if definitely not in set
*/
test(peerId: string): boolean {
for (let i = 0; i < this.numHashes; i++) {
const hash = this.hash(peerId, i);
const index = hash % this.size;
const byteIndex = Math.floor(index / 8);
const bitIndex = index % 8;
if (!(this.bits[byteIndex] & (1 << bitIndex))) {
return false;
}
}
return true;
}
/**
* Simple hash function (FNV-1a variant)
*/
private hash(str: string, seed: number): number {
let hash = 2166136261 ^ seed;
for (let i = 0; i < str.length; i++) {
hash ^= str.charCodeAt(i);
hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
}
return hash >>> 0;
}
}
/**
* Helper to parse bloom filter from base64 string
*/
export function parseBloomFilter(base64: string): BloomFilter | null {
try {
return new BloomFilter(base64);
} catch {
return null;
}
}

View File

@@ -16,7 +16,6 @@ export interface Config {
offerMinTtl: number; offerMinTtl: number;
cleanupInterval: number; cleanupInterval: number;
maxOffersPerRequest: number; maxOffersPerRequest: number;
maxTopicsPerOffer: number;
} }
/** /**
@@ -45,7 +44,6 @@ export function loadConfig(): Config {
offerMaxTtl: parseInt(process.env.OFFER_MAX_TTL || '86400000', 10), offerMaxTtl: parseInt(process.env.OFFER_MAX_TTL || '86400000', 10),
offerMinTtl: parseInt(process.env.OFFER_MIN_TTL || '60000', 10), offerMinTtl: parseInt(process.env.OFFER_MIN_TTL || '60000', 10),
cleanupInterval: parseInt(process.env.CLEANUP_INTERVAL || '60000', 10), cleanupInterval: parseInt(process.env.CLEANUP_INTERVAL || '60000', 10),
maxOffersPerRequest: parseInt(process.env.MAX_OFFERS_PER_REQUEST || '100', 10), maxOffersPerRequest: parseInt(process.env.MAX_OFFERS_PER_REQUEST || '100', 10)
maxTopicsPerOffer: parseInt(process.env.MAX_TOPICS_PER_OFFER || '50', 10),
}; };
} }

View File

@@ -20,7 +20,6 @@ async function main() {
offerMinTtl: `${config.offerMinTtl}ms`, offerMinTtl: `${config.offerMinTtl}ms`,
cleanupInterval: `${config.cleanupInterval}ms`, cleanupInterval: `${config.cleanupInterval}ms`,
maxOffersPerRequest: config.maxOffersPerRequest, maxOffersPerRequest: config.maxOffersPerRequest,
maxTopicsPerOffer: config.maxTopicsPerOffer,
corsOrigins: config.corsOrigins, corsOrigins: config.corsOrigins,
version: config.version, version: config.version,
}); });

View File

@@ -34,7 +34,7 @@ export class D1Storage implements Storage {
*/ */
async initializeDatabase(): Promise<void> { async initializeDatabase(): Promise<void> {
await this.db.exec(` await this.db.exec(`
-- Offers table (no topics) -- WebRTC signaling offers
CREATE TABLE IF NOT EXISTS offers ( CREATE TABLE IF NOT EXISTS offers (
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
peer_id TEXT NOT NULL, peer_id TEXT NOT NULL,
@@ -125,7 +125,7 @@ export class D1Storage implements Storage {
// D1 doesn't support true transactions yet, so we do this sequentially // D1 doesn't support true transactions yet, so we do this sequentially
for (const offer of offers) { for (const offer of offers) {
const id = offer.id || await generateOfferHash(offer.sdp, []); const id = offer.id || await generateOfferHash(offer.sdp);
const now = Date.now(); const now = Date.now();
await this.db.prepare(` await this.db.prepare(`

View File

@@ -1,22 +1,17 @@
/** /**
* Generates a content-based offer ID using SHA-256 hash * Generates a content-based offer ID using SHA-256 hash
* Creates deterministic IDs based on offer content (sdp, topics) * Creates deterministic IDs based on offer SDP content
* PeerID is not included as it's inferred from authentication * PeerID is not included as it's inferred from authentication
* Uses Web Crypto API for compatibility with both Node.js and Cloudflare Workers * Uses Web Crypto API for compatibility with both Node.js and Cloudflare Workers
* *
* @param sdp - The WebRTC SDP offer * @param sdp - The WebRTC SDP offer
* @param topics - Array of topic strings * @returns SHA-256 hash of the SDP content
* @returns SHA-256 hash of the sanitized offer content
*/ */
export async function generateOfferHash( export async function generateOfferHash(sdp: string): Promise<string> {
sdp: string,
topics: string[]
): Promise<string> {
// Sanitize and normalize the offer content // Sanitize and normalize the offer content
// Only include core offer content (not peerId - that's inferred from auth) // Only include core offer content (not peerId - that's inferred from auth)
const sanitizedOffer = { const sanitizedOffer = {
sdp, sdp
topics: [...topics].sort(), // Sort topics for consistency
}; };
// Create non-prettified JSON string // Create non-prettified JSON string

View File

@@ -36,7 +36,7 @@ export class SQLiteStorage implements Storage {
*/ */
private initializeDatabase(): void { private initializeDatabase(): void {
this.db.exec(` this.db.exec(`
-- Offers table (no topics) -- WebRTC signaling offers
CREATE TABLE IF NOT EXISTS offers ( CREATE TABLE IF NOT EXISTS offers (
id TEXT PRIMARY KEY, id TEXT PRIMARY KEY,
peer_id TEXT NOT NULL, peer_id TEXT NOT NULL,
@@ -132,7 +132,7 @@ export class SQLiteStorage implements Storage {
const offersWithIds = await Promise.all( const offersWithIds = await Promise.all(
offers.map(async (offer) => ({ offers.map(async (offer) => ({
...offer, ...offer,
id: offer.id || await generateOfferHash(offer.sdp, []), id: offer.id || await generateOfferHash(offer.sdp),
})) }))
); );

View File

@@ -1,5 +1,5 @@
/** /**
* Represents a WebRTC signaling offer (no topics) * Represents a WebRTC signaling offer
*/ */
export interface Offer { export interface Offer {
id: string; id: string;
@@ -9,7 +9,6 @@ export interface Offer {
expiresAt: number; expiresAt: number;
lastSeen: number; lastSeen: number;
secret?: string; secret?: string;
info?: string;
answererPeerId?: string; answererPeerId?: string;
answerSdp?: string; answerSdp?: string;
answeredAt?: number; answeredAt?: number;
@@ -37,7 +36,6 @@ export interface CreateOfferRequest {
sdp: string; sdp: string;
expiresAt: number; expiresAt: number;
secret?: string; secret?: string;
info?: string;
} }
/** /**

View File

@@ -13,7 +13,6 @@ export interface Env {
OFFER_MAX_TTL?: string; OFFER_MAX_TTL?: string;
OFFER_MIN_TTL?: string; OFFER_MIN_TTL?: string;
MAX_OFFERS_PER_REQUEST?: string; MAX_OFFERS_PER_REQUEST?: string;
MAX_TOPICS_PER_OFFER?: string;
CORS_ORIGINS?: string; CORS_ORIGINS?: string;
VERSION?: string; VERSION?: string;
} }
@@ -43,8 +42,7 @@ export default {
offerMaxTtl: env.OFFER_MAX_TTL ? parseInt(env.OFFER_MAX_TTL, 10) : 86400000, offerMaxTtl: env.OFFER_MAX_TTL ? parseInt(env.OFFER_MAX_TTL, 10) : 86400000,
offerMinTtl: env.OFFER_MIN_TTL ? parseInt(env.OFFER_MIN_TTL, 10) : 60000, offerMinTtl: env.OFFER_MIN_TTL ? parseInt(env.OFFER_MIN_TTL, 10) : 60000,
cleanupInterval: 60000, // Not used in Workers (scheduled handler instead) cleanupInterval: 60000, // Not used in Workers (scheduled handler instead)
maxOffersPerRequest: env.MAX_OFFERS_PER_REQUEST ? parseInt(env.MAX_OFFERS_PER_REQUEST, 10) : 100, maxOffersPerRequest: env.MAX_OFFERS_PER_REQUEST ? parseInt(env.MAX_OFFERS_PER_REQUEST, 10) : 100
maxTopicsPerOffer: env.MAX_TOPICS_PER_OFFER ? parseInt(env.MAX_TOPICS_PER_OFFER, 10) : 50,
}; };
// Create Hono app // Create Hono app