blob: 2d51f420fe80fc3ba9a718ba47ce8ceaf86b9896 [file]
// 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.
//
import { deserializeError } from '../error.utils.js';
import {
type ClusterNodeRoleKey,
type ClusterNodeStatusKey,
mapClusterNodeRole,
mapClusterNodeStatus,
} from './cluster.type.js';
export type TransportEndpoints = {
tcp: number
quic: number
http: number
websocket: number
}
export type ClusterNode = {
name: string
ip: string
endpoints: TransportEndpoints
role: ClusterNodeRoleKey
status: ClusterNodeStatusKey
}
type DeserializedClusterNode = { length: number, data: ClusterNode }
const CLUSTER_NODE_MIN_BUFFER_SIZE = 18; // 4 + 1 + 4 + 1 + 8 (endpoints) + 1 + 1;
export const deserializeNode = (b: Buffer, pos = 0): DeserializedClusterNode => {
if (b.length - pos < CLUSTER_NODE_MIN_BUFFER_SIZE)
deserializeError(
'cluster node', pos, b.length, CLUSTER_NODE_MIN_BUFFER_SIZE
);
const startPos = pos;
// Read name
const nameLen = b.readUInt32LE(pos);
if (b.length - pos < 4 + nameLen)
deserializeError(
'cluster node', pos, b.length, 4 + nameLen, { nameLen }
);
const name = b.subarray(pos + 4, pos + 4 + nameLen).toString();
pos += nameLen + 4;
// Read IP
const ipLen = b.readUInt32LE(pos);
if (b.length - pos < 4 + ipLen)
deserializeError(
'cluster node', pos, b.length, 4 + ipLen, { nameLen, name, ipLen }
);
const ip = b.subarray(pos + 4, pos + 4 + ipLen).toString();
pos += ipLen + 4;
// Read transport endpoints (4 ports, each u16)
if (b.length - pos < 8)
deserializeError(
'cluster node endpoints', pos, b.length, 8, { nameLen, name, ipLen, ip }
);
const endpoints: TransportEndpoints = {
tcp: b.readUInt16LE(pos),
quic: b.readUInt16LE(pos + 2),
http: b.readUInt16LE(pos + 4),
websocket: b.readUInt16LE(pos + 6)
};
pos += 8;
// Read role and status
if (b.length - pos < 2)
deserializeError(
'cluster node', pos, b.length, 2, { nameLen, name, ipLen, ip }
);
const role = mapClusterNodeRole(b.readUInt8(pos));
pos += 1;
const status = mapClusterNodeStatus(b.readUInt8(pos));
pos += 1;
return {
length: pos - startPos,
data: {
name,
ip,
endpoints,
role,
status
}
}
};
export type ClusterMetadata = {
// Name of the cluster.
name: string,
// List of all nodes in the cluster.
nodes: ClusterNode[],
};
// min = 4 + 1 + 4 + CLUSTER_NODE_MIN_BUFFER_SIZE;
const CLUSTER_METADATA_MIN_SIZE = 8 + CLUSTER_NODE_MIN_BUFFER_SIZE;
export const deserializeMetadata = (b: Buffer, pos = 0): ClusterMetadata => {
if (b.length - pos < CLUSTER_METADATA_MIN_SIZE)
deserializeError(
'cluster metadata', pos, b.length, CLUSTER_METADATA_MIN_SIZE
);
// Read cluster name
const nameLen = b.readUInt32LE(pos);
if (b.length - pos < 4 + nameLen)
deserializeError(
'cluster metadata', pos, b.length, 4 + nameLen, { nameLen }
);
const name = b.subarray(pos + 4, pos + 4 + nameLen).toString();
pos += nameLen + 4;
// Read nodes count
if (b.length - pos < 4)
deserializeError(
'cluster metadata', pos, b.length, 4, { nameLen, name }
);
const nodeCount = b.readUInt32LE(pos);
pos += 4;
// Read nodes array
const nodes: ClusterNode[] = [];
for (let i = 0; i < nodeCount; i++) {
const { length, data } = deserializeNode(b, pos);
nodes.push(data);
pos += length;
}
return {
name,
nodes
}
};