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

io.agora.rtm.internal.RtmClientImpl Maven / Gradle / Ivy

package io.agora.rtm.internal;

import io.agora.common.internal.BuildConfig;
import io.agora.rtm.ChannelInfo;
import io.agora.rtm.ErrorInfo;
import io.agora.rtm.GetOnlineUsersResult;
import io.agora.rtm.LockDetail;
import io.agora.rtm.LockEvent;
import io.agora.rtm.MessageEvent;
import io.agora.rtm.Metadata;
import io.agora.rtm.PresenceEvent;
import io.agora.rtm.PublishOptions;
import io.agora.rtm.ResultCallback;
import io.agora.rtm.RtmClient;
import io.agora.rtm.RtmConfig;
import io.agora.rtm.RtmConstants;
import io.agora.rtm.RtmConstants.RtmConnectionChangeReason;
import io.agora.rtm.RtmConstants.RtmConnectionState;
import io.agora.rtm.RtmConstants.RtmErrorCode;
import io.agora.rtm.RtmConstants.RtmMessageType;
import io.agora.rtm.RtmEventListener;
import io.agora.rtm.RtmLock;
import io.agora.rtm.RtmPresence;
import io.agora.rtm.RtmStorage;
import io.agora.rtm.StorageEvent;
import io.agora.rtm.StreamChannel;
import io.agora.rtm.SubscribeOptions;
import io.agora.rtm.SubscribeTopicResult;
import io.agora.rtm.TopicEvent;
import io.agora.rtm.UserState;
import io.agora.rtm.WhoNowResult;
import io.agora.rtm.internal.IRtmEventHandler;
import io.agora.rtm.internal.RequestInfo;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.concurrent.CopyOnWriteArraySet;

public class RtmClientImpl extends RtmClient {
  private static final String TAG = RtmClientImpl.class.getSimpleName();

  private static boolean sLibLoaded = false;
  static String nativeLibraryNameMixed = "agora-rtc-sdk"; // use mixed sdk(rtc+rtm)
  static String nativeLibraryNameIndependent = "agora-rtm-sdk"; // use rtm sdk only
  static String nativeLibraryPrefix = "lib";
  static String nativeLibrarySuffix = ".so";

  private long mNativeClient = 0;
  private RtmStorageImpl mRtmStorage;
  private RtmLockImpl mRtmLock;
  private RtmPresenceImpl mRtmPresence;
  private RtmEventHandler mRtmEventHandler;
  private CopyOnWriteArraySet mChannels =
      new CopyOnWriteArraySet();
  private CopyOnWriteArraySet mRtmEventListeners =
      new CopyOnWriteArraySet();

  // callback
  public final byte[] mRtmCallbackLock = new byte[0];
  private ResultCallback mLoginCallback;
  private HashMap> mPublishCallback =
      new HashMap>();
  private HashMap> mSubscribeCallback =
      new HashMap>();
  public HashMap> mJoinCallback =
      new HashMap>();
  public Deque> mLeaveCallback = new LinkedList>();
  public Deque> mJoinTopicCallback = new LinkedList>();
  public Deque> mLeaveTopicCallback = new LinkedList>();
  public Deque> mSubscribeTopicCallback =
      new LinkedList>();
  public HashMap> mModifyMetadataCallback =
      new HashMap>();
  public HashMap> mGetMetadataCallback =
      new HashMap>();
  public HashMap> mSubscribeUserMetadataCallback =
      new HashMap>();
  public HashMap> mModifyLockCallback =
      new HashMap>();
  public HashMap> mAcquireLockCallback =
      new HashMap>();
  public HashMap>> mGetLocksCallback =
      new HashMap>>();
  public HashMap> mWhoNowCallback =
      new HashMap>();
  public HashMap>> mWhereNowCallback =
      new HashMap>>();
  public HashMap> mGetOnlineUsersCallback =
      new HashMap>();
  public HashMap>> mGetUserChannelsCallback =
      new HashMap>>();
  public HashMap> mModifyStateCallback =
      new HashMap>();
  public HashMap> mGetStateCallback =
      new HashMap>();

  public static synchronized boolean initializeNativeLibs() {
    return initializeNativeLibs(null);
  }

  public static synchronized boolean initializeNativeLibs(String libPath) {
    if (!sLibLoaded) {
      sLibLoaded = loadLibrary(libPath, "agora-rtm-sdk");
      sLibLoaded = loadLibrary(libPath, "agora-rtm-sdk-jni");
    }
    return sLibLoaded;
  }

  private static void copyStream(InputStream input, OutputStream output) throws IOException {
    try (BufferedInputStream bufferedInput = new BufferedInputStream(input);
         BufferedOutputStream bufferedOutput = new BufferedOutputStream(output)) {
      byte[] buffer = new byte[1024];
      int bytesRead;
      while ((bytesRead = bufferedInput.read(buffer)) != -1) {
        bufferedOutput.write(buffer, 0, bytesRead);
      }

      bufferedOutput.flush();
    }
  }

  private static boolean loadLibrary(String path, String name) {
    try {
      String tmpPath = System.getProperty("java.io.tmpdir") + "/" + ((path == null) ? "rtm" : path);
      File outFileDir = new File(tmpPath);
      if (!outFileDir.exists()) {
        outFileDir.mkdirs();
      }
      String libFullName = nativeLibraryPrefix + name + nativeLibrarySuffix;
      File outFile = new File(tmpPath + "/" + libFullName);
      if (outFile.exists()) {
        outFile.delete();
      }
      outFile.createNewFile();

      InputStream input = RtmClientImpl.class.getResourceAsStream("/native/" + libFullName);
      OutputStream output = new FileOutputStream(outFile);
      copyStream(input, output);
      input.close();
      output.close();
      System.load(outFile.getAbsolutePath());
      return true;
    } catch (Exception e) {
      e.printStackTrace();
      throw new RuntimeException("failed to load library " + name + " from " + path, e);
    }
  }

  private static boolean safeLoadLibrary(String path, String name) {
    boolean loaded = true;
    try {
      if (path == null || path.length() == 0) {
        System.loadLibrary(name);
      } else {
        System.load(getNativeLibFullPath(path, name));
      }
    } catch (SecurityException e) {
      e.printStackTrace();
      loaded = false;
    } catch (UnsatisfiedLinkError e) {
      e.printStackTrace();
      loaded = false;
    } catch (NullPointerException e) {
      e.printStackTrace();
      loaded = false;
    } catch (Exception e) {
      e.printStackTrace();
      loaded = false;
    }
    if (!loaded) {
      // Logging.w(TAG, "failed to load library " + name + " from " + path);
    }
    return loaded;
  }

  static String getNativeLibFullPath(String path, String name) {
    String fullName = nativeLibraryPrefix + name + nativeLibrarySuffix;
    if (path == null || path.length() == 0) {
      return fullName;
    } else {
      return path.endsWith(File.separator) ? (path + fullName) : (path + File.separator + fullName);
    }
  }

  public void addChannel(StreamChannelImpl channel) {
    if (channel != null) {
      mChannels.add(channel);
    }
  }

  public void removeChannel(StreamChannelImpl channel) {
    if (channel != null) {
      mChannels.remove(channel);
    }
  }

  @Override
  protected synchronized RtmErrorCode initialize(RtmConfig config) {
    if (config == null) {
      throw new NullPointerException("eventListener is null");
    }
    if (mNativeClient != 0) {
      return RtmErrorCode.OK;
    }
    mNativeClient = nativeObjectInit();
    if (mNativeClient == 0) {
      throw new IllegalArgumentException("create native rtm client failed");
    }

    if (config.getEventListener() != null) {
      mRtmEventListeners.add(config.getEventListener());
    }
    mRtmEventHandler = new RtmEventHandler();
    int ret = nativeInitialize(mNativeClient, config, mRtmEventHandler);
    return RtmErrorCode.getEnum(ret);
  }

  @Override
  protected synchronized RtmErrorCode releaseClient() {
    if (mNativeClient != 0) {
      for (StreamChannelImpl channel : mChannels) {
        if (channel != null) {
          channel.release();
        }
      }
      nativeDestroy(mNativeClient);
      mNativeClient = 0;
    }
    mChannels.clear();
    return RtmErrorCode.OK;
  }

  @Override
  public synchronized void addEventListener(RtmEventListener listener) {
    if (listener == null) {
      // Logging.w(TAG, "added event listener is null");
      return;
    }
    mRtmEventListeners.add(listener);
  }

  @Override
  public synchronized void removeEventListener(RtmEventListener listener) {
    if (listener == null) {
      // Logging.w(TAG, "removed event listener is null");
      return;
    }
    mRtmEventListeners.remove(listener);
  }

  @Override
  public synchronized RtmStorage getStorage() {
    if (mNativeClient == 0) {
      return null;
    }

    if (mRtmStorage == null) {
      long handle = nativeGetStorage(mNativeClient);
      if (handle == 0) {
        return null;
      }
      mRtmStorage = new RtmStorageImpl(handle, this);
    }
    return mRtmStorage;
  }

  @Override
  public synchronized RtmLock getLock() {
    if (mNativeClient == 0) {
      return null;
    }

    if (mRtmLock == null) {
      long handle = nativeGetLock(mNativeClient);
      if (handle == 0) {
        return null;
      }
      mRtmLock = new RtmLockImpl(handle, this);
    }
    return mRtmLock;
  }

  @Override
  public synchronized RtmPresence getPresence() {
    if (mNativeClient == 0) {
      return null;
    }

    if (mRtmPresence == null) {
      long handle = nativeGetPresence(mNativeClient);
      if (handle == 0) {
        return null;
      }
      mRtmPresence = new RtmPresenceImpl(handle, this);
    }
    return mRtmPresence;
  }

  @Override
  public synchronized void login(String token, ResultCallback resultCallback) {
    if (mNativeClient == 0) {
      processFailureCallback(
          resultCallback, RtmErrorCode.INSTANCE_ALREADY_RELEASED, RtmConstants.LOGIN_API_STR);
      return;
    }

    synchronized (mRtmCallbackLock) {
      int ret = nativeLogin(mNativeClient, token);
      RtmErrorCode errorCode = RtmErrorCode.getEnum(ret);
      if (errorCode == RtmErrorCode.OK) {
        mLoginCallback = resultCallback;
      } else {
        processFailureCallback(resultCallback, errorCode, RtmConstants.LOGIN_API_STR);
      }
    }
  }

  @Override
  public synchronized void logout(ResultCallback resultCallback) {
    if (mNativeClient == 0) {
      processFailureCallback(
          resultCallback, RtmErrorCode.INSTANCE_ALREADY_RELEASED, RtmConstants.LOGOUT_API_STR);
      return;
    }

    int ret = nativeLogout(mNativeClient);
    processCallback(ret, resultCallback, RtmConstants.LOGOUT_API_STR);
  }

  @Override
  public synchronized void renewToken(String token, ResultCallback resultCallback) {
    if (mNativeClient == 0) {
      processFailureCallback(
          resultCallback, RtmErrorCode.INSTANCE_ALREADY_RELEASED, RtmConstants.RENEW_TOKEN_API_STR);
      return;
    }

    int ret = nativeRenewToken(mNativeClient, token);
    processCallback(ret, resultCallback, RtmConstants.RENEW_TOKEN_API_STR);
  }

  @Override
  public synchronized void publish(String channelName, String message, PublishOptions options,
      ResultCallback resultCallback) {
    if (mNativeClient == 0) {
      processFailureCallback(
          resultCallback, RtmErrorCode.INSTANCE_ALREADY_RELEASED, RtmConstants.PUBLISH_API_STR);
      return;
    }

    if (options == null) {
      options = new PublishOptions();
    }
    RequestInfo requestInfo = new RequestInfo();
    int ret = nativePublishStringMessage(mNativeClient, channelName, message, options, requestInfo);
    RtmErrorCode errorCode = RtmErrorCode.getEnum(ret);
    if (errorCode == RtmErrorCode.OK) {
      mPublishCallback.put(requestInfo.requestId, resultCallback);
    } else {
      processFailureCallback(resultCallback, errorCode, RtmConstants.PUBLISH_API_STR);
    }
  }

  @Override
  public synchronized void publish(String channelName, byte[] message, PublishOptions options,
      ResultCallback resultCallback) {
    if (mNativeClient == 0) {
      processFailureCallback(
          resultCallback, RtmErrorCode.INSTANCE_ALREADY_RELEASED, RtmConstants.PUBLISH_API_STR);
      return;
    }

    if (options == null) {
      options = new PublishOptions();
    }
    RequestInfo requestInfo = new RequestInfo();
    int ret = nativePublishBinaryMessage(mNativeClient, channelName, message, options, requestInfo);
    RtmErrorCode errorCode = RtmErrorCode.getEnum(ret);
    if (errorCode == RtmErrorCode.OK) {
      mPublishCallback.put(requestInfo.requestId, resultCallback);
    } else {
      processFailureCallback(resultCallback, errorCode, RtmConstants.PUBLISH_API_STR);
    }
  }

  @Override
  public synchronized void subscribe(
      String channelName, SubscribeOptions options, ResultCallback resultCallback) {
    if (mNativeClient == 0) {
      processFailureCallback(
          resultCallback, RtmErrorCode.INSTANCE_ALREADY_RELEASED, RtmConstants.SUBSCRIBE_API_STR);
      return;
    }

    if (options == null) {
      options = new SubscribeOptions();
    }

    synchronized (mRtmCallbackLock) {
      RequestInfo requestInfo = new RequestInfo();
      int ret = nativeSubscribe(mNativeClient, channelName, options, requestInfo);
      RtmErrorCode errorCode = RtmErrorCode.getEnum(ret);
      if (errorCode == RtmErrorCode.OK) {
        mSubscribeCallback.put(requestInfo.requestId, resultCallback);
      } else {
        processFailureCallback(resultCallback, errorCode, RtmConstants.SUBSCRIBE_API_STR);
      }
    }
  }

  @Override
  public synchronized void unsubscribe(String channelName, ResultCallback resultCallback) {
    if (mNativeClient == 0) {
      processFailureCallback(
          resultCallback, RtmErrorCode.INSTANCE_ALREADY_RELEASED, RtmConstants.UNSUBSCRIBE_API_STR);
      return;
    }
    int ret = nativeUnsubscribe(mNativeClient, channelName);
    processCallback(ret, resultCallback, RtmConstants.UNSUBSCRIBE_API_STR);
  }

  @Override
  public synchronized RtmErrorCode setParameters(String parameters) {
    if (mNativeClient == 0) {
      return RtmErrorCode.INSTANCE_ALREADY_RELEASED;
    }
    int ret = nativeSetParameters(mNativeClient, parameters);
    return RtmErrorCode.getEnum(ret);
  }

  @Override
  public synchronized StreamChannel createStreamChannel(String channelName) {
    if (mNativeClient == 0) {
      throw new NullPointerException("native client is null");
    }

    if (channelName == null) {
      throw new IllegalArgumentException("invalid channel name");
    }

    for (StreamChannelImpl channel : mChannels) {
      if (channel != null && channel.getChannelName().equals(channelName)) {
        return channel;
      }
    }

    long handle = nativeCreateStreamChannel(mNativeClient, channelName);
    if (handle == 0) {
      throw new IllegalArgumentException("create native stream channel instance failed");
    }
    StreamChannelImpl channel = new StreamChannelImpl(handle);
    mChannels.add(channel);
    channel.attach(this);
    return channel;
  }

  @Override
  public synchronized String getVersion() {
    if (mNativeClient == 0) {
      return "";
    }
    return nativeGetVersion(mNativeClient);
  }

  @Override
  public String getErrorReason(RtmErrorCode errorCode) {
    return getErrorReason(RtmErrorCode.getValue(errorCode));
  }

  public String getErrorReason(int errorCode) {
    if (mNativeClient == 0) {
      return "";
    }
    return nativeGetErrorReason(mNativeClient, errorCode);
  }

  public void processCallback(int code, ResultCallback callback, String methodName) {
    if (callback == null) {
      return;
    }
    RtmErrorCode errorCode = RtmErrorCode.getEnum(code);
    if (errorCode == RtmErrorCode.OK) {
      callback.onSuccess(null);
    } else {
      callback.onFailure(new ErrorInfo(errorCode, getErrorReason(errorCode), methodName));
    }
  }

  public void processFailureCallback(
      ResultCallback callback, RtmErrorCode errorCode, String methodName) {
    if (callback == null) {
      return;
    }
    callback.onFailure(new ErrorInfo(errorCode, getErrorReason(errorCode), methodName));
  }

  private class RtmEventHandler implements IRtmEventHandler {
    @Override
    public void onMessageEvent(MessageEvent event) {
      // Logging.d(TAG, "onMessageEvent");
      for (RtmEventListener listener : mRtmEventListeners) {
        listener.onMessageEvent(event);
      }
    }

    @Override
    public void onPresenceEvent(PresenceEvent event) {
      // Logging.d(TAG, "onPresenceEvent");
      for (RtmEventListener listener : mRtmEventListeners) {
        listener.onPresenceEvent(event);
      }
    }

    @Override
    public void onTopicEvent(TopicEvent event) {
      // Logging.d(TAG, "onTopicEvent");
      for (RtmEventListener listener : mRtmEventListeners) {
        listener.onTopicEvent(event);
      }
    }

    @Override
    public void onLockEvent(LockEvent event) {
      // Logging.d(TAG, "onLockEvent");
      for (RtmEventListener listener : mRtmEventListeners) {
        listener.onLockEvent(event);
      }
    }

    @Override
    public void onStorageEvent(StorageEvent event) {
      // Logging.d(TAG, "onStorageEvent");
      for (RtmEventListener listener : mRtmEventListeners) {
        listener.onStorageEvent(event);
      }
    }

    @Override
    public void onConnectionStateChanged(String channelName, int state, int reason) {
      for (RtmEventListener listener : mRtmEventListeners) {
        listener.onConnectionStateChanged(channelName, RtmConnectionState.getEnum(state),
            RtmConnectionChangeReason.getEnum(reason));
      }
    }

    @Override
    public void onTokenPrivilegeWillExpire(String channelName) {
      for (RtmEventListener listener : mRtmEventListeners) {
        listener.onTokenPrivilegeWillExpire(channelName);
      }
    }

    @Override
    public void onJoinResult(long requestId, int errorCode) {
      // Logging.d(TAG, "onJoinResult, requestId " + requestId + ", errorCode " + errorCode);
      synchronized (mRtmCallbackLock) {
        if (!mJoinCallback.containsKey(requestId)) {
          return;
        }
        processCallback(mJoinCallback.get(requestId), errorCode, RtmConstants.JOIN_API_STR);
        mJoinCallback.remove(requestId);
      }
    }

    @Override
    public void onLeaveResult(long requestId, int errorCode) {
      // Logging.d(TAG, "onLeaveResult, requestId " + requestId + ", errorCode " + errorCode);
      synchronized (mRtmCallbackLock) {
        if (mLeaveCallback.size() == 0) {
          return;
        }
        processCallback(mLeaveCallback.pollFirst(), errorCode, RtmConstants.LEAVE_API_STR);
      }
    }

    @Override
    public void onJoinTopicResult(long requestId, int errorCode) {
      // Logging.d(TAG, "onJoinTopicResult, requestId " + requestId + ", errorCode " + errorCode);
      synchronized (mRtmCallbackLock) {
        if (mJoinTopicCallback.size() == 0) {
          return;
        }
        processCallback(mJoinTopicCallback.pollFirst(), errorCode, RtmConstants.JOIN_TOPIC_API_STR);
      }
    }

    @Override
    public void onLeaveTopicResult(long requestId, int errorCode) {
      // Logging.d(TAG, "onLeaveTopicResult, requestId " + requestId + ", errorCode " + errorCode);
      synchronized (mRtmCallbackLock) {
        if (mLeaveTopicCallback.size() == 0) {
          return;
        }
        processCallback(
            mLeaveTopicCallback.pollFirst(), errorCode, RtmConstants.LEAVE_TOPIC_API_STR);
      }
    }

    @Override
    public void onSubscribeTopicResult(
        long requestId, String[] succeedUsers, String[] failedUsers, int errorCode) {
      // Logging.d(TAG, "onSubscribeTopicResult, requestId " + requestId + ", errorCode " +
      // errorCode);
      if (mSubscribeTopicCallback.size() == 0) {
        return;
      }

      synchronized (mRtmCallbackLock) {
        ResultCallback pendingCallback = mSubscribeTopicCallback.pollFirst();
        if (pendingCallback == null) {
          return;
        }
        if (errorCode == 0) {
          SubscribeTopicResult res =
              new SubscribeTopicResult(new ArrayList(Arrays.asList(succeedUsers)),
                  new ArrayList(Arrays.asList(failedUsers)));
          pendingCallback.onSuccess(res);
        } else {
          pendingCallback.onFailure(new ErrorInfo(RtmErrorCode.getEnum(errorCode),
              getErrorReason(errorCode), RtmConstants.SUBSCRIBE_TOPIC_API_STR));
        }
      }
    }

    @Override
    public void onSubscribeResult(long requestId, int errorCode) {
      // Logging.d(TAG, "onSubscribeResult, requestId " + requestId + ", errorCode " + errorCode);
      synchronized (mRtmCallbackLock) {
        if (!mSubscribeCallback.containsKey(requestId)) {
          // Logging.d(TAG, "onSubscribeResult, no callback");
          return;
        }
        processCallback(
            mSubscribeCallback.get(requestId), errorCode, RtmConstants.SUBSCRIBE_API_STR);
        mSubscribeCallback.remove(requestId);
      }
    }

    @Override
    public void onPublishResult(long requestId, int errorCode) {
      // Logging.d(TAG, "onPublishResult, requestId " + requestId + ", errorCode " + errorCode);
      synchronized (mRtmCallbackLock) {
        if (!mPublishCallback.containsKey(requestId)) {
          return;
        }
        processCallback(mPublishCallback.get(requestId), errorCode, RtmConstants.PUBLISH_API_STR);
        mPublishCallback.remove(requestId);
      }
    }

    @Override
    public void onLoginResult(int errorCode) {
      // Logging.d(TAG, "onLoginResult, errorCode " + errorCode);
      synchronized (mRtmCallbackLock) {
        if (mLoginCallback == null) {
          return;
        }
        if (errorCode == 0) {
          mLoginCallback.onSuccess(null);
        } else {
          mLoginCallback.onFailure(new ErrorInfo(RtmErrorCode.getEnum(errorCode),
              getErrorReason(errorCode), RtmConstants.LOGIN_API_STR));
        }
      }
    }

    @Override
    public void onSetChannelMetadataResult(long requestId, int errorCode) {
      // Logging.d(
      //     TAG, "onSetChannelMetadataResult, requestId " + requestId + ", errorCode " +
      //     errorCode);
      onModifyMetadataResult(requestId, errorCode, RtmConstants.SET_CHANNEL_METADATA_API_STR);
    }

    @Override
    public void onUpdateChannelMetadataResult(long requestId, int errorCode) {
      // Logging.d(TAG,
      //     "onUpdateChannelMetadataResult, requestId " + requestId + ", errorCode " + errorCode);
      onModifyMetadataResult(requestId, errorCode, RtmConstants.UPDATE_CHANNEL_METADATA_API_STR);
    }

    @Override
    public void onRemoveChannelMetadataResult(long requestId, int errorCode) {
      // Logging.d(TAG,
      //     "onRemoveChannelMetadataResult, requestId " + requestId + ", errorCode " + errorCode);
      onModifyMetadataResult(requestId, errorCode, RtmConstants.REMOVE_CHANNEL_METADATA_API_STR);
    }

    @Override
    public void onGetChannelMetadataResult(long requestId, long data, int errorCode) {
      // Logging.d(
      //     TAG, "onGetChannelMetadataResult, requestId " + requestId + ", errorCode " +
      //     errorCode);
      onGetMetadataResult(requestId, data, errorCode, RtmConstants.GET_CHANNEL_METADATA_API_STR);
    }

    @Override
    public void onSetUserMetadataResult(long requestId, int errorCode) {
      // Logging.d(
      //     TAG, "onSetUserMetadataResult, requestId " + requestId + ", errorCode " + errorCode);
      onModifyMetadataResult(requestId, errorCode, RtmConstants.SET_USER_METADATA_API_STR);
    }

    @Override
    public void onUpdateUserMetadataResult(long requestId, int errorCode) {
      // Logging.d(
      //     TAG, "onUpdateUserMetadataResult, requestId " + requestId + ", errorCode " +
      //     errorCode);
      onModifyMetadataResult(requestId, errorCode, RtmConstants.UPDATE_USER_METADATA_API_STR);
    }

    @Override
    public void onRemoveUserMetadataResult(long requestId, int errorCode) {
      // Logging.d(
      //     TAG, "onRemoveUserMetadataResult, requestId " + requestId + ", errorCode " +
      //     errorCode);
      onModifyMetadataResult(requestId, errorCode, RtmConstants.REMOVE_USER_METADATA_API_STR);
    }

    @Override
    public void onGetUserMetadataResult(long requestId, long data, int errorCode) {
      // Logging.d(
      //     TAG, "onGetUserMetadataResult, requestId " + requestId + ", errorCode " + errorCode);
      onGetMetadataResult(requestId, data, errorCode, RtmConstants.GET_USER_METADATA_API_STR);
    }

    @Override
    public void onSubscribeUserMetadataResult(long requestId, int errorCode) {
      // Logging.d(TAG,
      //     "onSubscribeUserMetadataResult, requestId " + requestId + ", errorCode " + errorCode);

      synchronized (mRtmCallbackLock) {
        if (!mSubscribeUserMetadataCallback.containsKey(requestId)) {
          return;
        }
        processCallback(mSubscribeUserMetadataCallback.get(requestId), errorCode,
            RtmConstants.SUBSCRIBE_USER_METADATA_API_STR);
        mSubscribeUserMetadataCallback.remove(requestId);
      }
    }

    @Override
    public void onSetLockResult(long requestId, int errorCode) {
      // Logging.d(TAG, "onSetLockResult, requestId " + requestId + ", errorCode " + errorCode);
      onModifyLockResult(requestId, errorCode, RtmConstants.SET_LOCK_API_STR);
    }

    @Override
    public void onRemoveLockResult(long requestId, int errorCode) {
      // Logging.d(TAG, "onRemoveLockResult, requestId " + requestId + ", errorCode " + errorCode);
      onModifyLockResult(requestId, errorCode, RtmConstants.REMOVE_LOCK_API_STR);
    }

    @Override
    public void onReleaseLockResult(long requestId, int errorCode) {
      // Logging.d(TAG, "onReleaseLockResult, requestId " + requestId + ", errorCode " + errorCode);
      onModifyLockResult(requestId, errorCode, RtmConstants.RELEASE_LOCK_API_STR);
    }

    @Override
    public void onAcquireLockResult(long requestId, String errorDetails, int errorCode) {
      // Logging.d(TAG, "onAcquireLockResult, requestId " + requestId + ", errorCode " + errorCode);

      synchronized (mRtmCallbackLock) {
        if (!mAcquireLockCallback.containsKey(requestId)) {
          return;
        }
        ResultCallback pendingCallback = mAcquireLockCallback.get(requestId);
        mAcquireLockCallback.remove(requestId);
        if (pendingCallback == null) {
          return;
        }
        if (errorCode == 0) {
          pendingCallback.onSuccess(null);
        } else {
          pendingCallback.onFailure(new ErrorInfo(RtmErrorCode.getEnum(errorCode),
              getErrorReason(errorCode), RtmConstants.ACQUIRE_LOCK_API_STR));
        }
      }
    }

    @Override
    public void onRevokeLockResult(long requestId, int errorCode) {
      // Logging.d(TAG, "onRevokeLockResult, requestId " + requestId + ", errorCode " + errorCode);
      onModifyLockResult(requestId, errorCode, RtmConstants.REVOKE_LOCK_API_STR);
    }

    @Override
    public void onGetLocksResult(long requestId, LockDetail[] lockDetailList, int errorCode) {
      // Logging.d(TAG, "onGetLocksResult, requestId " + requestId + ", errorCode " + errorCode);

      synchronized (mRtmCallbackLock) {
        if (!mGetLocksCallback.containsKey(requestId)) {
          return;
        }
        ResultCallback> pendingCallback = mGetLocksCallback.get(requestId);
        mGetLocksCallback.remove(requestId);
        if (pendingCallback == null) {
          return;
        }
        if (errorCode == 0) {
          pendingCallback.onSuccess(new ArrayList(Arrays.asList(lockDetailList)));
        } else {
          pendingCallback.onFailure(new ErrorInfo(RtmErrorCode.getEnum(errorCode),
              getErrorReason(errorCode), RtmConstants.GET_LOCKS_API_STR));
        }
      }
    }

    @Override
    public void onWhoNowResult(
        long requestId, UserState[] userStateList, long userCount, String nextPage, int errorCode) {
      // Logging.d(TAG, "whoNowResult, requestId " + requestId + ", errorCode " + errorCode);
      synchronized (mRtmCallbackLock) {
        if (!mWhoNowCallback.containsKey(requestId)) {
          // Logging.d(TAG, "mWhoNowCallback, no callback");
          return;
        }
        ResultCallback pendingCallback = mWhoNowCallback.get(requestId);
        mWhoNowCallback.remove(requestId);
        if (pendingCallback == null) {
          return;
        }
        if (errorCode == 0) {
          WhoNowResult res = new WhoNowResult(
              nextPage, new ArrayList(Arrays.asList(userStateList)), (int) userCount);
          pendingCallback.onSuccess(res);
        } else {
          pendingCallback.onFailure(new ErrorInfo(RtmErrorCode.getEnum(errorCode),
              getErrorReason(errorCode), RtmConstants.WHO_NOW_API_STR));
        }
      }
    }

    @Override
    public void onWhereNowResult(
        long requestId, ChannelInfo[] channels, long channelCount, int errorCode) {
      // Logging.d(TAG, "whereNowResult, requestId " + requestId + ", errorCode " + errorCode);

      synchronized (mRtmCallbackLock) {
        if (!mWhereNowCallback.containsKey(requestId)) {
          // Logging.d(TAG, "onWhereNowResult, no callback");
          return;
        }
        ResultCallback> pendingCallback = mWhereNowCallback.get(requestId);
        mWhereNowCallback.remove(requestId);
        if (pendingCallback == null) {
          return;
        }
        if (errorCode == 0) {
          pendingCallback.onSuccess(new ArrayList(Arrays.asList(channels)));
        } else {
          pendingCallback.onFailure(new ErrorInfo(RtmErrorCode.getEnum(errorCode),
              getErrorReason(errorCode), RtmConstants.WHERE_NOW_API_STR));
        }
      }
    }

    @Override
    public void onGetOnlineUsersResult(
        long requestId, UserState[] userStateList, long userCount, String nextPage, int errorCode) {
      // Logging.d(TAG, "onGetOnlineUsersResult, requestId " + requestId + ", errorCode " +
      // errorCode);
      synchronized (mRtmCallbackLock) {
        if (!mGetOnlineUsersCallback.containsKey(requestId)) {
          // Logging.d(TAG, "mGetOnlineUsersCallback, no callback");
          return;
        }
        ResultCallback pendingCallback =
            mGetOnlineUsersCallback.get(requestId);
        mGetOnlineUsersCallback.remove(requestId);
        if (pendingCallback == null) {
          return;
        }
        if (errorCode == 0) {
          GetOnlineUsersResult res = new GetOnlineUsersResult(
              nextPage, new ArrayList(Arrays.asList(userStateList)), (int) userCount);
          pendingCallback.onSuccess(res);
        } else {
          pendingCallback.onFailure(new ErrorInfo(RtmErrorCode.getEnum(errorCode),
              getErrorReason(errorCode), RtmConstants.GET_ONLINE_USERS_API_STR));
        }
      }
    }

    @Override
    public void onGetUserChannelsResult(
        long requestId, ChannelInfo[] channels, long channelCount, int errorCode) {
      // Logging.d(TAG, "GetUserChannelsResult, requestId " + requestId + ", errorCode " +
      // errorCode);

      synchronized (mRtmCallbackLock) {
        if (!mGetUserChannelsCallback.containsKey(requestId)) {
          return;
        }
        ResultCallback> pendingCallback =
            mGetUserChannelsCallback.get(requestId);
        mGetUserChannelsCallback.remove(requestId);
        if (pendingCallback == null) {
          return;
        }
        if (errorCode == 0) {
          pendingCallback.onSuccess(new ArrayList(Arrays.asList(channels)));
        } else {
          pendingCallback.onFailure(new ErrorInfo(RtmErrorCode.getEnum(errorCode),
              getErrorReason(errorCode), RtmConstants.GET_USER_CHANNELS_API_STR));
        }
      }
    }

    @Override
    public void onPresenceSetStateResult(long requestId, int errorCode) {
      // Logging.d(
      //     TAG, "onPresenceSetStateResult, requestId " + requestId + ", errorCode " + errorCode);
      onModifyStateResult(requestId, errorCode, RtmConstants.SET_STATE_API_STR);
    }

    @Override
    public void onPresenceRemoveStateResult(long requestId, int errorCode) {
      // Logging.d(
      //     TAG, "onPresenceRemoveStateResult, requestId " + requestId + ", errorCode " +
      //     errorCode);
      onModifyStateResult(requestId, errorCode, RtmConstants.REMOVE_STATE_API_STR);
    }

    @Override
    public void onPresenceGetStateResult(long requestId, UserState state, int errorCode) {
      // Logging.d(
      //     TAG, "onPresenceGetStateResult, requestId " + requestId + ", errorCode " + errorCode);

      synchronized (mRtmCallbackLock) {
        if (!mGetStateCallback.containsKey(requestId)) {
          // Logging.d(TAG, "onPresenceGetStateResult, no callback");
          return;
        }
        ResultCallback pendingCallback = mGetStateCallback.get(requestId);
        mGetStateCallback.remove(requestId);
        if (pendingCallback == null) {
          return;
        }
        if (errorCode == 0) {
          pendingCallback.onSuccess(state);
        } else {
          pendingCallback.onFailure(new ErrorInfo(RtmErrorCode.getEnum(errorCode),
              getErrorReason(errorCode), RtmConstants.GET_STATE_API_STR));
        }
      }
    }

    private void onModifyMetadataResult(long requestId, int errorCode, String methodName) {
      synchronized (mRtmCallbackLock) {
        if (!mModifyMetadataCallback.containsKey(requestId)) {
          return;
        }
        processCallback(mModifyMetadataCallback.get(requestId), errorCode, methodName);
        mModifyMetadataCallback.remove(requestId);
      }
    }

    private void onGetMetadataResult(long requestId, long data, int errorCode, String methodName) {
      synchronized (mRtmCallbackLock) {
        if (!mGetMetadataCallback.containsKey(requestId)) {
          return;
        }
        ResultCallback pendingCallback = mGetMetadataCallback.get(requestId);
        mGetMetadataCallback.remove(requestId);
        if (pendingCallback == null) {
          return;
        }
        if (errorCode == 0) {
          Metadata metadata = new MetadataImpl(data);
          pendingCallback.onSuccess(metadata);
        } else {
          pendingCallback.onFailure(new ErrorInfo(
              RtmErrorCode.getEnum(errorCode), getErrorReason(errorCode), methodName));
        }
      }
    }

    private void onModifyLockResult(long requestId, int errorCode, String methodName) {
      synchronized (mRtmCallbackLock) {
        if (!mModifyLockCallback.containsKey(requestId)) {
          return;
        }
        processCallback(mModifyLockCallback.get(requestId), errorCode, methodName);
        mModifyLockCallback.remove(requestId);
      }
    }

    private void onModifyStateResult(long requestId, int errorCode, String methodName) {
      // Logging.d(TAG, "onModifyStateResult, requestId " + requestId + ", errorCode " + errorCode);
      synchronized (mRtmCallbackLock) {
        if (!mModifyStateCallback.containsKey(requestId)) {
          // Logging.d(TAG, "onModifyStateResult, no callback");
          return;
        }
        processCallback(mModifyStateCallback.get(requestId), errorCode, methodName);
        mModifyStateCallback.remove(requestId);
      }
    }

    private void processCallback(ResultCallback callback, int errorCode, String methodName) {
      if (callback == null) {
        return;
      }
      if (errorCode == 0) {
        callback.onSuccess(null);
      } else {
        callback.onFailure(
            new ErrorInfo(RtmErrorCode.getEnum(errorCode), getErrorReason(errorCode), methodName));
      }
    }
  }

  private native long nativeObjectInit();

  private static native int nativeDestroy(long handle);

  private native int nativeInitialize(
      long nativeRtmClientAndroid, RtmConfig config, Object nativeRtmEventHandler);

  private native long nativeCreateStreamChannel(long nativeRtmClientAndroid, String channelName);

  private native long nativeGetStorage(long nativeRtmClientAndroid);

  private native long nativeGetLock(long nativeRtmClientAndroid);

  private native long nativeGetPresence(long nativeRtmClientAndroid);

  private native int nativeLogin(long nativeRtmClientAndroid, String token);

  private native int nativeLogout(long nativeRtmClientAndroid);

  private native int nativeRenewToken(long nativeRtmClientAndroid, String token);

  private native int nativePublishStringMessage(long nativeRtmClientAndroid, String channelName,
      String message, PublishOptions options, RequestInfo requestInfo);

  private native int nativePublishBinaryMessage(long nativeRtmClientAndroid, String channelName,
      byte[] message, PublishOptions options, RequestInfo requestInfo);

  private native int nativeSubscribe(long nativeRtmClientAndroid, String channelName,
      SubscribeOptions options, RequestInfo requestInfo);

  private native int nativeUnsubscribe(long nativeRtmClientAndroid, String channelName);

  private native int nativeSetParameters(long nativeRtmClientAndroid, String parameters);

  private native String nativeGetErrorReason(long nativeRtmClientAndroid, int errorCode);

  private native String nativeGetVersion(long nativeRtmClientAndroid);
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy