@ably/cli
Version:
Ably CLI for Pub/Sub, Chat and Spaces
199 lines (198 loc) • 8.65 kB
JavaScript
import { Args } from "@oclif/core";
import chalk from "chalk";
import { SpacesBaseCommand } from "../../../spaces-base-command.js";
export default class SpacesLocksGetAll extends SpacesBaseCommand {
static args = {
spaceId: Args.string({
description: "Space ID to get locks from",
required: true,
}),
};
static description = "Get all current locks in a space";
static examples = [
"$ ably spaces locks get-all my-space",
"$ ably spaces locks get-all my-space --json",
"$ ably spaces locks get-all my-space --pretty-json",
];
static flags = {
...SpacesBaseCommand.globalFlags,
};
// Declare class properties
realtimeClient = null;
spacesClient = null;
space = null;
async run() {
const { args, flags } = await this.parse(SpacesLocksGetAll);
const { spaceId } = args;
try {
// Create Spaces client using setupSpacesClient
const setupResult = await this.setupSpacesClient(flags, spaceId);
this.realtimeClient = setupResult.realtimeClient;
this.spacesClient = setupResult.spacesClient;
this.space = setupResult.space;
if (!this.realtimeClient || !this.spacesClient || !this.space) {
this.error("Failed to initialize clients or space");
return;
}
// Make sure we have a connection before proceeding
await new Promise((resolve, reject) => {
const checkConnection = () => {
const { state } = this.realtimeClient.connection;
if (state === "connected") {
resolve();
}
else if (state === "failed" ||
state === "closed" ||
state === "suspended") {
reject(new Error(`Connection failed with state: ${state}`));
}
else {
setTimeout(checkConnection, 100);
}
};
checkConnection();
});
// Get the space
this.log(`Connecting to space: ${chalk.cyan(spaceId)}...`);
await this.space.enter();
// Wait for space to be properly entered before fetching locks
await new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error("Timed out waiting for space connection"));
}, 5000);
const checkSpaceStatus = () => {
try {
if (this.realtimeClient.connection.state === "connected") {
clearTimeout(timeout);
this.log(`${chalk.green("Connected to space:")} ${chalk.cyan(spaceId)}`);
resolve();
}
else if (this.realtimeClient.connection.state === "failed" ||
this.realtimeClient.connection.state === "closed" ||
this.realtimeClient.connection.state === "suspended") {
clearTimeout(timeout);
reject(new Error(`Space connection failed with connection state: ${this.realtimeClient.connection.state}`));
}
else {
setTimeout(checkSpaceStatus, 100);
}
}
catch (error) {
clearTimeout(timeout);
reject(error);
}
};
checkSpaceStatus();
});
// Get all locks
if (!this.shouldOutputJson(flags)) {
this.log(`Fetching locks for space ${chalk.cyan(spaceId)}...`);
}
let locks = [];
try {
const result = await this.space.locks.getAll();
locks = Array.isArray(result) ? result : [];
const validLocks = locks.filter((lock) => {
if (!lock || !lock.id)
return false;
return true;
});
if (this.shouldOutputJson(flags)) {
this.log(this.formatJsonOutput({
locks: validLocks.map((lock) => ({
attributes: lock.attributes || {},
holder: lock.member?.clientId || null,
id: lock.id,
status: lock.status || "unknown",
})),
spaceId,
success: true,
timestamp: new Date().toISOString(),
}, flags));
}
else if (!validLocks || validLocks.length === 0) {
this.log(chalk.yellow("No locks are currently active in this space."));
}
else {
const lockCount = validLocks.length;
this.log(`\n${chalk.cyan("Current locks")} (${chalk.bold(String(lockCount))}):\n`);
validLocks.forEach((lock) => {
try {
this.log(`- ${chalk.blue(lock.id)}:`);
this.log(` ${chalk.dim("Status:")} ${lock.status || "unknown"}`);
this.log(` ${chalk.dim("Holder:")} ${lock.member?.clientId || "None"}`);
if (lock.attributes && Object.keys(lock.attributes).length > 0) {
this.log(` ${chalk.dim("Attributes:")} ${JSON.stringify(lock.attributes, null, 2)}`);
}
}
catch (error) {
this.log(`- ${chalk.red("Error displaying lock item")}: ${error instanceof Error ? error.message : String(error)}`);
}
});
}
}
catch (error) {
if (this.shouldOutputJson(flags)) {
this.log(this.formatJsonOutput({
error: error instanceof Error ? error.message : String(error),
spaceId: args.spaceId,
status: "error",
success: false,
}, flags));
}
else {
this.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
}
}
try {
await this.space.leave();
if (this.shouldOutputJson(flags)) {
this.log(this.formatJsonOutput({
spaceId,
status: "left",
success: true,
}, flags));
}
else {
this.log(chalk.green("\nSuccessfully disconnected."));
}
}
catch (error) {
if (this.shouldOutputJson(flags)) {
this.log(this.formatJsonOutput({
error: error instanceof Error ? error.message : String(error),
spaceId: args.spaceId,
status: "error",
success: false,
}, flags));
}
else {
this.log(chalk.yellow(`Error leaving space: ${error instanceof Error ? error.message : String(error)}`));
}
}
}
catch (error) {
if (this.shouldOutputJson(flags)) {
this.log(this.formatJsonOutput({
error: error instanceof Error ? error.message : String(error),
spaceId: args.spaceId,
status: "error",
success: false,
}, flags));
}
else {
this.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
}
}
finally {
try {
if (this.realtimeClient) {
this.realtimeClient.close();
}
}
catch (closeError) {
this.log(chalk.yellow(`Error closing client: ${closeError instanceof Error ? closeError.message : String(closeError)}`));
}
}
}
}