chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.apache.hertzbeat</groupId>
|
||||
<artifactId>hertzbeat</artifactId>
|
||||
<version>2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hertzbeat-remoting</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.hertzbeat</groupId>
|
||||
<artifactId>hertzbeat-common-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.hertzbeat.remoting;
|
||||
|
||||
import org.apache.hertzbeat.common.entity.message.ClusterMsg;
|
||||
import org.apache.hertzbeat.remoting.netty.NettyRemotingProcessor;
|
||||
|
||||
/**
|
||||
* remoting client interface
|
||||
*/
|
||||
public interface RemotingClient extends RemotingService {
|
||||
|
||||
/**
|
||||
* register remoting processor by type
|
||||
* @param messageType type
|
||||
* @param processor remoting processor
|
||||
*/
|
||||
void registerProcessor(ClusterMsg.MessageType messageType, NettyRemotingProcessor processor);
|
||||
|
||||
/**
|
||||
* send message to server
|
||||
* @param request request message
|
||||
*/
|
||||
void sendMsg(ClusterMsg.Message request);
|
||||
|
||||
/**
|
||||
* send message to server and sync waiting receive server message
|
||||
* @param request request message
|
||||
* @param timeoutMillis timeout millis
|
||||
* @return response message
|
||||
*/
|
||||
ClusterMsg.Message sendMsgSync(ClusterMsg.Message request, int timeoutMillis);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.hertzbeat.remoting;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import java.util.List;
|
||||
import org.apache.hertzbeat.common.entity.message.ClusterMsg;
|
||||
import org.apache.hertzbeat.remoting.netty.NettyHook;
|
||||
import org.apache.hertzbeat.remoting.netty.NettyRemotingProcessor;
|
||||
|
||||
/**
|
||||
* remoting server interface
|
||||
*/
|
||||
public interface RemotingServer extends RemotingService {
|
||||
|
||||
/**
|
||||
* register remoting processor by type
|
||||
* @param messageType type
|
||||
* @param processor remoting processor
|
||||
*/
|
||||
void registerProcessor(ClusterMsg.MessageType messageType, NettyRemotingProcessor processor);
|
||||
|
||||
/**
|
||||
* send message to client
|
||||
* @param channel client channel
|
||||
* @param request request message
|
||||
*/
|
||||
void sendMsg(Channel channel, ClusterMsg.Message request);
|
||||
|
||||
/**
|
||||
* send message to client and receive client message
|
||||
* @param channel client channel
|
||||
* @param request request message
|
||||
* @param timeoutMillis timeout millis
|
||||
* @return response message
|
||||
*/
|
||||
ClusterMsg.Message sendMsgSync(Channel channel, ClusterMsg.Message request, int timeoutMillis);
|
||||
|
||||
/**
|
||||
* register hook.
|
||||
* @param nettyHookList hook list
|
||||
*/
|
||||
void registerHook(List<NettyHook> nettyHookList);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.hertzbeat.remoting;
|
||||
|
||||
/**
|
||||
* Derived from Apache Rocketmq org.apache.rocketmq.remoting.RemotingService
|
||||
* remoting service interface
|
||||
* @see <a href="https://github.com/apache/rocketmq/blob/develop/remoting/src/main/java/org/apache/rocketmq/remoting/RemotingService.java">RemotingService</a>
|
||||
*/
|
||||
public interface RemotingService {
|
||||
|
||||
/**
|
||||
* start server
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* shutdown server
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* test use
|
||||
* @return is server start
|
||||
*/
|
||||
boolean isStart();
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.hertzbeat.remoting.event;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
|
||||
/**
|
||||
* interface some method from ChannelInboundHandler
|
||||
*/
|
||||
public interface NettyEventListener {
|
||||
|
||||
/**
|
||||
* do something when channel active
|
||||
* @param channel netty channel
|
||||
*/
|
||||
default void onChannelActive(final Channel channel) throws Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* do something when channel idle
|
||||
* @param channel netty channel
|
||||
*/
|
||||
default void onChannelIdle(final Channel channel) throws Exception {
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.hertzbeat.remoting.netty;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* netty client config
|
||||
*/
|
||||
@Data
|
||||
public class NettyClientConfig {
|
||||
|
||||
private String serverHost;
|
||||
|
||||
private int serverPort;
|
||||
|
||||
private int connectTimeoutMillis = 10000;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.hertzbeat.remoting.netty;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import org.apache.hertzbeat.common.entity.message.ClusterMsg;
|
||||
|
||||
/**
|
||||
* hook interface, handle something before request processor
|
||||
*/
|
||||
public interface NettyHook {
|
||||
|
||||
void doBeforeRequest(ChannelHandlerContext ctx, ClusterMsg.Message message);
|
||||
|
||||
}
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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.hertzbeat.remoting.netty;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.epoll.Epoll;
|
||||
import io.netty.handler.timeout.IdleState;
|
||||
import io.netty.handler.timeout.IdleStateEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.hertzbeat.common.entity.message.ClusterMsg;
|
||||
import org.apache.hertzbeat.common.util.NetworkUtil;
|
||||
import org.apache.hertzbeat.remoting.RemotingService;
|
||||
import org.apache.hertzbeat.remoting.event.NettyEventListener;
|
||||
|
||||
/**
|
||||
* Derived from Apache Rocketmq org.apache.rocketmq.remoting.netty.NettyRemotingAbstract
|
||||
* netty remote abstract
|
||||
* @see <a href="https://github.com/apache/rocketmq/blob/develop/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingAbstract.java">NettyRemotingAbstract</a>
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class NettyRemotingAbstract implements RemotingService {
|
||||
protected ConcurrentHashMap<ClusterMsg.MessageType, NettyRemotingProcessor> processorTable = new ConcurrentHashMap<>();
|
||||
|
||||
protected ConcurrentHashMap<String, ResponseFuture> responseTable = new ConcurrentHashMap<>();
|
||||
|
||||
protected List<NettyHook> nettyHookList = new ArrayList<>();
|
||||
|
||||
protected NettyEventListener nettyEventListener;
|
||||
|
||||
protected NettyRemotingAbstract(NettyEventListener nettyEventListener) {
|
||||
this.nettyEventListener = nettyEventListener;
|
||||
}
|
||||
|
||||
public void registerProcessor(final ClusterMsg.MessageType messageType, final NettyRemotingProcessor processor) {
|
||||
this.processorTable.put(messageType, processor);
|
||||
}
|
||||
|
||||
protected void processReceiveMsg(ChannelHandlerContext ctx, ClusterMsg.Message message) {
|
||||
if (ClusterMsg.Direction.REQUEST.equals(message.getDirection())) {
|
||||
this.processRequestMsg(ctx, message);
|
||||
} else {
|
||||
this.processResponseMsg(ctx, message);
|
||||
}
|
||||
}
|
||||
|
||||
protected void processRequestMsg(ChannelHandlerContext ctx, ClusterMsg.Message request) {
|
||||
this.doBeforeRequest(ctx, request);
|
||||
|
||||
NettyRemotingProcessor processor = this.processorTable.get(request.getType());
|
||||
if (processor == null) {
|
||||
log.info("request type {} not supported", request.getType());
|
||||
return;
|
||||
}
|
||||
ClusterMsg.Message response = processor.handle(ctx, request);
|
||||
if (response != null) {
|
||||
ctx.writeAndFlush(response);
|
||||
}
|
||||
}
|
||||
|
||||
private void doBeforeRequest(ChannelHandlerContext ctx, ClusterMsg.Message request) {
|
||||
if (CollectionUtils.isEmpty(this.nettyHookList)) {
|
||||
return;
|
||||
}
|
||||
for (NettyHook nettyHook : this.nettyHookList) {
|
||||
nettyHook.doBeforeRequest(ctx, request);
|
||||
}
|
||||
}
|
||||
|
||||
protected void processResponseMsg(ChannelHandlerContext ctx, ClusterMsg.Message response) {
|
||||
// for sync response
|
||||
if (this.responseTable.containsKey(response.getIdentity())) {
|
||||
ResponseFuture responseFuture = this.responseTable.get(response.getIdentity());
|
||||
responseFuture.putResponse(response);
|
||||
} else {
|
||||
// async response
|
||||
NettyRemotingProcessor processor = this.processorTable.get(response.getType());
|
||||
if (processor != null) {
|
||||
ClusterMsg.Message repMessage = processor.handle(ctx, response);
|
||||
if (repMessage != null) {
|
||||
ctx.writeAndFlush(repMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void sendMsgImpl(final Channel channel, final ClusterMsg.Message request) {
|
||||
channel.writeAndFlush(request).addListener(future -> {
|
||||
if (!future.isSuccess()) {
|
||||
log.warn("send request message failed. address: {}, ", channel.remoteAddress(), future.cause());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected ClusterMsg.Message sendMsgSyncImpl(final Channel channel, final ClusterMsg.Message request, final int timeoutMillis) {
|
||||
final String identity = request.getIdentity();
|
||||
|
||||
try {
|
||||
ResponseFuture responseFuture = new ResponseFuture();
|
||||
this.responseTable.put(identity, responseFuture);
|
||||
channel.writeAndFlush(request).addListener(future -> {
|
||||
if (!future.isSuccess()) {
|
||||
responseTable.remove(identity);
|
||||
log.warn("send request message failed. request: {}, address: {}, ", request, channel.remoteAddress(), future.cause());
|
||||
}
|
||||
});
|
||||
ClusterMsg.Message response = responseFuture.waitResponse(timeoutMillis);
|
||||
if (response == null) {
|
||||
log.warn("get response message failed, message is null");
|
||||
}
|
||||
return response;
|
||||
} catch (InterruptedException e) {
|
||||
log.warn("get response message failed, ", e);
|
||||
} finally {
|
||||
responseTable.remove(identity);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
if (this.nettyEventListener != null && ctx.channel().isActive()) {
|
||||
this.nettyEventListener.onChannelActive(ctx.channel());
|
||||
}
|
||||
}
|
||||
|
||||
protected void channelIdle(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||
IdleStateEvent event = (IdleStateEvent) evt;
|
||||
if (this.nettyEventListener != null && event.state() == IdleState.ALL_IDLE) {
|
||||
ctx.channel().closeFuture();
|
||||
this.nettyEventListener.onChannelIdle(ctx.channel());
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean useEpoll() {
|
||||
return NetworkUtil.isLinuxPlatform()
|
||||
&& Epoll.isAvailable();
|
||||
}
|
||||
|
||||
}
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* 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.hertzbeat.remoting.netty;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.compression.ZlibCodecFactory;
|
||||
import io.netty.handler.codec.compression.ZlibWrapper;
|
||||
import io.netty.handler.codec.protobuf.ProtobufDecoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufEncoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import org.apache.hertzbeat.common.concurrent.BackgroundTaskExecutor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.entity.message.ClusterMsg;
|
||||
import org.apache.hertzbeat.remoting.RemotingClient;
|
||||
import org.apache.hertzbeat.remoting.event.NettyEventListener;
|
||||
|
||||
/**
|
||||
* Derived from Apache Rocketmq org.apache.rocketmq.remoting.netty.NettyRemotingClient
|
||||
* netty client
|
||||
* @see <a href="https://github.com/apache/rocketmq/blob/develop/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java">NettyRemotingClient</a>
|
||||
*/
|
||||
@Slf4j
|
||||
public class NettyRemotingClient extends NettyRemotingAbstract implements RemotingClient {
|
||||
|
||||
private static final int DEFAULT_WORKER_THREAD_NUM = Math.min(4, Runtime.getRuntime().availableProcessors());
|
||||
|
||||
private final NettyClientConfig nettyClientConfig;
|
||||
|
||||
private final BackgroundTaskExecutor threadPool;
|
||||
|
||||
private final Bootstrap bootstrap = new Bootstrap();
|
||||
|
||||
private EventLoopGroup workerGroup;
|
||||
|
||||
private Channel channel;
|
||||
|
||||
public NettyRemotingClient(final NettyClientConfig nettyClientConfig,
|
||||
final NettyEventListener nettyEventListener,
|
||||
final BackgroundTaskExecutor threadPool) {
|
||||
super(nettyEventListener);
|
||||
this.nettyClientConfig = nettyClientConfig;
|
||||
this.threadPool = threadPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
this.threadPool.executeLongRunning(() -> {
|
||||
ThreadFactory threadFactory = new ThreadFactoryBuilder()
|
||||
.setUncaughtExceptionHandler((thread, throwable) -> {
|
||||
log.error("NettyClientWorker has uncaughtException.");
|
||||
log.error(throwable.getMessage(), throwable);
|
||||
})
|
||||
.setDaemon(true)
|
||||
.setNameFormat("netty-client-worker-%d")
|
||||
.build();
|
||||
String envThreadNum = System.getProperty("hertzbeat.client.worker.thread.num");
|
||||
int workerThreadNum = envThreadNum != null ? Integer.parseInt(envThreadNum) : DEFAULT_WORKER_THREAD_NUM;
|
||||
this.workerGroup = new NioEventLoopGroup(workerThreadNum, threadFactory);
|
||||
this.bootstrap.group(workerGroup)
|
||||
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, this.nettyClientConfig.getConnectTimeoutMillis())
|
||||
.channel(NioSocketChannel.class)
|
||||
.handler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(SocketChannel channel) throws Exception {
|
||||
NettyRemotingClient.this.initChannel(channel);
|
||||
}
|
||||
});
|
||||
|
||||
this.channel = null;
|
||||
boolean first = true;
|
||||
while (!Thread.currentThread().isInterrupted()
|
||||
&& (first || this.channel == null || !this.channel.isActive())) {
|
||||
first = false;
|
||||
try {
|
||||
this.channel = this.bootstrap
|
||||
.connect(this.nettyClientConfig.getServerHost(), this.nettyClientConfig.getServerPort())
|
||||
.sync().channel();
|
||||
this.channel.closeFuture().sync();
|
||||
} catch (InterruptedException ignored) {
|
||||
log.info("client shutdown now!");
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (Exception e2) {
|
||||
log.error("client connect to server error: {}. try after 10s.", e2.getMessage());
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
workerGroup.shutdownGracefully();
|
||||
});
|
||||
}
|
||||
|
||||
private void initChannel(final SocketChannel channel) {
|
||||
ChannelPipeline pipeline = channel.pipeline();
|
||||
// zip
|
||||
pipeline.addLast(ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
|
||||
pipeline.addLast(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
|
||||
// protocol buf encode decode
|
||||
pipeline.addLast(new ProtobufVarint32FrameDecoder());
|
||||
pipeline.addLast(new ProtobufDecoder(ClusterMsg.Message.getDefaultInstance()));
|
||||
pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
|
||||
pipeline.addLast(new ProtobufEncoder());
|
||||
pipeline.addLast(new NettyClientHandler());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
try {
|
||||
if (this.channel != null) {
|
||||
this.channel.close();
|
||||
}
|
||||
|
||||
this.workerGroup.shutdownGracefully();
|
||||
|
||||
this.threadPool.destroy();
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("netty client shutdown exception, ", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStart() {
|
||||
return this.channel != null && this.channel.isActive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMsg(final ClusterMsg.Message request) {
|
||||
this.sendMsgImpl(this.channel, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClusterMsg.Message sendMsgSync(ClusterMsg.Message request, int timeoutMillis) {
|
||||
return this.sendMsgSyncImpl(this.channel, request, timeoutMillis);
|
||||
}
|
||||
|
||||
class NettyClientHandler extends SimpleChannelInboundHandler<ClusterMsg.Message> {
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
NettyRemotingClient.this.channelActive(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, ClusterMsg.Message msg) throws Exception {
|
||||
NettyRemotingClient.this.processReceiveMsg(ctx, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||
NettyRemotingClient.this.channelIdle(ctx, evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.hertzbeat.remoting.netty;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import org.apache.hertzbeat.common.entity.message.ClusterMsg;
|
||||
|
||||
/**
|
||||
* Derived from Apache Rocketmq org.apache.rocketmq.remoting.netty.NettyRequestProcessor
|
||||
* netty remoting processor
|
||||
* @see <a href="https://github.com/apache/rocketmq/blob/develop/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRequestProcessor.java">NettyRequestProcessor</a>
|
||||
*/
|
||||
public interface NettyRemotingProcessor {
|
||||
|
||||
ClusterMsg.Message handle(ChannelHandlerContext ctx, ClusterMsg.Message message);
|
||||
|
||||
}
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* 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.hertzbeat.remoting.netty;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.channel.epoll.EpollEventLoopGroup;
|
||||
import io.netty.channel.epoll.EpollServerSocketChannel;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.codec.compression.ZlibCodecFactory;
|
||||
import io.netty.handler.codec.compression.ZlibWrapper;
|
||||
import io.netty.handler.codec.protobuf.ProtobufDecoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufEncoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
|
||||
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
|
||||
import io.netty.handler.logging.LogLevel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import org.apache.hertzbeat.common.concurrent.BackgroundTaskExecutor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.entity.message.ClusterMsg;
|
||||
import org.apache.hertzbeat.remoting.RemotingServer;
|
||||
import org.apache.hertzbeat.remoting.event.NettyEventListener;
|
||||
|
||||
/**
|
||||
* Derived from Apache Rocketmq org.apache.rocketmq.remoting.netty.NettyRemotingServer
|
||||
* netty server
|
||||
* @see <a href="https://github.com/apache/rocketmq/blob/develop/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java">NettyRemotingServer</a>
|
||||
*/
|
||||
@Slf4j
|
||||
public class NettyRemotingServer extends NettyRemotingAbstract implements RemotingServer {
|
||||
|
||||
private final NettyServerConfig nettyServerConfig;
|
||||
|
||||
private final BackgroundTaskExecutor threadPool;
|
||||
|
||||
private EventLoopGroup bossGroup;
|
||||
|
||||
private EventLoopGroup workerGroup;
|
||||
|
||||
private Channel channel = null;
|
||||
|
||||
public NettyRemotingServer(final NettyServerConfig nettyServerConfig,
|
||||
final NettyEventListener nettyEventListener,
|
||||
final BackgroundTaskExecutor threadPool) {
|
||||
super(nettyEventListener);
|
||||
this.nettyServerConfig = nettyServerConfig;
|
||||
this.threadPool = threadPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
this.threadPool.executeLongRunning(() -> {
|
||||
int port = this.nettyServerConfig.getPort();
|
||||
ThreadFactory bossThreadFactory = new ThreadFactoryBuilder()
|
||||
.setUncaughtExceptionHandler((thread, throwable) -> {
|
||||
log.error("NettyServerBoss has uncaughtException.");
|
||||
log.error(throwable.getMessage(), throwable);
|
||||
})
|
||||
.setDaemon(true)
|
||||
.setNameFormat("netty-server-boss-%d")
|
||||
.build();
|
||||
ThreadFactory workerThreadFactory = new ThreadFactoryBuilder()
|
||||
.setUncaughtExceptionHandler((thread, throwable) -> {
|
||||
log.error("NettyServerWorker has uncaughtException.");
|
||||
log.error(throwable.getMessage(), throwable);
|
||||
})
|
||||
.setDaemon(true)
|
||||
.setNameFormat("netty-server-worker-%d")
|
||||
.build();
|
||||
if (this.useEpoll()) {
|
||||
bossGroup = new EpollEventLoopGroup(bossThreadFactory);
|
||||
workerGroup = new EpollEventLoopGroup(workerThreadFactory);
|
||||
} else {
|
||||
bossGroup = new NioEventLoopGroup(bossThreadFactory);
|
||||
workerGroup = new NioEventLoopGroup(workerThreadFactory);
|
||||
}
|
||||
|
||||
try {
|
||||
ServerBootstrap b = new ServerBootstrap();
|
||||
b.group(bossGroup, workerGroup)
|
||||
.channel(this.useEpoll() ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
|
||||
.handler(new LoggingHandler(LogLevel.INFO))
|
||||
.childOption(ChannelOption.TCP_NODELAY, true)
|
||||
.childOption(ChannelOption.SO_KEEPALIVE, false)
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(SocketChannel channel) throws Exception {
|
||||
NettyRemotingServer.this.initChannel(channel);
|
||||
}
|
||||
});
|
||||
channel = b.bind(port).sync().channel();
|
||||
channel.closeFuture().sync();
|
||||
} catch (InterruptedException ignored) {
|
||||
log.info("server shutdown now!");
|
||||
} catch (Exception e) {
|
||||
log.error("Netty Server start exception, {}", e.getMessage());
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
bossGroup.shutdownGracefully();
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStart() {
|
||||
return this.channel != null && this.channel.isActive();
|
||||
}
|
||||
|
||||
private void initChannel(final SocketChannel channel) {
|
||||
ChannelPipeline pipeline = channel.pipeline();
|
||||
// zip
|
||||
pipeline.addLast(ZlibCodecFactory.newZlibEncoder(ZlibWrapper.GZIP));
|
||||
pipeline.addLast(ZlibCodecFactory.newZlibDecoder(ZlibWrapper.GZIP));
|
||||
// protocol buf encode decode
|
||||
pipeline.addLast(new ProtobufVarint32FrameDecoder());
|
||||
pipeline.addLast(new ProtobufDecoder(ClusterMsg.Message.getDefaultInstance()));
|
||||
pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
|
||||
pipeline.addLast(new ProtobufEncoder());
|
||||
// idle state
|
||||
pipeline.addLast(new IdleStateHandler(0, 0, nettyServerConfig.getIdleStateEventTriggerTime()));
|
||||
pipeline.addLast(new NettyServerHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
try {
|
||||
this.bossGroup.shutdownGracefully();
|
||||
|
||||
this.workerGroup.shutdownGracefully();
|
||||
|
||||
this.threadPool.destroy();
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Netty Server shutdown exception, ", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMsg(final Channel channel, final ClusterMsg.Message request) {
|
||||
this.sendMsgImpl(channel, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClusterMsg.Message sendMsgSync(final Channel channel, final ClusterMsg.Message request, final int timeoutMillis) {
|
||||
return this.sendMsgSyncImpl(channel, request, timeoutMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerHook(List<NettyHook> nettyHookList) {
|
||||
this.nettyHookList.addAll(nettyHookList);
|
||||
}
|
||||
|
||||
/**
|
||||
* netty server handler
|
||||
*/
|
||||
@ChannelHandler.Sharable
|
||||
public class NettyServerHandler extends SimpleChannelInboundHandler<ClusterMsg.Message> {
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
NettyRemotingServer.this.channelActive(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, ClusterMsg.Message msg) throws Exception {
|
||||
NettyRemotingServer.this.processReceiveMsg(ctx, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||
NettyRemotingServer.this.channelIdle(ctx, evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.hertzbeat.remoting.netty;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* netty server config
|
||||
*/
|
||||
@Data
|
||||
public class NettyServerConfig {
|
||||
|
||||
private Integer port;
|
||||
|
||||
private Integer idleStateEventTriggerTime = 100;
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.hertzbeat.remoting.netty;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.apache.hertzbeat.common.entity.message.ClusterMsg;
|
||||
|
||||
/**
|
||||
* netty response future
|
||||
*/
|
||||
public class ResponseFuture {
|
||||
|
||||
private final CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
|
||||
private ClusterMsg.Message response;
|
||||
|
||||
public ClusterMsg.Message waitResponse(final long timeoutMillis) throws InterruptedException {
|
||||
this.countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
|
||||
return this.response;
|
||||
}
|
||||
|
||||
public void putResponse(final ClusterMsg.Message response) {
|
||||
this.response = response;
|
||||
this.countDownLatch.countDown();
|
||||
}
|
||||
|
||||
}
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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.hertzbeat.remoting;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import org.apache.hertzbeat.common.entity.message.ClusterMsg;
|
||||
import org.apache.hertzbeat.common.concurrent.BackgroundTaskExecutor;
|
||||
import org.apache.hertzbeat.remoting.netty.NettyClientConfig;
|
||||
import org.apache.hertzbeat.remoting.netty.NettyRemotingClient;
|
||||
import org.apache.hertzbeat.remoting.netty.NettyRemotingServer;
|
||||
import org.apache.hertzbeat.remoting.netty.NettyServerConfig;
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* test NettyRemotingClient and NettyRemotingServer
|
||||
*/
|
||||
public class RemotingServiceTest {
|
||||
|
||||
private final BackgroundTaskExecutor threadPool = new BackgroundTaskExecutor() {
|
||||
private final ExecutorService executor = Executors.newCachedThreadPool();
|
||||
|
||||
@Override
|
||||
public void execute(Runnable runnable) {
|
||||
executor.execute(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeLongRunning(Runnable runnable) {
|
||||
executor.execute(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
executor.shutdownNow();
|
||||
}
|
||||
};
|
||||
|
||||
private RemotingServer remotingServer;
|
||||
|
||||
private RemotingClient remotingClient;
|
||||
|
||||
public RemotingServer createRemotingServer(int port) {
|
||||
NettyServerConfig nettyServerConfig = new NettyServerConfig();
|
||||
nettyServerConfig.setPort(port);
|
||||
// todo test NettyEventListener
|
||||
RemotingServer server = new NettyRemotingServer(nettyServerConfig, null, threadPool);
|
||||
server.start();
|
||||
return server;
|
||||
}
|
||||
|
||||
public RemotingClient createRemotingClient(int port) {
|
||||
NettyClientConfig nettyClientConfig = new NettyClientConfig();
|
||||
nettyClientConfig.setServerHost("localhost");
|
||||
nettyClientConfig.setServerPort(port);
|
||||
RemotingClient client = new NettyRemotingClient(nettyClientConfig, null, threadPool);
|
||||
client.start();
|
||||
return client;
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws InterruptedException {
|
||||
int port = 10000 + (int) (Math.random() * 10000);
|
||||
|
||||
remotingServer = createRemotingServer(port);
|
||||
// await remotingServer start
|
||||
int count = 5;
|
||||
while (count-- > 0) {
|
||||
Thread.sleep(1000);
|
||||
if (remotingServer.isStart()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count < 0) {
|
||||
throw new RuntimeException("remoting server start error");
|
||||
}
|
||||
|
||||
remotingClient = createRemotingClient(port);
|
||||
// await remotingClient start
|
||||
count = 5;
|
||||
while (count-- > 0) {
|
||||
Thread.sleep(1000);
|
||||
if (remotingClient.isStart()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count < 0) {
|
||||
throw new RuntimeException("remoting client start error");
|
||||
}
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void shutdown() {
|
||||
this.remotingClient.shutdown();
|
||||
this.remotingServer.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendMsg() {
|
||||
final String msg = "hello world";
|
||||
|
||||
this.remotingServer.registerProcessor(ClusterMsg.MessageType.HEARTBEAT, (ctx, message) -> {
|
||||
Assertions.assertEquals(msg, message.getMsg().toStringUtf8());
|
||||
return null;
|
||||
});
|
||||
|
||||
ClusterMsg.Message request = ClusterMsg.Message.newBuilder()
|
||||
.setDirection(ClusterMsg.Direction.REQUEST)
|
||||
.setType(ClusterMsg.MessageType.HEARTBEAT)
|
||||
.setMsg(ByteString.copyFromUtf8(msg))
|
||||
.build();
|
||||
this.remotingClient.sendMsg(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendMsgSync() {
|
||||
final String requestMsg = "request";
|
||||
final String responseMsg = "response";
|
||||
|
||||
this.remotingServer.registerProcessor(ClusterMsg.MessageType.HEARTBEAT, (ctx, message) -> {
|
||||
Assertions.assertEquals(requestMsg, message.getMsg().toStringUtf8());
|
||||
return ClusterMsg.Message.newBuilder()
|
||||
.setDirection(ClusterMsg.Direction.RESPONSE)
|
||||
.setMsg(ByteString.copyFromUtf8(responseMsg))
|
||||
.build();
|
||||
});
|
||||
|
||||
ClusterMsg.Message request = ClusterMsg.Message.newBuilder()
|
||||
.setDirection(ClusterMsg.Direction.REQUEST)
|
||||
.setType(ClusterMsg.MessageType.HEARTBEAT)
|
||||
.setMsg(ByteString.copyFromUtf8(requestMsg))
|
||||
.build();
|
||||
ClusterMsg.Message response = this.remotingClient.sendMsgSync(request, 3000);
|
||||
Assertions.assertEquals(responseMsg, response.getMsg().toStringUtf8());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNettyHook() {
|
||||
this.remotingServer.registerHook(Lists.newArrayList(
|
||||
(ctx, message) -> Assertions.assertEquals("hello world", message.getMsg().toStringUtf8())
|
||||
));
|
||||
|
||||
this.remotingServer.registerProcessor(ClusterMsg.MessageType.HEARTBEAT, (ctx, message) ->
|
||||
ClusterMsg.Message.newBuilder()
|
||||
.setDirection(ClusterMsg.Direction.RESPONSE)
|
||||
.build());
|
||||
|
||||
ClusterMsg.Message request = ClusterMsg.Message.newBuilder()
|
||||
.setDirection(ClusterMsg.Direction.REQUEST)
|
||||
.setType(ClusterMsg.MessageType.HEARTBEAT)
|
||||
.setMsg(ByteString.copyFromUtf8("hello world"))
|
||||
.build();
|
||||
this.remotingClient.sendMsg(request);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user