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

com.avos.avospush.push.AVPushRouter Maven / Gradle / Ivy

The newest version!
package com.avos.avospush.push;

import android.content.Context;
import android.content.SharedPreferences;

import com.alibaba.fastjson.JSON;
import com.avos.avoscloud.AVException;
import com.avos.avoscloud.AVHttpClient;
import com.avos.avoscloud.AVInstallation;
import com.avos.avoscloud.AVOSCloud;
import com.avos.avoscloud.AVUtils;
import com.avos.avoscloud.AppRouterManager;
import com.avos.avoscloud.GenericObjectCallback;
import com.avos.avoscloud.GetHttpResponseHandler;
import com.avos.avoscloud.LogUtil;
import com.avos.avoscloud.im.v2.AVIMOptions;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import okhttp3.Request;

/**
 * Created by yangchaozhong on 3/14/14.
 */
public class AVPushRouter {
  public static final String SERVER = "server";
  private static final String EXPIRE_AT = "expireAt";
  private static final String SECONDARY = "secondary";

  private static String ROUTER_QUERY_SRTING = "/v1/route?appId=%s&installationId=%s&secure=1";
  private static final String PUSH_SERVER_CACHE_KEY_FMT = "com.avos.push.router.server.cache%s";

  private final Context context;
  private final String installationId;
  private int ttlInSecs = -1;

  // router 请求的默认超时时间为 5 秒,否则 15 秒时间太长了
  private static final int ROUTER_REQUEST_TIME_OUT = 5 * 1000;

  private AVHttpClient routerHttpClient;

  private RouterResponseListener listener;

  // 是否正在发送请求,没有必要重复发送请求
  private volatile boolean isRequesting = false;

  // socket 连续连接失败的次数
  private AtomicInteger socketLostNum = new AtomicInteger(0);

  // 是否读取 permary 缓存
  private volatile boolean isPrimarySever = true;

  /**
   * AVPushRouter is used to get push server refer to appId and installationId.
   *
   * @param context application context of PushService
   */
  public AVPushRouter(Context context, RouterResponseListener listener) {
    this.context = context;
    this.listener = listener;
    this.installationId = AVInstallation.getCurrentInstallation(context).getInstallationId();
  }

  private String getRouterUrl() {
    String routerUrl = AppRouterManager.getInstance().getRtmRouterServer() + ROUTER_QUERY_SRTING;
    return String.format(routerUrl, AVOSCloud.applicationId, installationId);
  }

  private synchronized AVHttpClient getRouterHttpClient() {
    if (null == routerHttpClient) {
      routerHttpClient = AVHttpClient.newClientInstance(ROUTER_REQUEST_TIME_OUT);
    }
    return routerHttpClient;
  }

  /**
   * 避免对 router 进行重复请求,对 socket 结果进行处理
   * 如果 socket 连接成功,则继续使用缓存数据
   * 如果 连续两次失败,则第三次使用 secondary server
   * 如果连续四次失败,则第五次会去网络请求 router 数据
   * @param e
   */
  public void processSocketConnectionResult(AVException e) {
    if (null == e) {
      socketLostNum.set(0);
    } else {
      final String errorMessage = e.getMessage();
      if (AVUtils.isConnected(this.context)
        && (AVUtils.isBlankContent(errorMessage) || !errorMessage.contains("Permission"))) {
        // 只有有网络时才需要累加,并且如果是因为权限引起的错误,不需要累加(同时也是为了处理小米的神隐模式)
        socketLostNum.incrementAndGet();
        if (socketLostNum.get() > 1) {
          // 当连续两次失败后,换用 secondary server
          isPrimarySever = false;
        }
      }
    }
  }

  /**
   * fetch push server:
*
    *
  • fetch push server from router.
  • *
  • use ttl to judge if it's no need to fetch push server from router and get push server from * cache instead.
  • *
      * * @return null or {"groupId":"xxx", "server":"ws://..."} */ public void fetchPushServer() { if (AVUtils.isBlankString(AVOSCloud.applicationId)) { LogUtil.avlog.e("Please initialize Application first"); return; } String specifiedServer = AVIMOptions.getGlobalOptions().getRTMServer(); if (!AVUtils.isBlankString(specifiedServer)) { listener.onServerAddress(specifiedServer); } else if (!AVUtils.isConnected(this.context)) { // 无网络时只能返回缓存数据 Map pushServerCache = getPushServerFromCache(); if (pushServerCache != null) { listener.onServerAddress((String) pushServerCache.get(SERVER)); } else { listener.onServerAddress(null); } } else { Map pushServerCache = getPushServerFromCache(); if ((pushServerCache != null && (Long) pushServerCache.get(EXPIRE_AT) > System.currentTimeMillis()) && socketLostNum.get() <= 3) { // 如果缓存有效并且连续失败小于四次,则从缓存中获取数据 String serverAddress = (String) pushServerCache.get(SERVER); if (!isPrimarySever) { String secondaryAddress = (String)pushServerCache.get(SECONDARY); if (!AVUtils.isBlankContent(secondaryAddress)) { serverAddress = secondaryAddress; } } listener.onServerAddress(serverAddress); if (AVOSCloud.isDebugLogEnabled()) { LogUtil.avlog.d("get push server from cache:" + serverAddress); } } else { // 如果缓存无效,则发送请求 fetchPushServerFromServer(); } } } private void fetchPushServerFromServer() { if (isRequesting) { // 避免重复请求 return; } isRequesting = true; final String routerUrlStr = getRouterUrl(); if (AVOSCloud.showInternalDebugLog()) { LogUtil.avlog.d("try to fetch push server from :" + routerUrlStr); } final GenericObjectCallback callback = new GenericObjectCallback() { @Override public void onSuccess(String content, AVException e) { if (e == null) { try { socketLostNum.set(0); HashMap response = JSON.parseObject(content, HashMap.class); ttlInSecs = (Integer) response.get("ttl"); HashMap result = new HashMap(); result.put(SERVER, response.get(SERVER)); result.put(EXPIRE_AT, ttlInSecs * 1000l + System.currentTimeMillis()); result.put(SECONDARY, response.get(SECONDARY)); if (response.containsKey("groupUrl")) { AppRouterManager.getInstance().updateRtmRouterServer( (String) response.get("groupUrl"), true); } cachePushServer(result); listener.onServerAddress((String) result.get(SERVER)); isPrimarySever = true; } catch (Exception e1) { this.onFailure(e1, content); } } isRequesting = false; } @Override public void onFailure(Throwable error, String content) { if (AVOSCloud.showInternalDebugLog()) { LogUtil.avlog.d("failed to fetch push server:" + error); } listener.onServerAddress(null); isRequesting = false; } @Override public boolean isRequestStatisticNeed() { return false; } }; Request.Builder builder = new Request.Builder(); builder.url(routerUrlStr).get(); if (AVOSCloud.isDebugLogEnabled()) { LogUtil.avlog.d("get router url: " + routerUrlStr); } getRouterHttpClient().execute(builder.build(), false, new GetHttpResponseHandler(callback)); } private HashMap getPushServerFromCache() { HashMap pushServerMap = new HashMap(); SharedPreferences pushServerData = context .getSharedPreferences( String.format(PUSH_SERVER_CACHE_KEY_FMT, AVOSCloud.applicationId), Context.MODE_PRIVATE); pushServerMap.put(SERVER, pushServerData.getString(SERVER, null)); pushServerMap.put(EXPIRE_AT, pushServerData.getLong(EXPIRE_AT, 0)); pushServerMap.put(SECONDARY, pushServerData.getString(SECONDARY, null)); return pushServerMap; } private void cachePushServer(HashMap pushServerMap) { SharedPreferences pushServerData = context .getSharedPreferences( String.format(PUSH_SERVER_CACHE_KEY_FMT, AVOSCloud.applicationId), Context.MODE_PRIVATE); SharedPreferences.Editor editor = pushServerData.edit(); editor.putString(SERVER, (String) pushServerMap.get(SERVER)); editor.putLong(EXPIRE_AT, (Long) pushServerMap.get(EXPIRE_AT)); editor.putString(SECONDARY, (String) pushServerMap.get(SECONDARY)); editor.commit(); } public interface RouterResponseListener { void onServerAddress(String address); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy