mirror of
https://github.com/apache/rocketmq-dashboard.git
synced 2025-09-10 03:29:59 +08:00
This commit is contained in:
@@ -49,7 +49,7 @@ const remoteApi = {
|
||||
if (_redirectHandler) {
|
||||
_redirectHandler(); // 如果设置了重定向处理函数,则调用它
|
||||
}
|
||||
return { __isRedirectHandled: true };
|
||||
return {__isRedirectHandled: true};
|
||||
}
|
||||
|
||||
return response;
|
||||
@@ -77,24 +77,24 @@ const remoteApi = {
|
||||
listUsers: async (brokerAddress) => {
|
||||
const params = new URLSearchParams();
|
||||
if (brokerAddress) params.append('brokerAddress', brokerAddress);
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl(`/acl/listUsers?${params.toString()}`));
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl(`/acl/acls.query?${params.toString()}`));
|
||||
return await response.json();
|
||||
},
|
||||
|
||||
createUser: async (brokerAddress, userInfo) => {
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl('/acl/createUser'), {
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl('/acl/createUser.do'), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ brokerAddress, userInfo })
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({brokerAddress, userInfo})
|
||||
});
|
||||
return await response.json(); // 返回字符串消息
|
||||
},
|
||||
|
||||
updateUser: async (brokerAddress, userInfo) => {
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl('/acl/updateUser'), {
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl('/acl/updateUser.do'), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ brokerAddress, userInfo })
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({brokerAddress, userInfo})
|
||||
});
|
||||
return await response.json();
|
||||
},
|
||||
@@ -103,7 +103,7 @@ const remoteApi = {
|
||||
const params = new URLSearchParams();
|
||||
if (brokerAddress) params.append('brokerAddress', brokerAddress);
|
||||
params.append('username', username);
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl(`/acl/deleteUser?${params.toString()}`), {
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl(`/acl/deleteUser.do?${params.toString()}`), {
|
||||
method: 'DELETE'
|
||||
});
|
||||
return await response.json();
|
||||
@@ -114,24 +114,24 @@ const remoteApi = {
|
||||
const params = new URLSearchParams();
|
||||
if (brokerAddress) params.append('brokerAddress', brokerAddress);
|
||||
if (searchParam) params.append('searchParam', searchParam);
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl(`/acl/listAcls?${params.toString()}`));
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl(`/acl/acls.query?${params.toString()}`));
|
||||
return await response.json();
|
||||
},
|
||||
|
||||
createAcl: async (brokerAddress, subject, policies) => {
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl('/acl/createAcl'), {
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl('/acl/createAcl.do'), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ brokerAddress, subject, policies })
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({brokerAddress, subject, policies})
|
||||
});
|
||||
return await response.json();
|
||||
},
|
||||
|
||||
updateAcl: async (brokerAddress, subject, policies) => {
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl('/acl/updateAcl'), {
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl('/acl/updateAcl.do'), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ brokerAddress, subject, policies })
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({brokerAddress, subject, policies})
|
||||
});
|
||||
return await response.json();
|
||||
},
|
||||
@@ -141,7 +141,7 @@ const remoteApi = {
|
||||
if (brokerAddress) params.append('brokerAddress', brokerAddress);
|
||||
params.append('subject', subject);
|
||||
if (resource) params.append('resource', resource);
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl(`/acl/deleteAcl?${params.toString()}`), {
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl(`/acl/deleteAcl.do?${params.toString()}`), {
|
||||
method: 'DELETE'
|
||||
});
|
||||
return await response.json();
|
||||
@@ -159,7 +159,7 @@ const remoteApi = {
|
||||
return data
|
||||
} catch (error) {
|
||||
console.error("Error querying message by ID:", error);
|
||||
callback({ status: 1, errMsg: "Failed to query message by ID" });
|
||||
callback({status: 1, errMsg: "Failed to query message by ID"});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -197,7 +197,7 @@ const remoteApi = {
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Error querying DLQ messages by consumer group:", error);
|
||||
return { status: 1, errMsg: "Failed to query DLQ messages by consumer group" };
|
||||
return {status: 1, errMsg: "Failed to query DLQ messages by consumer group"};
|
||||
}
|
||||
},
|
||||
resendDlqMessage: async (msgId, consumerGroup, topic) => {
|
||||
@@ -217,7 +217,7 @@ const remoteApi = {
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Error resending DLQ message:", error);
|
||||
return { status: 1, errMsg: "Failed to resend DLQ message" };
|
||||
return {status: 1, errMsg: "Failed to resend DLQ message"};
|
||||
}
|
||||
},
|
||||
exportDlqMessage: async (msgId, consumerGroup) => {
|
||||
@@ -236,7 +236,7 @@ const remoteApi = {
|
||||
|
||||
if (!newWindow) {
|
||||
// 浏览器可能会阻止弹窗,需要用户允许
|
||||
return { status: 1, errMsg: "Failed to open new window. Please allow pop-ups for this site." };
|
||||
return {status: 1, errMsg: "Failed to open new window. Please allow pop-ups for this site."};
|
||||
}
|
||||
|
||||
// 2. 将 JSON 数据格式化后写入新窗口
|
||||
@@ -247,10 +247,10 @@ const remoteApi = {
|
||||
newWindow.document.write('</body></html>');
|
||||
newWindow.document.close(); // 关闭文档流,确保内容显示
|
||||
|
||||
return { status: 0, msg: "导出请求成功,内容已在新页面显示" };
|
||||
return {status: 0, msg: "导出请求成功,内容已在新页面显示"};
|
||||
} catch (error) {
|
||||
console.error("Error exporting DLQ message:", error);
|
||||
return { status: 1, errMsg: "Failed to export DLQ message: " + error.message };
|
||||
return {status: 1, errMsg: "Failed to export DLQ message: " + error.message};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -267,7 +267,7 @@ const remoteApi = {
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Error batch resending DLQ messages:", error);
|
||||
return { status: 1, errMsg: "Failed to batch resend DLQ messages" };
|
||||
return {status: 1, errMsg: "Failed to batch resend DLQ messages"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -372,7 +372,7 @@ const remoteApi = {
|
||||
callback(data);
|
||||
} catch (error) {
|
||||
console.error("Error fetching producer connection list:", error);
|
||||
callback({ status: 1, errMsg: "Failed to fetch producer connection list" }); // Simulate error response
|
||||
callback({status: 1, errMsg: "Failed to fetch producer connection list"}); // Simulate error response
|
||||
}
|
||||
},
|
||||
|
||||
@@ -383,7 +383,7 @@ const remoteApi = {
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Error fetching consumer group list:", error);
|
||||
return { status: 1, errMsg: "Failed to fetch consumer group list" };
|
||||
return {status: 1, errMsg: "Failed to fetch consumer group list"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -394,7 +394,7 @@ const remoteApi = {
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error(`Error refreshing consumer group ${consumerGroup}:`, error);
|
||||
return { status: 1, errMsg: `Failed to refresh consumer group ${consumerGroup}` };
|
||||
return {status: 1, errMsg: `Failed to refresh consumer group ${consumerGroup}`};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -405,7 +405,7 @@ const remoteApi = {
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Error refreshing all consumer groups:", error);
|
||||
return { status: 1, errMsg: "Failed to refresh all consumer groups" };
|
||||
return {status: 1, errMsg: "Failed to refresh all consumer groups"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -416,7 +416,7 @@ const remoteApi = {
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error(`Error fetching monitor config for ${consumeGroupName}:`, error);
|
||||
return { status: 1, errMsg: `Failed to fetch monitor config for ${consumeGroupName}` };
|
||||
return {status: 1, errMsg: `Failed to fetch monitor config for ${consumeGroupName}`};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -428,13 +428,13 @@ const remoteApi = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ consumeGroupName, minCount, maxDiffTotal })
|
||||
body: JSON.stringify({consumeGroupName, minCount, maxDiffTotal})
|
||||
});
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Error creating or updating consumer monitor:", error);
|
||||
return { status: 1, errMsg: "Failed to create or update consumer monitor" };
|
||||
return {status: 1, errMsg: "Failed to create or update consumer monitor"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -445,7 +445,7 @@ const remoteApi = {
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error(`Error fetching broker name list for ${consumerGroup}:`, error);
|
||||
return { status: 1, errMsg: `Failed to fetch broker name list for ${consumerGroup}` };
|
||||
return {status: 1, errMsg: `Failed to fetch broker name list for ${consumerGroup}`};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -456,13 +456,13 @@ const remoteApi = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ groupName, brokerNameList })
|
||||
body: JSON.stringify({groupName, brokerNameList})
|
||||
});
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error(`Error deleting consumer group ${groupName}:`, error);
|
||||
return { status: 1, errMsg: `Failed to delete consumer group ${groupName}` };
|
||||
return {status: 1, errMsg: `Failed to delete consumer group ${groupName}`};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -473,7 +473,7 @@ const remoteApi = {
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error(`Error fetching consumer config for ${consumerGroup}:`, error);
|
||||
return { status: 1, errMsg: `Failed to fetch consumer config for ${consumerGroup}` };
|
||||
return {status: 1, errMsg: `Failed to fetch consumer config for ${consumerGroup}`};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -490,7 +490,7 @@ const remoteApi = {
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Error creating or updating consumer:", error);
|
||||
return { status: 1, errMsg: "Failed to create or update consumer" };
|
||||
return {status: 1, errMsg: "Failed to create or update consumer"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -501,7 +501,7 @@ const remoteApi = {
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error(`Error fetching topics for consumer group ${consumerGroup}:`, error);
|
||||
return { status: 1, errMsg: `Failed to fetch topics for consumer group ${consumerGroup}` };
|
||||
return {status: 1, errMsg: `Failed to fetch topics for consumer group ${consumerGroup}`};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -512,7 +512,7 @@ const remoteApi = {
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error(`Error fetching consumer connections for ${consumerGroup}:`, error);
|
||||
return { status: 1, errMsg: `Failed to fetch consumer connections for ${consumerGroup}` };
|
||||
return {status: 1, errMsg: `Failed to fetch consumer connections for ${consumerGroup}`};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -523,7 +523,7 @@ const remoteApi = {
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error(`Error fetching running info for client ${clientId} in group ${consumerGroup}:`, error);
|
||||
return { status: 1, errMsg: `Failed to fetch running info for client ${clientId} in group ${consumerGroup}` };
|
||||
return {status: 1, errMsg: `Failed to fetch running info for client ${clientId} in group ${consumerGroup}`};
|
||||
}
|
||||
},
|
||||
queryTopicList: async () => {
|
||||
@@ -532,7 +532,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error fetching topic list:", error);
|
||||
return { status: 1, errMsg: "Failed to fetch topic list" };
|
||||
return {status: 1, errMsg: "Failed to fetch topic list"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -549,7 +549,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error deleting topic:", error);
|
||||
return { status: 1, errMsg: "Failed to delete topic" };
|
||||
return {status: 1, errMsg: "Failed to delete topic"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -559,7 +559,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error fetching topic stats:", error);
|
||||
return { status: 1, errMsg: "Failed to fetch topic stats" };
|
||||
return {status: 1, errMsg: "Failed to fetch topic stats"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -569,7 +569,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error fetching topic route:", error);
|
||||
return { status: 1, errMsg: "Failed to fetch topic route" };
|
||||
return {status: 1, errMsg: "Failed to fetch topic route"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -579,7 +579,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error fetching topic consumers:", error);
|
||||
return { status: 1, errMsg: "Failed to fetch topic consumers" };
|
||||
return {status: 1, errMsg: "Failed to fetch topic consumers"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -589,7 +589,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error fetching consumer groups:", error);
|
||||
return { status: 1, errMsg: "Failed to fetch consumer groups" };
|
||||
return {status: 1, errMsg: "Failed to fetch consumer groups"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -599,7 +599,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error fetching topic config:", error);
|
||||
return { status: 1, errMsg: "Failed to fetch topic config" };
|
||||
return {status: 1, errMsg: "Failed to fetch topic config"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -609,7 +609,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error fetching cluster list:", error);
|
||||
return { status: 1, errMsg: "Failed to fetch cluster list" };
|
||||
return {status: 1, errMsg: "Failed to fetch cluster list"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -625,7 +625,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error creating/updating topic:", error);
|
||||
return { status: 1, errMsg: "Failed to create/update topic" };
|
||||
return {status: 1, errMsg: "Failed to create/update topic"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -641,7 +641,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error resetting consumer offset:", error);
|
||||
return { status: 1, errMsg: "Failed to reset consumer offset" };
|
||||
return {status: 1, errMsg: "Failed to reset consumer offset"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -657,7 +657,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error skipping message accumulate:", error);
|
||||
return { status: 1, errMsg: "Failed to skip message accumulate" };
|
||||
return {status: 1, errMsg: "Failed to skip message accumulate"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -673,7 +673,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error sending topic message:", error);
|
||||
return { status: 1, errMsg: "Failed to send topic message" };
|
||||
return {status: 1, errMsg: "Failed to send topic message"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -684,12 +684,12 @@ const remoteApi = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ brokerName, topic })
|
||||
body: JSON.stringify({brokerName, topic})
|
||||
});
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error deleting topic by broker:", error);
|
||||
return { status: 1, errMsg: "Failed to delete topic by broker" };
|
||||
return {status: 1, errMsg: "Failed to delete topic by broker"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -700,7 +700,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error fetching ops home page data:", error);
|
||||
return { status: 1, errMsg: "Failed to fetch ops home page data" };
|
||||
return {status: 1, errMsg: "Failed to fetch ops home page data"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -712,7 +712,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error updating NameServer address:", error);
|
||||
return { status: 1, errMsg: "Failed to update NameServer address" };
|
||||
return {status: 1, errMsg: "Failed to update NameServer address"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -724,7 +724,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error adding NameServer address:", error);
|
||||
return { status: 1, errMsg: "Failed to add NameServer address" };
|
||||
return {status: 1, errMsg: "Failed to add NameServer address"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -736,7 +736,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error updating VIP Channel status:", error);
|
||||
return { status: 1, errMsg: "Failed to update VIP Channel status" };
|
||||
return {status: 1, errMsg: "Failed to update VIP Channel status"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -748,7 +748,7 @@ const remoteApi = {
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error updating TLS status:", error);
|
||||
return { status: 1, errMsg: "Failed to update TLS status" };
|
||||
return {status: 1, errMsg: "Failed to update TLS status"};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -759,7 +759,7 @@ const remoteApi = {
|
||||
callback(data);
|
||||
} catch (error) {
|
||||
console.error("Error fetching cluster list:", error);
|
||||
callback({ status: 1, errMsg: "Failed to fetch cluster list" });
|
||||
callback({status: 1, errMsg: "Failed to fetch cluster list"});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -767,16 +767,16 @@ const remoteApi = {
|
||||
try {
|
||||
const url = new URL(remoteApi.buildUrl('/dashboard/broker.query'));
|
||||
url.searchParams.append('date', date);
|
||||
const response = await remoteApi._fetch(url.toString(), { signal: AbortSignal.timeout(15000) }); // 15s timeout
|
||||
const response = await remoteApi._fetch(url.toString(), {signal: AbortSignal.timeout(15000)}); // 15s timeout
|
||||
const data = await response.json();
|
||||
callback(data);
|
||||
} catch (error) {
|
||||
if (error.name === 'TimeoutError') {
|
||||
console.error("Broker history data request timed out:", error);
|
||||
callback({ status: 1, errMsg: "Request timed out for broker history data" });
|
||||
callback({status: 1, errMsg: "Request timed out for broker history data"});
|
||||
} else {
|
||||
console.error("Error fetching broker history data:", error);
|
||||
callback({ status: 1, errMsg: "Failed to fetch broker history data" });
|
||||
callback({status: 1, errMsg: "Failed to fetch broker history data"});
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -786,32 +786,32 @@ const remoteApi = {
|
||||
const url = new URL(remoteApi.buildUrl('/dashboard/topic.query'));
|
||||
url.searchParams.append('date', date);
|
||||
url.searchParams.append('topicName', topicName);
|
||||
const response = await remoteApi._fetch(url.toString(), { signal: AbortSignal.timeout(15000) }); // 15s timeout
|
||||
const response = await remoteApi._fetch(url.toString(), {signal: AbortSignal.timeout(15000)}); // 15s timeout
|
||||
const data = await response.json();
|
||||
callback(data);
|
||||
} catch (error) {
|
||||
if (error.name === 'TimeoutError') {
|
||||
console.error("Topic history data request timed out:", error);
|
||||
callback({ status: 1, errMsg: "Request timed out for topic history data" });
|
||||
callback({status: 1, errMsg: "Request timed out for topic history data"});
|
||||
} else {
|
||||
console.error("Error fetching topic history data:", error);
|
||||
callback({ status: 1, errMsg: "Failed to fetch topic history data" });
|
||||
callback({status: 1, errMsg: "Failed to fetch topic history data"});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
queryTopicCurrentData: async (callback) => {
|
||||
try {
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl('/dashboard/topicCurrent.query'), { signal: AbortSignal.timeout(15000) }); // 15s timeout
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl('/dashboard/topicCurrent.query'), {signal: AbortSignal.timeout(15000)}); // 15s timeout
|
||||
const data = await response.json();
|
||||
callback(data);
|
||||
} catch (error) {
|
||||
if (error.name === 'TimeoutError') {
|
||||
console.error("Topic current data request timed out:", error);
|
||||
callback({ status: 1, errMsg: "Request timed out for topic current data" });
|
||||
callback({status: 1, errMsg: "Request timed out for topic current data"});
|
||||
} else {
|
||||
console.error("Error fetching topic current data:", error);
|
||||
callback({ status: 1, errMsg: "Failed to fetch topic current data" });
|
||||
callback({status: 1, errMsg: "Failed to fetch topic current data"});
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -825,7 +825,7 @@ const remoteApi = {
|
||||
callback(data);
|
||||
} catch (error) {
|
||||
console.error("Error fetching broker config:", error);
|
||||
callback({ status: 1, errMsg: "Failed to fetch broker config" });
|
||||
callback({status: 1, errMsg: "Failed to fetch broker config"});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -839,7 +839,7 @@ const remoteApi = {
|
||||
callback(data);
|
||||
} catch (error) {
|
||||
console.error("Error fetching proxy home page:", error);
|
||||
callback({ status: 1, errMsg: "Failed to fetch proxy home page" });
|
||||
callback({status: 1, errMsg: "Failed to fetch proxy home page"});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -850,14 +850,14 @@ const remoteApi = {
|
||||
try {
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl("/proxy/addProxyAddr.do"), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: new URLSearchParams({ newProxyAddr }).toString()
|
||||
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
body: new URLSearchParams({newProxyAddr}).toString()
|
||||
});
|
||||
const data = await response.json();
|
||||
callback(data);
|
||||
} catch (error) {
|
||||
console.error("Error adding proxy address:", error);
|
||||
callback({ status: 1, errMsg: "Failed to add proxy address" });
|
||||
callback({status: 1, errMsg: "Failed to add proxy address"});
|
||||
}
|
||||
},
|
||||
login: async (username, password) => {
|
||||
@@ -882,19 +882,19 @@ const remoteApi = {
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Error logging in:", error);
|
||||
return { status: 1, errMsg: "Failed to log in" };
|
||||
return {status: 1, errMsg: "Failed to log in"};
|
||||
}
|
||||
},
|
||||
|
||||
logout: async () => {
|
||||
try {
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl("/login/logout.do"),{
|
||||
const response = await remoteApi._fetch(remoteApi.buildUrl("/login/logout.do"), {
|
||||
method: 'POST'
|
||||
});
|
||||
return await response.json()
|
||||
}catch (error) {
|
||||
} catch (error) {
|
||||
console.error("Error logging out:", error);
|
||||
return { status: 1, errMsg: "Failed to log out" };
|
||||
return {status: 1, errMsg: "Failed to log out"};
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -939,4 +939,4 @@ const tools = {
|
||||
}
|
||||
};
|
||||
|
||||
export { remoteApi, tools };
|
||||
export {remoteApi, tools};
|
||||
|
@@ -23,6 +23,7 @@ import org.apache.rocketmq.dashboard.model.request.UserUpdateRequest;
|
||||
import org.apache.rocketmq.dashboard.service.impl.AclServiceImpl;
|
||||
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -31,24 +32,23 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@Controller
|
||||
@RequestMapping("/acl")
|
||||
public class AclController {
|
||||
|
||||
@Autowired
|
||||
private AclServiceImpl aclService;
|
||||
|
||||
@GetMapping("/listUsers")
|
||||
@GetMapping("/users.query")
|
||||
@ResponseBody
|
||||
public List<UserInfo> listUsers(@RequestParam(required = false) String brokerAddress) {
|
||||
return aclService.listUsers(brokerAddress);
|
||||
}
|
||||
|
||||
@GetMapping("/listAcls")
|
||||
@GetMapping("/acls.query")
|
||||
@ResponseBody
|
||||
public Object listAcls(
|
||||
@RequestParam(required = false) String brokerAddress,
|
||||
@@ -56,34 +56,34 @@ public class AclController {
|
||||
return aclService.listAcls(brokerAddress, searchParam);
|
||||
}
|
||||
|
||||
@PostMapping("/createAcl")
|
||||
@PostMapping("/createAcl.do")
|
||||
@ResponseBody
|
||||
public Object createAcl(@RequestBody PolicyRequest request) {
|
||||
aclService.createAcl(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
@DeleteMapping("/deleteUser")
|
||||
@DeleteMapping("/deleteUser.do")
|
||||
@ResponseBody
|
||||
public Object deleteUser(@RequestParam(required = false) String brokerAddress, @RequestParam String username) {
|
||||
aclService.deleteUser(brokerAddress, username);
|
||||
return true;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/updateUser", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
|
||||
@RequestMapping(value = "/updateUser.do", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
|
||||
@ResponseBody
|
||||
public Object updateUser(@RequestBody UserUpdateRequest request) {
|
||||
aclService.updateUser(request.getBrokerAddress(), request.getUserInfo());
|
||||
return true;
|
||||
}
|
||||
|
||||
@PostMapping("/createUser")
|
||||
@PostMapping("/createUser.do")
|
||||
public Object createUser(@RequestBody UserCreateRequest request) {
|
||||
aclService.createUser(request.getBrokerAddress(), request.getUserInfo());
|
||||
return true;
|
||||
}
|
||||
|
||||
@DeleteMapping("/deleteAcl")
|
||||
@DeleteMapping("/deleteAcl.do")
|
||||
public Object deleteAcl(
|
||||
@RequestParam(required = false) String brokerAddress,
|
||||
@RequestParam String subject,
|
||||
@@ -92,7 +92,7 @@ public class AclController {
|
||||
return true;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/updateAcl", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
|
||||
@RequestMapping(value = "/updateAcl.do", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
|
||||
@ResponseBody
|
||||
public Object updateAcl(@RequestBody PolicyRequest request) {
|
||||
aclService.updateAcl(request);
|
||||
|
@@ -19,8 +19,8 @@ package org.apache.rocketmq.dashboard.model;
|
||||
import org.hibernate.validator.constraints.Range;
|
||||
|
||||
public class User {
|
||||
public static final int ORDINARY = 0;
|
||||
public static final int ADMIN = 1;
|
||||
public static final int SUPER = 0;
|
||||
public static final int NORMAL = 1;
|
||||
|
||||
private long id;
|
||||
private String name;
|
||||
|
@@ -17,9 +17,11 @@
|
||||
|
||||
package org.apache.rocketmq.dashboard.model.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class UserInfoParam {
|
||||
private String username;
|
||||
private String password;
|
||||
|
@@ -58,7 +58,7 @@ public abstract class AbstractFileStore {
|
||||
}
|
||||
}
|
||||
|
||||
abstract void load(InputStream inputStream);
|
||||
protected abstract void load(InputStream inputStream);
|
||||
|
||||
private void load() {
|
||||
load(null);
|
||||
@@ -66,7 +66,7 @@ public abstract class AbstractFileStore {
|
||||
|
||||
private boolean watch() {
|
||||
try {
|
||||
FileWatchService fileWatchService = new FileWatchService(new String[] {filePath}, new FileWatchService.Listener() {
|
||||
FileWatchService fileWatchService = new FileWatchService(new String[]{filePath}, new FileWatchService.Listener() {
|
||||
@Override
|
||||
public void onChanged(String path) {
|
||||
log.info("The file changed, reload the context");
|
||||
|
@@ -17,13 +17,10 @@
|
||||
|
||||
package org.apache.rocketmq.dashboard.service.impl;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.service.LoginService;
|
||||
import org.apache.rocketmq.dashboard.service.UserService;
|
||||
import org.apache.rocketmq.dashboard.service.provider.UserInfoProvider;
|
||||
import org.apache.rocketmq.dashboard.service.strategy.UserContext;
|
||||
import org.apache.rocketmq.dashboard.util.UserInfoContext;
|
||||
import org.apache.rocketmq.dashboard.util.WebUtil;
|
||||
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
||||
@@ -33,34 +30,29 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@Service
|
||||
public class LoginServiceImpl implements LoginService {
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Resource
|
||||
private RMQConfigure rmqConfigure;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
private UserInfoProvider userInfoProvider;
|
||||
private UserContext userContext;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean login(HttpServletRequest request, HttpServletResponse response) {
|
||||
String username = (String) WebUtil.getValueFromSession(request, WebUtil.USER_NAME);
|
||||
if (username != null) {
|
||||
UserInfo userInfo = userInfoProvider.getUserInfoByUsername(username);
|
||||
UserInfo userInfo = userContext.queryByUsername(username);
|
||||
if (userInfo == null) {
|
||||
auth(request, response);
|
||||
return false;
|
||||
}
|
||||
UserInfoContext.set(WebUtil.USER_NAME, userInfo);
|
||||
return true;
|
||||
|
||||
}
|
||||
auth(request, response);
|
||||
return false;
|
||||
@@ -69,11 +61,7 @@ public class LoginServiceImpl implements LoginService {
|
||||
protected void auth(HttpServletRequest request, HttpServletResponse response) {
|
||||
try {
|
||||
String url = WebUtil.getUrl(request);
|
||||
try {
|
||||
url = URLEncoder.encode(url, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
logger.error("url encode:{}", url, e);
|
||||
}
|
||||
url = URLEncoder.encode(url, StandardCharsets.UTF_8);
|
||||
logger.debug("redirect url : {}", url);
|
||||
WebUtil.redirect(response, request, "/#/login?redirect=" + url);
|
||||
} catch (IOException e) {
|
||||
|
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.apache.rocketmq.dashboard.service.strategy;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.apache.rocketmq.dashboard.service.ClusterInfoService;
|
||||
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
||||
import org.apache.rocketmq.remoting.protocol.route.BrokerData;
|
||||
import org.apache.rocketmq.tools.admin.MQAdminExt;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class AclUserStrategy implements UserStrategy {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AclUserStrategy.class);
|
||||
|
||||
private final MQAdminExt mqAdminExt;
|
||||
|
||||
private final ClusterInfoService clusterInfoService;
|
||||
|
||||
@Override
|
||||
public UserInfo getUserInfoByUsername(String username) {
|
||||
ClusterInfo clusterInfo = clusterInfoService.get();
|
||||
|
||||
if (clusterInfo == null || clusterInfo.getBrokerAddrTable() == null || clusterInfo.getBrokerAddrTable().isEmpty()) {
|
||||
log.warn("Cluster information is not available or has no broker addresses.");
|
||||
return null;
|
||||
}
|
||||
for (BrokerData brokerLiveInfo : clusterInfo.getBrokerAddrTable().values()) {
|
||||
if (brokerLiveInfo == null || brokerLiveInfo.getBrokerAddrs() == null || brokerLiveInfo.getBrokerAddrs().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
String brokerAddr = brokerLiveInfo.getBrokerAddrs().get(0L); // Assuming 0L is the primary address
|
||||
if (brokerAddr == null) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
UserInfo userInfo = mqAdminExt.getUser(brokerAddr, username);
|
||||
if (userInfo != null) {
|
||||
return userInfo;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to get user {} from broker {}. Trying next broker if available. Error: {}", username, brokerAddr, e.getMessage());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.apache.rocketmq.dashboard.service.strategy;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.apache.rocketmq.dashboard.config.RMQConfigure;
|
||||
import org.apache.rocketmq.dashboard.exception.ServiceException;
|
||||
import org.apache.rocketmq.dashboard.model.User;
|
||||
import org.apache.rocketmq.dashboard.service.impl.AbstractFileStore;
|
||||
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.FileReader;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Service
|
||||
public class FileUserStrategy implements UserStrategy, InitializingBean {
|
||||
@Resource
|
||||
private RMQConfigure configure;
|
||||
|
||||
private FileBasedUserInfoStore fileBasedUserInfoStore;
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (configure.isLoginRequired()) {
|
||||
fileBasedUserInfoStore = new FileBasedUserInfoStore(configure);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserInfo getUserInfoByUsername(String username) {
|
||||
User user = fileBasedUserInfoStore.queryByUsernameAndPassword(username);
|
||||
if (user != null) {
|
||||
return UserInfo.of(user.getName(), user.getPassword(), user.getType() == 0 ? "normal" : "super");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class FileBasedUserInfoStore extends AbstractFileStore {
|
||||
private static final String FILE_NAME = "users.properties";
|
||||
|
||||
private static Map<String, User> userMap = new ConcurrentHashMap<>();
|
||||
|
||||
public FileBasedUserInfoStore(RMQConfigure configure) {
|
||||
super(configure, FILE_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(InputStream inputStream) {
|
||||
Properties prop = new Properties();
|
||||
try {
|
||||
if (inputStream == null) {
|
||||
prop.load(new FileReader(filePath));
|
||||
} else {
|
||||
prop.load(inputStream);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("load user.properties failed", e);
|
||||
throw new ServiceException(0, String.format("Failed to load loginUserInfo property file: %s", filePath));
|
||||
}
|
||||
|
||||
Map<String, User> loadUserMap = new HashMap<>();
|
||||
String[] arrs;
|
||||
int role;
|
||||
for (String key : prop.stringPropertyNames()) {
|
||||
String v = prop.getProperty(key);
|
||||
if (v == null)
|
||||
continue;
|
||||
arrs = v.split(",", 2);
|
||||
if (arrs.length == 0) {
|
||||
continue;
|
||||
} else if (arrs.length == 1) {
|
||||
role = 0;
|
||||
} else {
|
||||
role = Integer.parseInt(arrs[1].trim());
|
||||
}
|
||||
|
||||
loadUserMap.put(key, new User(key, arrs[0].trim(), role));
|
||||
}
|
||||
|
||||
userMap.clear();
|
||||
userMap.putAll(loadUserMap);
|
||||
}
|
||||
|
||||
public User queryByName(String name) {
|
||||
return userMap.get(name);
|
||||
}
|
||||
|
||||
public User queryByUsernameAndPassword(@NotNull String username) {
|
||||
User user = queryByName(username);
|
||||
if (user != null) {
|
||||
return user.cloneOne();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.apache.rocketmq.dashboard.service.strategy;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
public class UserContext {
|
||||
private UserStrategy userStrategy;
|
||||
|
||||
@Autowired
|
||||
private Map<String, UserStrategy> userStrategies;
|
||||
|
||||
@Value("${rocketmq.config.authMode}")
|
||||
private String authMode;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
switch (authMode.toLowerCase()) {
|
||||
case "acl":
|
||||
this.userStrategy = userStrategies.get("aclUserStrategy");
|
||||
break;
|
||||
case "file":
|
||||
default:
|
||||
this.userStrategy = userStrategies.get("fileUserStrategy");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public UserInfo queryByUsername(String username) {
|
||||
return userStrategy.getUserInfoByUsername(username);
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.apache.rocketmq.dashboard.service.strategy;
|
||||
|
||||
import org.apache.rocketmq.remoting.protocol.body.UserInfo;
|
||||
|
||||
public interface UserStrategy {
|
||||
UserInfo getUserInfoByUsername(String username);
|
||||
}
|
@@ -58,6 +58,12 @@ rocketmq:
|
||||
ticketKey: ticket
|
||||
# must create userInfo file: ${rocketmq.config.dataPath}/users.properties if the login is required
|
||||
loginRequired: false
|
||||
# Authentication mode for RocketMQ Dashboard
|
||||
# Available options:
|
||||
# - 'file': Use username/password stored in a file (requires 'auth.file.path')
|
||||
# - 'acl': Use credentials from ACL system (requires 'acl.access.key' and 'acl.secret.key')
|
||||
# Default: file
|
||||
authMode: file
|
||||
useTLS: false
|
||||
proxyAddr: 127.0.0.1:8080
|
||||
proxyAddrs:
|
||||
|
Reference in New Issue
Block a user