content: /*
   * Copyright 1999-2018 Alibaba Group Holding Ltd.
   *
   * Licensed 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 com.alibaba.csp.sentinel.transport.config;
  
  import com.alibaba.csp.sentinel.config.SentinelConfig;
  import com.alibaba.csp.sentinel.log.RecordLog;
  import com.alibaba.csp.sentinel.util.HostNameUtil;
  import com.alibaba.csp.sentinel.util.StringUtil;
  import com.alibaba.csp.sentinel.transport.endpoint.Endpoint;
  import com.alibaba.csp.sentinel.transport.endpoint.Protocol;
  
  import java.util.ArrayList;
  import java.util.List;
  
  /**
   * @author Carpenter Lee
   * @author Jason Joo
   * @author Leo Li
   */
  public class TransportConfig {
  
      public static final String CONSOLE_SERVER = "csp.sentinel.dashboard.server";
      public static final String SERVER_PORT = "csp.sentinel.api.port";
      public static final String HEARTBEAT_INTERVAL_MS = "csp.sentinel.heartbeat.interval.ms";
      public static final String HEARTBEAT_CLIENT_IP = "csp.sentinel.heartbeat.client.ip";
      public static final String HEARTBEAT_API_PATH = "csp.sentinel.heartbeat.api.path";
  
      public static final String HEARTBEAT_DEFAULT_PATH = "/registry/machine";
  
      private static int runtimePort = -1;
  
      /**
       * Get heartbeat interval in milliseconds.
       *
       * @return heartbeat interval in milliseconds if exists, or null if not configured or invalid config
       */
      public static Long getHeartbeatIntervalMs() {
          String interval = SentinelConfig.getConfig(HEARTBEAT_INTERVAL_MS);
          try {
              return interval == null ? null : Long.parseLong(interval);
          } catch (Exception ex) {
              RecordLog.warn("[TransportConfig] Failed to parse heartbeat interval: " + interval);
              return null;
          }
      }
  
      /**
       * Get a list of Endpoint(protocol, ip/domain, port) indicating Sentinel Dashboard's address.<br>
       * NOTE: only support <b>HTTP</b> and <b>HTTPS</b> protocol
       *
       * @return list of Endpoint(protocol, ip/domain, port). <br>
       *         <b>May not be null</b>. <br>
       *         An empty list returned when not configured.
       */
      public static List<Endpoint> getConsoleServerList() {
          String config = SentinelConfig.getConfig(CONSOLE_SERVER);
          List<Endpoint> list = new ArrayList<Endpoint>();
          if (StringUtil.isBlank(config)) {
              return list;
          }
  
          int pos = -1;
          int cur = 0;
          while (true) {
              pos = config.indexOf(',', cur);
              if (cur < config.length() - 1 && pos < 0) {
                  // for single segment, pos move to the end
                  pos = config.length();
              }
              if (pos < 0) {
                  break;
              }
              if (pos <= cur) {
                  cur ++;
                  continue;
              }
              // parsing
              String ipPortStr = config.substring(cur, pos);
              cur = pos + 1;
              if (StringUtil.isBlank(ipPortStr)) {
                  continue;
              }
              ipPortStr = ipPortStr.trim();
              int port = 80;
              Protocol protocol = Protocol.HTTP;
              if (ipPortStr.startsWith("http://")) {
                  ipPortStr = ipPortStr.substring(7);
              } else if (ipPortStr.startsWith("https://")) {
                  ipPortStr = ipPortStr.substring(8);
                  port = 443;
                  protocol = Protocol.HTTPS;
              }
              int index = ipPortStr.indexOf(":");
              if (index == 0) {
                  // skip
                  continue;
              }
              String host = ipPortStr;
              if (index >= 0) {
                  try {
                      port = Integer.parseInt(ipPortStr.substring(index + 1));
                      if (port <= 1 || port >= 65535) {
                          throw new RuntimeException("Port number [" + port + "] over range");
                      }
                  } catch (Exception e) {
                      RecordLog.warn("Parse port of dashboard server failed: " + ipPortStr, e);
                      // skip
                      continue;
                  }
                  host = ipPortStr.substring(0, index);
              }
              list.add(new Endpoint(protocol, host, port));
          }
          return list;
      }
  
      public static int getRuntimePort() {
          return runtimePort;
      }
  
      /**
       * Get Server port of this HTTP server.
       *
       * @return the port, maybe null if not configured.
       */
      public static String getPort() {
          if (runtimePort > 0) {
              return String.valueOf(runtimePort);
          }
          return SentinelConfig.getConfig(SERVER_PORT, true);
      }
  
      /**
       * Set real port this HTTP server uses.
       *
       * @param port real port.
       */
      public static void setRuntimePort(int port) {
          runtimePort = port;
      }
  
      /**
       * Get heartbeat client local ip.
       * If the client ip not configured,it will be the address of local host
       *
       * @return the local ip.
       */
      public static String getHeartbeatClientIp() {
          String ip = SentinelConfig.getConfig(HEARTBEAT_CLIENT_IP, true);
          if (StringUtil.isBlank(ip)) {
              ip = HostNameUtil.getIp();
          }
          return ip;
      }
  
      /**
       * Get the heartbeat api path. If the machine registry path of the dashboard
       * is modified, then the API path should also be consistent with the API path of the dashboard.
       *
       * @return the heartbeat api path
       * @since 1.7.1
       */
      public static String getHeartbeatApiPath() {
          String apiPath = SentinelConfig.getConfig(HEARTBEAT_API_PATH);
          if (StringUtil.isBlank(apiPath)) {
              return HEARTBEAT_DEFAULT_PATH;
          }
          if (!apiPath.startsWith("/")) {
              apiPath = "/" + apiPath;
          }
          return apiPath;
      }
  }
  