Skip to content

Commit

Permalink
Dashboard: Fix bugs in the delete handler for Client
Browse files Browse the repository at this point in the history
Signed-off-by: Xiaoyang Liu <[email protected]>
  • Loading branch information
xiaoyang-sde committed Jul 2, 2022
1 parent edf9284 commit 7cde790
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 52 deletions.
2 changes: 1 addition & 1 deletion eventmesh-dashboard/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const NavItem = ({
role="group"
cursor="pointer"
_hover={{
bg: 'cyan.400',
bg: 'blue.500',
color: 'white',
}}
{...rest}
Expand Down
31 changes: 20 additions & 11 deletions eventmesh-dashboard/components/client/ClientTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import { useEffect, useState } from 'react';
interface Client {
env: string,
subsystem: string,
path: string,
url: string,
pid: number,
host: string,
port: number,
Expand All @@ -54,24 +54,31 @@ interface ClientProps {
port: number,
group: string,
protocol: string,
url: string,
}

interface RemoveClientRequest {
host: string,
port: number,
protocol: string,
url: string,
}

const ClientRow = ({
host, port, group, protocol,
host, port, group, protocol, url,
}: ClientProps) => {
const toast = useToast();
const [loading, setLoading] = useState(false);
const onRemoveClick = async () => {
try {
setLoading(true);
await axios.delete<RemoveClientRequest>('/client', {
data: { host, port, protocol },
data: {
host,
port,
protocol,
url,
},
});
setLoading(false);
} catch (error) {
Expand All @@ -89,13 +96,14 @@ const ClientRow = ({

return (
<Tr>
<Td>{host}</Td>
<Td isNumeric>{port}</Td>
{protocol === 'TCP' && <Td>{`${host}:${port}`}</Td>}
{(protocol === 'HTTP' || protocol === 'gRPC') && <Td>{url}</Td>}
<Td>{group}</Td>
<Td>{protocol}</Td>
<Td>
<HStack>
<Button
isDisabled
colorScheme="red"
isLoading={loading}
onClick={onRemoveClick}
Expand All @@ -109,9 +117,9 @@ const ClientRow = ({
};

const ClientTable = () => {
const [searchInput, setsearchInput] = useState<string>('');
const [searchInput, setSearchInput] = useState<string>('');
const handleSearchInputChange = (event: React.FormEvent<HTMLInputElement>) => {
setsearchInput(event.currentTarget.value);
setSearchInput(event.currentTarget.value);
};

const [protocolFilter, setProtocolFilter] = useState<string>('');
Expand Down Expand Up @@ -147,6 +155,7 @@ const ClientTable = () => {
duration: 3000,
isClosable: true,
});
setClientList([]);
}
}
};
Expand All @@ -161,10 +170,10 @@ const ClientTable = () => {
borderWidth="1px"
borderRadius="md"
overflow="hidden"
p="4"
>
<HStack
spacing="2"
margin="2"
>
<Input
w="200%"
Expand Down Expand Up @@ -194,8 +203,7 @@ const ClientTable = () => {
<Table variant="simple">
<Thead>
<Tr>
<Th>Host</Th>
<Th isNumeric>Port</Th>
<Th>Host or url</Th>
<Th>Group</Th>
<Th>Protocol</Th>
<Th>Action</Th>
Expand All @@ -217,13 +225,14 @@ const ClientTable = () => {
}
return true;
}).map(({
host, port, group, protocol,
host, port, group, protocol, url,
}) => (
<ClientRow
host={host}
port={port}
group={group}
protocol={protocol}
url={url}
/>
))}
</Tbody>
Expand Down
104 changes: 104 additions & 0 deletions eventmesh-dashboard/components/index/Endpoint.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* 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 {
HStack,
Input,
VStack,
Button,
Text,
useToast,
} from '@chakra-ui/react';
import axios from 'axios';
import React, { useEffect, useState } from 'react';

const Endpoint = () => {
const toast = useToast();
const [endpointInput, setEndpointInput] = useState('http://localhost:10106');
const [loading, setLoading] = useState(false);

useEffect(() => {
const endpoint = localStorage.getItem('endpoint');
if (endpoint === null) {
return;
}
setEndpointInput(endpoint);
axios.defaults.baseURL = endpoint;
}, []);

const handleEndpointInputChange = (event: React.FormEvent<HTMLInputElement>) => {
setEndpointInput(event.currentTarget.value);
};

const handleSaveButtonClick = async () => {
try {
setLoading(true);
await axios.get(`${endpointInput}/client`);
axios.defaults.baseURL = endpointInput;
localStorage.setItem('endpoint', endpointInput);
} catch (error) {
if (axios.isAxiosError(error)) {
toast({
title: `Failed to connect to ${endpointInput}`,
description: error.message,
status: 'error',
duration: 3000,
isClosable: true,
});
}
} finally {
setLoading(false);
}
};

return (
<VStack
maxW="full"
bg="white"
borderWidth="1px"
borderRadius="md"
overflow="hidden"
p="4"
>
<Text
w="full"
>
EventMesh Admin Endpoint
</Text>
<HStack
w="full"
>
<Input
placeholder="Apache EventMesh Backend Endpoint"
value={endpointInput}
onChange={handleEndpointInputChange}
/>
<Button
colorScheme="blue"
isLoading={loading}
onClick={handleSaveButtonClick}
>
Save
</Button>
</HStack>
</VStack>
);
};

export default Endpoint;
3 changes: 2 additions & 1 deletion eventmesh-dashboard/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@

import Head from 'next/head';
import type { NextPage } from 'next';
import Endpoint from '../components/index/Endpoint';

const Index: NextPage = () => (
<>
<Head>
<title>Apache EventMesh Dashboard</title>
</Head>
<text>Apache EventMesh Dashboard</text>
<Endpoint />
</>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,51 +85,66 @@ void preflight(HttpExchange httpExchange) throws IOException {
* DELETE /client
*/
void delete(HttpExchange httpExchange) throws IOException {
String request = HttpExchangeUtils.streamToString(httpExchange.getRequestBody());
DeleteClientRequest deleteClientRequest = JsonUtils.toObject(request, DeleteClientRequest.class);
String host = deleteClientRequest.host;
int port = deleteClientRequest.port;
String protocol = deleteClientRequest.protocol;
OutputStream out = httpExchange.getResponseBody();
try {
String request = HttpExchangeUtils.streamToString(httpExchange.getRequestBody());
DeleteClientRequest deleteClientRequest = JsonUtils.toObject(request, DeleteClientRequest.class);
String host = deleteClientRequest.host;
int port = deleteClientRequest.port;
String protocol = deleteClientRequest.protocol;
String url = deleteClientRequest.url;

if (Objects.equals(protocol, "tcp")) {
ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping();
ConcurrentHashMap<InetSocketAddress, Session> sessionMap = clientSessionGroupMapping.getSessionMap();
if (!sessionMap.isEmpty()) {
for (Map.Entry<InetSocketAddress, Session> entry : sessionMap.entrySet()) {
if (entry.getKey().getHostString().equals(host) && entry.getKey().getPort() == port) {
EventMeshTcp2Client.serverGoodby2Client(
eventMeshTCPServer,
entry.getValue(),
clientSessionGroupMapping
);
if (Objects.equals(protocol, "TCP")) {
ClientSessionGroupMapping clientSessionGroupMapping = eventMeshTCPServer.getClientSessionGroupMapping();
ConcurrentHashMap<InetSocketAddress, Session> sessionMap = clientSessionGroupMapping.getSessionMap();
if (!sessionMap.isEmpty()) {
for (Map.Entry<InetSocketAddress, Session> entry : sessionMap.entrySet()) {
if (entry.getKey().getHostString().equals(host) && entry.getKey().getPort() == port) {
EventMeshTcp2Client.serverGoodby2Client(
eventMeshTCPServer,
entry.getValue(),
clientSessionGroupMapping
);
}
}
}
}
}

if (Objects.equals(protocol, "http")) {
for (List<Client> clientList : eventMeshHTTPServer.localClientInfoMapping.values()) {
clientList.removeIf(client -> Objects.equals(client.hostname, host));
if (Objects.equals(protocol, "HTTP")) {
for (List<Client> clientList : eventMeshHTTPServer.localClientInfoMapping.values()) {
clientList.removeIf(client -> Objects.equals(client.url, url));
}
}
}

if (Objects.equals(protocol, "gRPC")) {
ConsumerManager consumerManager = eventMeshGrpcServer.getConsumerManager();
Map<String, List<ConsumerGroupClient>> clientTable = consumerManager.getClientTable();
for (List<ConsumerGroupClient> clientList : clientTable.values()) {
for (ConsumerGroupClient client : clientList) {
if (Objects.equals(client.getHostname(), host)) {
consumerManager.deregisterClient(client);
if (Objects.equals(protocol, "gRPC")) {
ConsumerManager consumerManager = eventMeshGrpcServer.getConsumerManager();
Map<String, List<ConsumerGroupClient>> clientTable = consumerManager.getClientTable();
for (List<ConsumerGroupClient> clientList : clientTable.values()) {
for (ConsumerGroupClient client : clientList) {
if (Objects.equals(client.getUrl(), url)) {
consumerManager.deregisterClient(client);
}
}
}
}
}

httpExchange.getResponseHeaders().add("Content-Type", "application/json");
httpExchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
httpExchange.sendResponseHeaders(200, 0);
OutputStream out = httpExchange.getResponseBody();
out.close();
httpExchange.getResponseHeaders().add("Content-Type", "application/json");
httpExchange.getResponseHeaders().add("Access-Control-Allow-Origin", "*");
httpExchange.sendResponseHeaders(200, 0);
} catch (Exception e) {
Error error = new Error(e.toString());
String result = JsonUtils.toJson(error);
httpExchange.sendResponseHeaders(500, result.getBytes().length);
out.write(result.getBytes());
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
logger.warn("out close failed...", e);
}
}
}
}

/**
Expand Down Expand Up @@ -178,7 +193,7 @@ void list(HttpExchange httpExchange) throws IOException {
Optional.ofNullable(client.idc).orElse(""),
Optional.ofNullable(client.consumerGroup).orElse(""),
"",
"gRPC"
"HTTP"
);
getClientResponseList.add(getClientResponse);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,19 @@ public class DeleteClientRequest {
public String host;
public int port;
public String protocol;
public String url;

@JsonCreator
public DeleteClientRequest(
@JsonProperty("host") String host,
@JsonProperty("port") int port,
@JsonProperty("protocol") String protocol
@JsonProperty("protocol") String protocol,
@JsonProperty("url") String url
) {
super();
this.host = host;
this.port = port;
this.protocol = protocol;
this.url = url;
}
}
Loading

0 comments on commit 7cde790

Please sign in to comment.