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

com.avos.avoscloud.AppRouterManager Maven / Gradle / Ivy

package com.avos.avoscloud;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import okhttp3.Request;


/**
 * Created by wli on 16/5/6.
 */
public class AppRouterManager {

  /**
   * app router 地址
   */
  private static final String ROUTER_ADDRESS = " https://app-router.leancloud.cn/2/route?appId=";

  /**
   * share preference 的 key 值
   */
  private static final String API_SERVER_KEY = "api_server";
  private static final String STATS_SERVRE_KEY = "stats_server";
  private static final String RTM_ROUTER_SERVRE_KEY = "rtm_router_server";
  private static final String PUSH_SERVRE_KEY = "push_server";
  private static final String ENGINE_SERVRE_KEY = "engine_server";
  private static final String TTL_KEY = "ttl";

  private static final String LATEST_UPDATE_TIME_KEY = "latest_update_time";

  /**
   * api 默认的地址
   */
  private static final String DEFAULT_QCLOUD_API_SERVER = "https://e1-api.leancloud.cn";
  private static final String DEFALUT_US_API_SERVER = "https://us-api.leancloud.cn";

  /**
   * push router 默认地址
   */
  private static final String DEFAULT_QCLOUD_ROUTER_SERVER = "https://router-q0-push.leancloud.cn";
  private static final String DEFAULT_US_ROUTER_SERVER = "https://router-a0-push.leancloud.cn";


  private Map apiMaps = new ConcurrentHashMap<>();
  private static Map customApiMaps = new ConcurrentHashMap<>();

  private static AppRouterManager appRouterManager;

  public synchronized static AppRouterManager getInstance() {
    if (null == appRouterManager) {
      appRouterManager = new AppRouterManager();
    }
    return appRouterManager;
  }

  private AppRouterManager() {
  }

  static void setServer(AVOSCloud.SERVER_TYPE server, String host) {
    customApiMaps.put(server.name, host);
    RequestStatisticsUtil.REPORT_INTERNAL_STATS = false;
  }

  String getStorageServer() {
    return getServerUrl(AVOSCloud.SERVER_TYPE.API);
  }

  /**
   * 处理  /push, /installations 所有请求
   * @return
   */
  String getPushServer() {
    return getServerUrl(AVOSCloud.SERVER_TYPE.PUSH);
  }

  String getStatsServer() {
    return getServerUrl(AVOSCloud.SERVER_TYPE.STATS);
  }

  String getEngineServer() {
    return getServerUrl(AVOSCloud.SERVER_TYPE.ENGINE);
  }

  public String getRtmRouterServer() {
    return getServerUrl(AVOSCloud.SERVER_TYPE.RTM);
  }

  private String getServerUrl(AVOSCloud.SERVER_TYPE type) {
    if (customApiMaps.containsKey(type.name)) {
      return customApiMaps.get(type.name);
    }

    final boolean isRtm = type.equals(AVOSCloud.SERVER_TYPE.RTM);

    // 美国节点
    if (isUsApp(AVOSCloud.applicationId)) {
      return isRtm ? DEFAULT_US_ROUTER_SERVER : DEFALUT_US_API_SERVER;
    }

    // QCloud 节点
    if (isQCloudApp(AVOSCloud.applicationId)) {
      return isRtm ? DEFAULT_QCLOUD_ROUTER_SERVER : DEFAULT_QCLOUD_API_SERVER;
    }

    // UCloud 节点
    if (apiMaps.containsKey(type.name) && !AVUtils.isBlankString(apiMaps.get(type.name))) {
      return apiMaps.get(type.name);
    } else {
      return getUcloudDefaultServer(type);
    }
  }

  /**
   * 获取默认的 UCloud 节点的 url
   * @param type
   * @return
   */
  private String getUcloudDefaultServer(AVOSCloud.SERVER_TYPE type) {
    if (!AVUtils.isBlankString(AVOSCloud.applicationId)) {
      return String.format("https://%s.%s.lncld.net", AVOSCloud.applicationId.substring(0, 8), type.name);
    } else {
      LogUtil.avlog.e("AppId is null, Please call AVOSCloud.initialize first");
      return "";
    }
  }


  /**
   * 更新 router url
   * 有可能因为测试或者 301 等原因需要运行过程中修改 url
   *
   * @param router
   * @param persistence 是否需要持久化存储到本地
   *                    为 true 则存到本地,app 下次打开后仍有效果,否则仅当次声明周期内有效
   */
  public void updateRtmRouterServer(String router, boolean persistence) {
    apiMaps.put(AVOSCloud.SERVER_TYPE.RTM.name, addHttpsPrefix(router));
    if (persistence) {
      AVPersistenceUtils.sharedInstance().savePersistentSettingString(
        getAppRouterSPName(), RTM_ROUTER_SERVRE_KEY, apiMaps.get(AVOSCloud.SERVER_TYPE.RTM.name));
    }
  }

  /**
   * 拉取 router 地址
   *
   * @param force 是否强制拉取,如果为 true 则强制拉取,如果为 false 则需要间隔超过 ttl 才会拉取
   */
  void fetchRouter(boolean force) {
    fetchRouter(force, null);
  }

  /**
   * 添加此函数仅仅是为了测试时使用
   * @param force
   * @param callback
   */
  void fetchRouter(boolean force, final AVCallback callback) {
    if (!isUsApp(AVOSCloud.applicationId)) {
      updateServers();

      Long lastTime = AVPersistenceUtils.sharedInstance().getPersistentSettingLong(
        getAppRouterSPName(), LATEST_UPDATE_TIME_KEY, 0L);

      int ttl = AVPersistenceUtils.sharedInstance().getPersistentSettingInteger(
        getAppRouterSPName(), TTL_KEY, 0);

      if (force || System.currentTimeMillis() - lastTime > ttl * 1000) {
        AVHttpClient client = AVHttpClient.clientInstance();
        Request.Builder builder = new Request.Builder();
        builder.url(ROUTER_ADDRESS + AVOSCloud.applicationId).get();
        client.execute(builder.build(), false, new GetHttpResponseHandler(new GenericObjectCallback() {
          @Override
          public void onSuccess(String content, AVException e) {
            if (null == e) {
              if (AVOSCloud.showInternalDebugLog()) {
                LogUtil.avlog.d(" fetchRouter :" + content);
              }

              saveRouterResult(content);
            } else {
              LogUtil.avlog.e("get router error ", e);
            }
            if (null != callback) {
              callback.internalDone(e);
            }
          }

          @Override
          public void onFailure(Throwable error, String content) {
            LogUtil.avlog.e("get router error ", new AVException(error));
            if (null != callback) {
              callback.internalDone(new AVException(error));
            }
          }

          @Override
          public boolean isRequestStatisticNeed() {
            return false;
          }
        }));
      } else {
        if (null != callback) {
          callback.internalDone(null);
        }
      }
    } else {
      if (null != callback) {
        callback.internalDone(null);
      }
    }
  }

  private void saveRouterResult(String result) {
    com.alibaba.fastjson.JSONObject response = null;
    try {
      response = JSON.parseObject(result);
    } catch (Exception exception) {
      LogUtil.avlog.e("get router error ", exception);
    }

    if (null != response) {
      updateMapAndSaveLocal(apiMaps, response, AVOSCloud.SERVER_TYPE.RTM.name, RTM_ROUTER_SERVRE_KEY);
      updateMapAndSaveLocal(apiMaps, response, AVOSCloud.SERVER_TYPE.PUSH.name, PUSH_SERVRE_KEY);
      updateMapAndSaveLocal(apiMaps, response, AVOSCloud.SERVER_TYPE.API.name, API_SERVER_KEY);
      updateMapAndSaveLocal(apiMaps, response, AVOSCloud.SERVER_TYPE.STATS.name, STATS_SERVRE_KEY);
      updateMapAndSaveLocal(apiMaps, response, AVOSCloud.SERVER_TYPE.ENGINE.name, ENGINE_SERVRE_KEY);

      if (response.containsKey(TTL_KEY)) {
        AVPersistenceUtils.sharedInstance().savePersistentSettingInteger(
          getAppRouterSPName(), TTL_KEY, response.getIntValue(TTL_KEY));
      }

      AVPersistenceUtils.sharedInstance().savePersistentSettingLong(
        getAppRouterSPName(), LATEST_UPDATE_TIME_KEY, System.currentTimeMillis());
    }
  }

  private void updateMapAndSaveLocal(Map maps, JSONObject jsonObject, String mapKey, String jsonKey) {
    if (jsonObject.containsKey(jsonKey)) {
      String value = addHttpsPrefix(jsonObject.getString(jsonKey));
      AVPersistenceUtils.sharedInstance().savePersistentSettingString(
        getAppRouterSPName(), jsonKey, value);
      if (!AVUtils.isBlankString(value)) {
        maps.put(mapKey, value);
      }
    }
  }

  private void refreshMap(Map maps, String mapKey, String spKey) {
    String value = AVPersistenceUtils.sharedInstance().getPersistentSettingString(
      getAppRouterSPName(), spKey, "");
    if (!AVUtils.isBlankString(value)) {
      maps.put(mapKey, value);
    }
  }

  private String getAppRouterSPName() {
    return "com.avos.avoscloud.approuter." + AVOSCloud.applicationId;
  }

  /**
   * 根据当前 appId 更新 shareprefenence 的 name
   * 这样如果运行过程中动态切换了 appId,app router 仍然可以正常 work
   */
  private void updateServers() {
    refreshMap(apiMaps, AVOSCloud.SERVER_TYPE.RTM.name, RTM_ROUTER_SERVRE_KEY);
    refreshMap(apiMaps, AVOSCloud.SERVER_TYPE.PUSH.name, PUSH_SERVRE_KEY);
    refreshMap(apiMaps, AVOSCloud.SERVER_TYPE.API.name, API_SERVER_KEY);
    refreshMap(apiMaps, AVOSCloud.SERVER_TYPE.STATS.name, STATS_SERVRE_KEY);
    refreshMap(apiMaps, AVOSCloud.SERVER_TYPE.ENGINE.name, ENGINE_SERVRE_KEY);
  }

  /**
   * 添加 https 前缀
   * 主要是因为 server 部分 url 返回数据不一致,有的有前缀,有的没有
   *
   * @param url
   * @return
   */
  private String addHttpsPrefix(String url) {
    if (!AVUtils.isBlankString(url) && !url.startsWith("http")) {
      return "https://" + url;
    }
    return url;
  }

  /**
   * QCloud 节点的末尾是写死的,这里根据末尾后缀判断是否为 QCloud 节点
   *
   * @return
   */
  static boolean isQCloudApp(String appId) {
    return !AVUtils.isBlankString(appId) && appId.endsWith("9Nh9j0Va");
  }

  /**
   * 判断是否为 us 节点
   * @param appId
   * @return
   */
  static boolean isUsApp(String appId) {
    return !AVOSCloud.isCN() || (!AVUtils.isBlankString(appId) && appId.endsWith("MdYXbMMI"));
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy