feat(rabbitmq): add message queue management support
This commit is contained in:
1 parent
503d6748d4
commit
39e554369f
76 files changed
+14915
-707
No files matched your search
+17
@@ -17,4 +17,21 @@ describe("mqAuth", () => {
|
||||
}),
|
||||
).toBe("basic");
|
||||
});
|
||||
|
||||
it("allows basic auth for RabbitMQ", () => {
|
||||
expect(isMqAuthKindAllowedForSystem("rabbitmq", "basic")).toBe(true);
|
||||
expect(isMqAuthKindAllowedForSystem("rabbitmq", "kerberos")).toBe(false);
|
||||
expect(isMqAuthKindAllowedForSystem("rabbitmq", "token")).toBe(false);
|
||||
});
|
||||
|
||||
it("detects RabbitMQ basic auth from config", () => {
|
||||
expect(
|
||||
detectMqUiAuthKind({
|
||||
systemKind: "rabbitmq",
|
||||
authKind: "basic",
|
||||
saslMechanism: "",
|
||||
jaasConfig: "",
|
||||
}),
|
||||
).toBe("basic");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { normalizeRabbitmqAddresses } from "@/lib/connection/rabbitmqAddresses";
|
||||
|
||||
describe("RabbitMQ addresses", () => {
|
||||
it("keeps comma-separated addresses", () => {
|
||||
expect(normalizeRabbitmqAddresses("node1:5672, node2:5672")).toBe("node1:5672,node2:5672");
|
||||
});
|
||||
|
||||
it("appends the default AMQP port when missing", () => {
|
||||
expect(normalizeRabbitmqAddresses("127.0.0.1")).toBe("127.0.0.1:5672");
|
||||
expect(normalizeRabbitmqAddresses("node1, node2:5673")).toBe("node1:5672,node2:5673");
|
||||
});
|
||||
|
||||
it("normalizes common address separators to commas", () => {
|
||||
expect(normalizeRabbitmqAddresses("node1:5672;node2:5672,node3:5672\nnode4:5672 node5:5672")).toBe("node1:5672,node2:5672,node3:5672,node4:5672,node5:5672");
|
||||
});
|
||||
|
||||
it("keeps IPv6 addresses", () => {
|
||||
expect(normalizeRabbitmqAddresses("[::1]:5672;[2001:db8::1]:5672")).toBe("[::1]:5672,[2001:db8::1]:5672");
|
||||
});
|
||||
|
||||
it("rejects empty addresses", () => {
|
||||
expect(() => normalizeRabbitmqAddresses(" ")).toThrow("RabbitMQ addresses are required");
|
||||
});
|
||||
|
||||
it("rejects addresses with URL schemes", () => {
|
||||
expect(() => normalizeRabbitmqAddresses("amqp://node1:5672,node2:5672")).toThrow("RabbitMQ addresses must be host:port values without a URL scheme");
|
||||
});
|
||||
|
||||
it("rejects invalid address values", () => {
|
||||
expect(() => normalizeRabbitmqAddresses("node1:5672/path,node2:5672")).toThrow("RabbitMQ addresses are invalid");
|
||||
});
|
||||
});
|
||||
@@ -15,6 +15,7 @@ export function agentDriverInstallKey(dbType: DatabaseType | undefined, driverPr
|
||||
if (dbType === "mq") {
|
||||
if (driverProfile === "kafka") return "kafka";
|
||||
if (driverProfile === "rocketmq") return "rocketmq";
|
||||
if (driverProfile === "rabbitmq") return "rabbitmq";
|
||||
return undefined;
|
||||
}
|
||||
return driverProfile && driverProfile !== dbType ? driverProfile : dbType;
|
||||
|
||||
@@ -5,10 +5,12 @@ export type MqUiAuthKind = MqAuthKind | "kerberos";
|
||||
|
||||
const KAFKA_AUTH_KINDS = new Set<MqUiAuthKind>(["none", "basic", "kerberos"]);
|
||||
const ROCKETMQ_AUTH_KINDS = new Set<MqUiAuthKind>(["none", "basic"]);
|
||||
const RABBITMQ_AUTH_KINDS = new Set<MqUiAuthKind>(["none", "basic"]);
|
||||
|
||||
export function isMqAuthKindAllowedForSystem(systemKind: MqSystemKind, authKind: MqUiAuthKind): boolean {
|
||||
if (systemKind === "kafka") return KAFKA_AUTH_KINDS.has(authKind);
|
||||
if (systemKind === "rocketmq") return ROCKETMQ_AUTH_KINDS.has(authKind);
|
||||
if (systemKind === "rabbitmq") return RABBITMQ_AUTH_KINDS.has(authKind);
|
||||
return authKind !== "kerberos";
|
||||
}
|
||||
|
||||
@@ -22,6 +24,9 @@ export function detectMqUiAuthKind({ systemKind, authKind, saslMechanism, jaasCo
|
||||
if (systemKind === "rocketmq") {
|
||||
return authKind === "basic" ? "basic" : "none";
|
||||
}
|
||||
if (systemKind === "rabbitmq") {
|
||||
return authKind === "basic" ? "basic" : "none";
|
||||
}
|
||||
|
||||
return authKind || "none";
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
const RABBITMQ_ADDRESS_SEPARATOR = /[\s,;,;]+/u;
|
||||
const RABBITMQ_DEFAULT_PORT = "5672";
|
||||
|
||||
function requireRabbitmqAddresses(value: string): string {
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) throw new Error("RabbitMQ addresses are required");
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
function normalizeRabbitmqAddress(address: string): string {
|
||||
if (address.includes("://")) {
|
||||
throw new Error("RabbitMQ addresses must be host:port values without a URL scheme");
|
||||
}
|
||||
let parsed: URL;
|
||||
try {
|
||||
parsed = new URL(`amqp://${address}`);
|
||||
} catch {
|
||||
throw new Error("RabbitMQ addresses are invalid");
|
||||
}
|
||||
if (!parsed.hostname || parsed.username || parsed.password || parsed.search || parsed.hash || (parsed.pathname && parsed.pathname !== "/")) {
|
||||
throw new Error("RabbitMQ addresses are invalid");
|
||||
}
|
||||
return parsed.port ? address : `${address}:${RABBITMQ_DEFAULT_PORT}`;
|
||||
}
|
||||
|
||||
export function normalizeRabbitmqAddresses(value: string): string {
|
||||
const addresses = requireRabbitmqAddresses(value)
|
||||
.split(RABBITMQ_ADDRESS_SEPARATOR)
|
||||
.map((address) => address.trim())
|
||||
.filter(Boolean)
|
||||
.map(normalizeRabbitmqAddress);
|
||||
if (!addresses.length) throw new Error("RabbitMQ addresses are required");
|
||||
return addresses.join(",");
|
||||
}
|
||||
Reference in new issue
Block a user