All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fisco.bcos.channel.proxy.Server Maven / Gradle / Ivy

package org.fisco.bcos.channel.proxy;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.SocketChannel;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timer;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import javax.net.ssl.SSLException;
import org.fisco.bcos.channel.handler.ChannelConnections;
import org.fisco.bcos.channel.handler.ConnectionInfo;
import org.fisco.bcos.channel.handler.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

public class Server {
  private static Logger logger = LoggerFactory.getLogger(Server.class);

  class ConnectionCallback implements ChannelConnections.Callback {
    public Server getServer() {
      return server;
    }

    public void setServer(Server server) {
      this.server = server;
    }

    public Boolean getFromRemote() {
      return fromRemote;
    }

    public void setFromRemote(Boolean fromRemote) {
      this.fromRemote = fromRemote;
    }

    @Override
    public void onMessage(ChannelHandlerContext ctx, ByteBuf message) {
      try {
        Message msg = new Message();
        msg.readHeader(message);
        msg.readExtra(message);

        logger.debug("receive Message type: {}", msg.getType());

        if (msg.getType() == 0x20 || msg.getType() == 0x21) {
          logger.debug("channel ");
        } else if (msg.getType() == 0x30 || msg.getType() == 0x31) {
          logger.debug("channel2");
        } else if (msg.getType() == 0x32) {
          logger.debug("topic");

          onTopic(ctx, msg);
          return;
        } else if (msg.getType() == 0x12) {
          logger.debug("ethereum");
        } else if (msg.getType() == 0x13) {
          onHeartBeat(ctx, msg);
          return;
        } else if (msg.getType() == 0x1000) {
          logger.debug("transaction message call back.");
        } else {
          logger.error("unknown message:{}", msg.getType());
        }

        if (fromRemote) {
          logger.debug("remote message");
          server.onRemoteMessage(ctx, msg);
        } else {
          logger.debug("local message");
          server.onLocalMessage(ctx, msg);
        }
      } finally {
        message.release();
      }
    }

    @Override
    public void onConnect(ChannelHandlerContext ctx) {
      // 成功连接到新节点,发送topic
      if (fromRemote) {
        try {
          logger.debug("endpoint connection established,send topic");
          broadcastTopic(ctx);
        } catch (Exception e) {
          logger.error("error ", e);
        }
      }
    }

    @Override
    public void onDisconnect(ChannelHandlerContext ctx) {
      // 有sdk断开,需更新topic
      if (!fromRemote) {
        // 需要清除该连接的信息
        logger.debug("SDK disconnect,update and broadcast topic");

        broadcastTopic();
      }
    }

    private Server server;
    private Boolean fromRemote = false;
  }

  public ChannelConnections getLocalConnections() {
    return localConnections;
  }

  public void setLocalConnections(ChannelConnections localConnections) {
    this.localConnections = localConnections;
  }

  public ChannelConnections getRemoteConnections() {
    return remoteConnections;
  }

  public void setRemoteConnections(ChannelConnections connections) {
    this.remoteConnections = connections;
  }

  public Map getSeq2Connections() {
    return seq2Connections;
  }

  public void setSeq2Connections(Map seq2Connections) {
    this.seq2Connections = seq2Connections;
  }

  public Integer getBindPort() {
    return bindPort;
  }

  public void setBindPort(Integer bindPort) {
    this.bindPort = bindPort;
  }

  public Timer getTimeoutHandler() {
    return timeoutHandler;
  }

  public void setTimeoutHandler(Timer timeoutHandler) {
    this.timeoutHandler = timeoutHandler;
  }

  public void run() throws SSLException {
    logger.debug("init ProxyServer");

    try {
      ConnectionCallback localConnectionCallback = new ConnectionCallback();
      localConnectionCallback.setServer(this);
      localConnectionCallback.setFromRemote(false);

      ConnectionCallback remoteConnectionCallback = new ConnectionCallback();
      remoteConnectionCallback.setServer(this);
      remoteConnectionCallback.setFromRemote(true);

      localConnections.setCallback(localConnectionCallback);
      localConnections.startListen(bindPort);

      remoteConnections.setCallback(remoteConnectionCallback);
      remoteConnections.init();
      remoteConnections.setThreadPool(threadPool);
      remoteConnections.startConnect();
    } catch (Exception e) {
      logger.error("error ", e);

      throw e;
    }
  }

  public void broadcastTopic() {
    broadcastTopic(null);
  }

  public void broadcastTopic(ChannelHandlerContext ctx) {
    try {
      Message message = new Message();
      message.setResult(0);
      message.setType((short) 0x32); // topic设置topic消息0x32
      message.setSeq(UUID.randomUUID().toString().replaceAll("-", ""));

      // 综合所有的topics
      Set allTopics = new HashSet();
      for (ConnectionInfo connectionInfo : localConnections.getConnections()) {
        // 有效的连接,才增加到全局topic
        ChannelHandlerContext localCtx =
            localConnections.getNetworkConnectionByHost(
                connectionInfo.getHost(), connectionInfo.getPort());

        if (localCtx != null && localCtx.channel().isActive()) {
          logger.debug(
              "node:{}:{} follow topics: {}",
              connectionInfo.getHost(),
              connectionInfo.getPort(),
              connectionInfo.getTopics());
          allTopics.addAll(connectionInfo.getTopics());
        }
      }

      message.setData(objectMapper.writeValueAsBytes(allTopics.toArray()));

      logger.debug("all topics: {}", new String(message.getData()));

      if (ctx == null) {
        // 广播到所有远端节点
        for (String key : remoteConnections.getNetworkConnections().keySet()) {
          ChannelHandlerContext remoteCtx = remoteConnections.getNetworkConnections().get(key);

          if (remoteCtx != null && remoteCtx.channel().isActive()) {
            ByteBuf out = remoteCtx.alloc().buffer();
            message.writeHeader(out);
            message.writeExtra(out);

            if (remoteCtx != null && remoteCtx.channel().isActive()) {
              logger.debug(
                  "send topic {}:{}",
                  ((SocketChannel) remoteCtx.channel())
                      .remoteAddress()
                      .getAddress()
                      .getHostAddress(),
                  ((SocketChannel) remoteCtx.channel()).remoteAddress().getPort());

              remoteCtx.writeAndFlush(out);
            }
          }
        }
      } else {
        // 发送到指定远端节点
        logger.debug(
            "topic send to {}:{}",
            ((SocketChannel) ctx.channel()).remoteAddress().getAddress().getHostAddress(),
            ((SocketChannel) ctx.channel()).remoteAddress().getPort());

        ByteBuf out = ctx.alloc().buffer();
        message.writeHeader(out);
        message.writeExtra(out);

        ctx.writeAndFlush(out);
      }
    } catch (Exception e) {
      logger.error("error ", e);
    }
  }

  public void onLocalMessage(ChannelHandlerContext ctx, Message message) {
    try {
      logger.debug("sdk request: " + message.getSeq());

      ChannelHandlerContext remoteCtx = null;

      ConnectionPair pair = seq2Connections.get(message.getSeq());

      if (pair != null) {
        // 已有这个seq,发往远端的响应
        logger.debug("seq existed");

        // 发送到远端的响应
        remoteCtx = pair.remoteConnection;

        if (message.getType() != 0x31) {
          pair.localConnection = ctx;
        }

        ByteBuf out = remoteCtx.alloc().buffer();
        message.writeHeader(out);
        message.writeExtra(out);

        logger.debug(
            "msg send to:{}:{}",
            ((SocketChannel) remoteCtx.channel()).remoteAddress().getAddress().getHostAddress(),
            ((SocketChannel) remoteCtx.channel()).remoteAddress().getPort());
        remoteCtx.writeAndFlush(out);
      } else {
        pair = new ConnectionPair();
        pair.localConnection = ctx;
        pair.setServer(this);
        pair.setMessage(message);

        // 没有这个seq,可能是新发请求或者新收到的push
        // 本地发往远程的消息,如果是链上链下,需要按给定的nodeID发
        if (message.getType() == 0x20 || message.getType() == 0x21) {
          // 获取nodeID
          logger.debug("channel message v1");
          if (message.getData().length < 256) {
            logger.error(
                "wrong channel message, length less than 256:{}", message.getData().length);
          }

          // 获取nodeID对应的连接,检查可用性
          String nodeID = new String(message.getData(), 128, 128);

          logger.debug("forward:{}", nodeID, message.getData());
          for (ConnectionInfo conn : remoteConnections.getConnections()) {
            if (conn.getNodeID().equals(nodeID)) {
              remoteCtx =
                  remoteConnections.getNetworkConnectionByHost(conn.getHost(), conn.getPort());
              pair.remoteConnection = remoteCtx;

              break;
            }
          }

          if (remoteCtx == null || !remoteCtx.channel().isActive()) {
            // 找不到连接,错误
            logger.error("connect exception,error 99");

            if (message.getType() == 0x20 || message.getType() == 0x21) {
              message.setType((short) 0x21);
            } else {
              message.setType((short) 0x31);
            }

            message.setResult(99);

            ByteBuf out = ctx.alloc().buffer();
            message.writeHeader(out);
            message.writeExtra(out);

            ctx.writeAndFlush(out);

            return;
          }

          ByteBuf out = remoteCtx.alloc().buffer();
          message.writeHeader(out);
          message.writeExtra(out);

          logger.debug(
              "send to:{}:{}",
              ((SocketChannel) remoteCtx.channel()).remoteAddress().getAddress().getHostAddress(),
              ((SocketChannel) remoteCtx.channel()).remoteAddress().getPort());
          remoteCtx.writeAndFlush(out);
          pair.init();
        } else {
          logger.debug("other type message,ConnectionPair");

          pair.setRemoteChannelConnections(remoteConnections);

          List remoteConnectionInfos = new ArrayList();
          remoteConnectionInfos.addAll(remoteConnections.getConnections());
          pair.setRemoteConnectionInfos(remoteConnectionInfos);

          seq2Connections.put(message.getSeq(), pair);

          pair.init();
          pair.retrySendRemoteMessage();
        }
      }
    } catch (Exception e) {
      logger.error("error ", e);
    }
  }

  public void onRemoteMessage(ChannelHandlerContext ctx, Message message) {
    try {
      logger.debug("processing : " + message.getSeq());

      ChannelHandlerContext localCtx = null;

      ConnectionPair pair = seq2Connections.get(message.getSeq());

      if (message.getType() == 0x30) {
        // 链上链下二期,需要找到关注该topic的连接
        Short length = (short) message.getData()[0];
        String topic = new String(message.getData(), 1, length - 1);

        Set topicCtxs = new HashSet();
        for (ConnectionInfo connectionInfo : localConnections.getConnections()) {
          if (connectionInfo.getTopics().contains(topic)) {
            ChannelHandlerContext topicCtx =
                localConnections.getNetworkConnectionByHost(
                    connectionInfo.getHost(), connectionInfo.getPort());

            if (topicCtx != null && topicCtx.channel().isActive()) {
              topicCtxs.add(topicCtx);
            }
          }
        }

        logger.debug("send topic:{} sum{} follow topic", topic, topicCtxs.size());

        if (topicCtxs.isEmpty()) {
          // 找不到连接,错误
          logger.error("connection not found,error 99");

          message.setType((short) 0x31);
          message.setResult(99);

          ByteBuf out = ctx.alloc().buffer();
          message.writeHeader(out);
          message.writeExtra(out);

          ctx.writeAndFlush(out);

          return;
        }

        // 随机下发
        Random random = new SecureRandom();
        Integer index = random.nextInt(topicCtxs.size());
        ChannelHandlerContext target = (ChannelHandlerContext) topicCtxs.toArray()[index];

        logger.debug(
            "send to {}:{}",
            ((SocketChannel) target.channel()).remoteAddress().getAddress().getHostAddress(),
            ((SocketChannel) target.channel()).remoteAddress().getPort());

        localCtx = target;

        if (pair == null) {
          pair = new ConnectionPair();
          pair.localConnection = localCtx;
          pair.remoteConnection = ctx;
          pair.setServer(this);
          pair.setMessage(message);

          seq2Connections.put(message.getSeq(), pair);
          pair.init();
        } else {
          pair.remoteConnection = ctx;
        }
      } else {
        if (pair != null) {
          // 已有这个seq,可能是发送响应或者收到回包消息
          logger.debug("seq existed");

          // 收到来自远端的回包
          localCtx = pair.localConnection;

          if (message.getResult() != 0 && message.getType() == 0x31) {
            // 链上链下二期错误时,执行retry
            logger.error("endpoint error:{},retry", message.getResult());

            pair.retrySendRemoteMessage();
            return;
          }

          pair.remoteConnection = ctx;
        } else {
          // 没有这个seq,可能是新发请求或者新收到的push

          // 其他消息(链上链下一期),随机发
          localCtx = localConnections.randomNetworkConnection();
        }
      }

      if (localCtx == null || !localCtx.channel().isActive()) {
        // 找不到连接,错误
        logger.error("connect unavailable,error 99");

        if (message.getType() == 0x20 || message.getType() == 0x21) {
          message.setType((short) 0x21);
        } else {
          message.setType((short) 0x31);
        }

        message.setResult(99);

        ByteBuf out = ctx.alloc().buffer();
        message.writeHeader(out);
        message.writeExtra(out);

        ctx.writeAndFlush(out);

        return;
      }

      ByteBuf out = localCtx.alloc().buffer();
      message.writeHeader(out);
      message.writeExtra(out);

      logger.debug(
          "send to:{}:{}",
          ((SocketChannel) localCtx.channel()).remoteAddress().getAddress().getHostAddress(),
          ((SocketChannel) localCtx.channel()).remoteAddress().getPort());
      localCtx.writeAndFlush(out);
    } catch (Exception e) {
      logger.error("error ", e);
    }
  }

  public void onHeartBeat(ChannelHandlerContext ctx, Message message) {
    String content = "1";
    try {
      content = new String(message.getData(), "utf-8");
    } catch (UnsupportedEncodingException e) {
      logger.error("unexpected heartbeat ");
    } catch (Exception e) {
      logger.error("heartbeat error");
    }

    if (content.equals("0")) {
      Message response = new Message();

      response.setSeq(message.getSeq());
      response.setResult(0);
      response.setType((short) 0x13);
      response.setData("1".getBytes());

      ByteBuf out = ctx.alloc().buffer();
      response.writeHeader(out);
      response.writeExtra(out);

      ctx.writeAndFlush(out);
    } else if (content.equals("1")) {
    }
  }

  public void onTopic(ChannelHandlerContext ctx, Message message) {
    logger.debug("SDK topics message: {} {}", message.getSeq(), new String(message.getData()));
    String host = ((SocketChannel) ctx.channel()).remoteAddress().getAddress().getHostAddress();
    Integer port = ((SocketChannel) ctx.channel()).remoteAddress().getPort(); //
    ConnectionInfo info = localConnections.getConnectionInfo(host, port);

    if (info != null) {
      try {
        List topics = objectMapper.readValue(message.getData(), List.class);

        info.setTopics(topics);

        broadcastTopic();
      } catch (Exception e) {
        logger.error("parse topic error", e);
      }
    }
  }

  public ThreadPoolTaskExecutor getThreadPool() {
    return threadPool;
  }

  public void setThreadPool(ThreadPoolTaskExecutor threadPool) {
    this.threadPool = threadPool;
  }

  // private String orgID;
  private ChannelConnections localConnections = new ChannelConnections();
  private ChannelConnections remoteConnections;
  private Map seq2Connections =
      new ConcurrentHashMap();
  private Integer bindPort = 8830;
  private ObjectMapper objectMapper = new ObjectMapper();
  private Timer timeoutHandler = new HashedWheelTimer();

  private ThreadPoolTaskExecutor threadPool;
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy