rocketmq-client-nodejs
Version:
RocketMQ Node.js Client
204 lines (183 loc) • 6.17 kB
text/typescript
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* OffsetOption type enum.
*/
export enum OffsetType {
POLICY = 0,
OFFSET = 1,
TAIL_N = 2,
TIMESTAMP = 3,
}
/**
* ProtoBuf OffsetOption type.
*/
import { OffsetOption as ProtoOffsetOption } from '../../proto/apache/rocketmq/v2/definition_pb';
/**
* OffsetOption for specifying consume from offset.
*
* <p>OffsetOption is used to specify the starting point for message consumption.
* It supports various policies and custom offsets.</p>
*/
export class OffsetOption {
/** Policy constant: last offset */
static readonly POLICY_LAST_VALUE = BigInt(0);
/** Policy constant: min offset */
static readonly POLICY_MIN_VALUE = BigInt(1);
/** Policy constant: max offset */
static readonly POLICY_MAX_VALUE = BigInt(2);
/** Predefined option: LAST_OFFSET */
static readonly LAST_OFFSET = new OffsetOption(OffsetType.POLICY, OffsetOption.POLICY_LAST_VALUE);
/** Predefined option: MIN_OFFSET */
static readonly MIN_OFFSET = new OffsetOption(OffsetType.POLICY, OffsetOption.POLICY_MIN_VALUE);
/** Predefined option: MAX_OFFSET */
static readonly MAX_OFFSET = new OffsetOption(OffsetType.POLICY, OffsetOption.POLICY_MAX_VALUE);
private readonly type: OffsetType;
private readonly value: bigint;
private constructor(type: OffsetType, value: bigint) {
this.type = type;
this.value = value;
}
/**
* Create an OffsetOption from a specific offset.
*
* @param offset - The offset value (must be >= 0)
* @return OffsetOption instance
* @throws Error if offset is negative
*/
static ofOffset(offset: number | bigint): OffsetOption {
const value = typeof offset === 'number' ? BigInt(offset) : offset;
if (value < BigInt(0)) {
throw new Error('offset must be greater than or equal to 0');
}
return new OffsetOption(OffsetType.OFFSET, value);
}
/**
* Create an OffsetOption from tail N messages.
*
* @param tailN - Number of messages from the tail (must be >= 0)
* @return OffsetOption instance
* @throws Error if tailN is negative
*/
static ofTailN(tailN: number | bigint): OffsetOption {
const value = typeof tailN === 'number' ? BigInt(tailN) : tailN;
if (value < BigInt(0)) {
throw new Error('tailN must be greater than or equal to 0');
}
return new OffsetOption(OffsetType.TAIL_N, value);
}
/**
* Create an OffsetOption from a timestamp.
*
* @param timestamp - Unix timestamp in milliseconds (must be >= 0)
* @return OffsetOption instance
* @throws Error if timestamp is negative
*/
static ofTimestamp(timestamp: number | bigint): OffsetOption {
const value = typeof timestamp === 'number' ? BigInt(timestamp) : timestamp;
if (value < BigInt(0)) {
throw new Error('timestamp must be greater than or equal to 0');
}
return new OffsetOption(OffsetType.TIMESTAMP, value);
}
/**
* Get the type of this OffsetOption.
*
* @return OffsetType
*/
getType(): OffsetType {
return this.type;
}
/**
* Get the value of this OffsetOption.
*
* @return Value as bigint
*/
getValue(): bigint {
return this.value;
}
/**
* Returns a string representation of this OffsetOption.
*
* @return String representation
*/
toString(): string {
return `OffsetOption{type=${OffsetType[this.type]}, value=${this.value}}`;
}
/**
* Validate that a bigint value is within the safe number range.
*
* @param value - The bigint value to validate
* @throws Error if value is out of safe number range
*/
private validateSafeNumberRange(value: bigint): void {
if (value > BigInt(Number.MAX_SAFE_INTEGER) || value < BigInt(Number.MIN_SAFE_INTEGER)) {
throw new Error(`Value ${value} is out of safe number range`);
}
}
/**
* Convert this OffsetOption to ProtoBuf OffsetOption.
*
* @return ProtoBuf OffsetOption instance
*/
toProtobuf(): ProtoOffsetOption {
const proto = new ProtoOffsetOption();
switch (this.type) {
case OffsetType.POLICY: {
// Map our policy values to ProtoBuf Policy enum
// POLICY_LAST_VALUE (0) -> Policy.LAST (0)
// POLICY_MIN_VALUE (1) -> Policy.MIN (1)
// POLICY_MAX_VALUE (2) -> Policy.MAX (2)
this.validateSafeNumberRange(this.value);
proto.setPolicy(Number(this.value));
break;
}
case OffsetType.OFFSET: {
this.validateSafeNumberRange(this.value);
proto.setOffset(Number(this.value));
break;
}
case OffsetType.TAIL_N: {
this.validateSafeNumberRange(this.value);
proto.setTailN(Number(this.value));
break;
}
case OffsetType.TIMESTAMP: {
this.validateSafeNumberRange(this.value);
proto.setTimestamp(Number(this.value));
break;
}
default:
throw new Error(`Unknown OffsetType: ${this.type}`);
}
return proto;
}
equals(other: OffsetOption): boolean {
if (this === other) return true;
if (!other) return false;
return this.type === other.type && this.value === other.value;
}
hashCode(): number {
let hash = 17;
// eslint-disable-next-line no-bitwise
hash = (hash * 31 + this.type) | 0;
const valueNum = Number(this.value);
// eslint-disable-next-line no-bitwise
hash = (hash * 31 + valueNum) | 0;
return hash;
}
}