import { type Throws } from '@livekit/throws-transformer/throws'; import { LivekitReasonedError } from '../errors'; import { U16_MAX_SIZE } from './utils'; export enum DataTrackHandleErrorReason { Reserved = 0, TooLarge = 1, } export class DataTrackHandleError< Reason extends DataTrackHandleErrorReason = DataTrackHandleErrorReason, > extends LivekitReasonedError { readonly name = 'DataTrackHandleError'; reason: Reason; reasonName: string; constructor(message: string, reason: Reason) { super(19, message); this.reason = reason; this.reasonName = DataTrackHandleErrorReason[reason]; } isReason(reason: R): this is DataTrackHandleError { return (this.reason as unknown as R) === reason; } static tooLarge() { return new DataTrackHandleError( 'Value too large to be a valid track handle', DataTrackHandleErrorReason.TooLarge, ); } static reserved(value: number) { return new DataTrackHandleError( `0x${value.toString(16)} is a reserved value.`, DataTrackHandleErrorReason.Reserved, ); } } export type DataTrackHandle = number; export const DataTrackHandle = { fromNumber(raw: number): Throws { if (raw === 0) { throw DataTrackHandleError.reserved(raw); } if (raw > U16_MAX_SIZE) { throw DataTrackHandleError.tooLarge(); } return raw; }, }; /** Manage allocating new handles which don't conflict over the lifetime of the client. */ export class DataTrackHandleAllocator { value = 0; /** Returns a unique track handle for the next publication, if one can be obtained. */ get(): DataTrackHandle | null { this.value += 1; if (this.value > U16_MAX_SIZE) { return null; } return this.value; } }