All files / lib/commands CLUSTER_NODES.ts

96.67% Statements 29/30
70% Branches 7/10
100% Functions 5/5
96.67% Lines 29/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 971x 1x     1x 1x 1x                                                     1x 1x 1x   1x 1x   1x 2x 2x                     2x 1x 1x 1x 1x     1x       1x 1x 1x               1x 1x     1x         1x       2x 2x   2x            
export function transformArguments(): Array<string> {
    return ['CLUSTER', 'NODES'];
}
 
export enum RedisClusterNodeLinkStates {
    CONNECTED = 'connected',
    DISCONNECTED = 'disconnected'
}
 
interface RedisClusterNodeTransformedUrl {
    host: string;
    port: number;
    cport: number;
}
 
export interface RedisClusterReplicaNode extends RedisClusterNodeTransformedUrl {
    id: string;
    url: string;
    flags: Array<string>,
    pingSent: number;
    pongRecv: number;
    configEpoch: number;
    linkState: RedisClusterNodeLinkStates;
}
 
export interface RedisClusterMasterNode extends RedisClusterReplicaNode {
    slots: Array<{
        from: number,
        to: number
    }>;
    replicas: Array<RedisClusterReplicaNode>;
}
 
export function transformReply(reply: string): Array<RedisClusterMasterNode> {
    const lines = reply.split('\n');
    lines.pop(); // last line is empty
 
    const mastersMap = new Map<string, RedisClusterMasterNode>(),
        replicasMap = new Map<string, Array<RedisClusterReplicaNode>>();
 
    for (const line of lines) {
        const [id, url, flags, masterId, pingSent, pongRecv, configEpoch, linkState, ...slots] = line.split(' '),
            node = {
                id,
                url,
                ...transformNodeUrl(url),
                flags: flags.split(','),
                pingSent: Number(pingSent),
                pongRecv: Number(pongRecv),
                configEpoch: Number(configEpoch),
                linkState: (linkState as RedisClusterNodeLinkStates)
            };
 
        if (masterId === '-') {
            let replicas = replicasMap.get(id);
            Eif (!replicas) {
                replicas = [];
                replicasMap.set(id, replicas);
            }
 
            mastersMap.set(id, {
                ...node,
                slots: slots.map(slot => {
                    // TODO: importing & exporting (https://redis.io/commands/cluster-nodes#special-slot-entries)
                    const [fromString, toString] = slot.split('-', 2),
                        from = Number(fromString);
                    return {
                        from,
                        to: toString ? Number(toString) : from
                    };
                }),
                replicas
            });
        } else {
            const replicas = replicasMap.get(masterId);
            Iif (!replicas) {
                replicasMap.set(masterId, [node]);
            } else {
                replicas.push(node);
            }
        }
    }
 
    return [...mastersMap.values()];
}
 
function transformNodeUrl(url: string): RedisClusterNodeTransformedUrl {
    const indexOfColon = url.indexOf(':'),
        indexOfAt = url.indexOf('@', indexOfColon);
 
    return {
        host: url.substring(0, indexOfColon),
        port: Number(url.substring(indexOfColon + 1, indexOfAt)),
        cport: Number(url.substring(indexOfAt + 1))
    };
}