
io.callstats.sdk.CallStats Maven / Gradle / Ivy
package io.callstats.sdk;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import io.callstats.sdk.data.BridgeStatusInfo;
import io.callstats.sdk.data.ConferenceInfo;
import io.callstats.sdk.data.ConferenceStats;
import io.callstats.sdk.data.ServerInfo;
import io.callstats.sdk.data.UserInfo;
import io.callstats.sdk.httpclient.CallStatsHttp2Client;
import io.callstats.sdk.internal.BridgeStatusInfoQueue;
import io.callstats.sdk.internal.CallStatsAuthenticator;
import io.callstats.sdk.internal.CallStatsBridgeKeepAliveManager;
import io.callstats.sdk.internal.CallStatsBridgeKeepAliveStatusListener;
import io.callstats.sdk.internal.CallStatsConfigProvider;
import io.callstats.sdk.internal.CallStatsConst;
import io.callstats.sdk.internal.CallStatsResponseStatus;
import io.callstats.sdk.internal.TokenGeneratorHs256;
import io.callstats.sdk.internal.listeners.CallStatsHttp2ResponseListener;
import io.callstats.sdk.listeners.CallStatsInitListener;
import io.callstats.sdk.listeners.CallStatsStartConferenceListener;
import io.callstats.sdk.messages.BridgeStatusUpdateMessage;
import io.callstats.sdk.messages.BridgeStatusUpdateResponse;
import io.callstats.sdk.messages.CallStatsEventResponse;
import io.callstats.sdk.messages.ConferenceSetupEvent;
import io.callstats.sdk.messages.ConferenceStatsEvent;
import okhttp3.Response;
/**
* The Class CallStats.
*
* @author Karthik Budigere
*/
public class CallStats {
/** The http client. */
private CallStatsHttp2Client httpClient;
/** The app id. */
private int appId;
/** The bridge id. */
private String bridgeId;
/** The listener. */
private CallStatsInitListener listener;
/** The authenticator. */
private CallStatsAuthenticator authenticator;
/** The logger. */
private static final Logger logger = LogManager.getLogger("CallStats");
/** The gson. */
private Gson gson;
/** The server info. */
private ServerInfo serverInfo;
/** The is initialized. */
private boolean isInitialized;
private BridgeStatusInfoQueue bridgeStatusInfoQueue;
private Map> conferenceStatsMap =
new HashMap>();
/** The bridge keep alive manager. */
private CallStatsBridgeKeepAliveManager bridgeKeepAliveManager;
private ICallStatsTokenGenerator tokenGenerator;
private CallStatsHttp2Client authHttpClient;
/**
* Checks if is initialized.
*
* @return true, if is initialized
*/
public boolean isInitialized() {
return isInitialized;
}
/**
* Sets the initialized.
*
* @param isInitialized the new initialized
*/
private void setInitialized(boolean isInitialized) {
this.isInitialized = isInitialized;
}
/**
* Instantiates a new callstats.
*/
public CallStats() {
gson = new Gson();
bridgeStatusInfoQueue = new BridgeStatusInfoQueue();
if (System.getProperty("callstats.configurationFile") != null) {
CallStatsConst.CallStatsJavaSDKPropertyFileName =
System.getProperty("callstats.configurationFile");
}
logger.info("config file path is " + System.getProperty("callstats.configurationFile") + ":"
+ CallStatsConst.CallStatsJavaSDKPropertyFileName);
CallStatsConst.CS_VERSION = getClass().getPackage().getImplementationVersion();
}
private String getToken() {
return authenticator.getToken();
}
/**
* Initialize callstats.
*
* @param appId the app id
* @param appSecret the app secret
* @param bridgeId the bridge id
* @param serverInfo the server info
* @param callStatsInitListener the call stats init listener
*/
public void initialize(final int appId, final String appSecret, final String bridgeId,
final ServerInfo serverInfo, final CallStatsInitListener callStatsInitListener) {
if (StringUtils.isBlank(appSecret)) {
logger.error("intialize: Arguments cannot be null ");
throw new IllegalArgumentException("intialize: Arguments cannot be null");
}
initialize(appId, new TokenGeneratorHs256(appSecret.toCharArray(), appId, bridgeId), bridgeId,
serverInfo, callStatsInitListener);
}
/**
* Initialize callstats.
*
* @param appId the app id
* @param tokenGenerator token generator
* @param bridgeId the bridge id
* @param serverInfo the server info
* @param callStatsInitListener the call stats init listener
*/
public void initialize(final int appId, ICallStatsTokenGenerator tokenGenerator,
final String bridgeId, final ServerInfo serverInfo,
final CallStatsInitListener callStatsInitListener) {
if (appId <= 0 || StringUtils.isBlank(bridgeId) || serverInfo == null
|| callStatsInitListener == null) {
logger.error("intialize: Arguments cannot be null ");
throw new IllegalArgumentException("intialize: Arguments cannot be null");
}
this.appId = appId;
this.tokenGenerator = tokenGenerator;
this.bridgeId = bridgeId;
this.listener = callStatsInitListener;
this.serverInfo = serverInfo;
CallStatsConfigProvider.init();
httpClient = new CallStatsHttp2Client(CallStatsConfigProvider.connectionTimeOut);
authHttpClient = new CallStatsHttp2Client(CallStatsConfigProvider.connectionTimeOut);
authenticator = new CallStatsAuthenticator(appId, this.tokenGenerator, bridgeId, authHttpClient,
new CallStatsInitListener() {
public void onInitialized(String msg) {
setInitialized(true);
logger.info("SDK Initialized " + msg);
startKeepAliveThread();
listener.onInitialized(msg);
}
public void onError(CallStatsErrors error, String errMsg) {
logger.info("SDK Initialization Failed " + errMsg);
listener.onError(error, errMsg);;
}
});
authenticator.doAuthentication();
}
/**
* Send call stats bridge status update.
*
* @param bridgeStatusInfo the bridge status info
*/
public void sendCallStatsBridgeStatusUpdate(BridgeStatusInfo bridgeStatusInfo) {
if (!isInitialized()) {
bridgeStatusInfoQueue.push(bridgeStatusInfo);
return;
}
long epoch = System.currentTimeMillis();
String token = getToken();
BridgeStatusUpdateMessage eventMessage =
new BridgeStatusUpdateMessage(bridgeId, epoch, bridgeStatusInfo);
String requestMessageString = gson.toJson(eventMessage);
String url = "/" + appId + "/stats/bridge/status";
httpClient.sendBridgeStatistics(url, token, requestMessageString,
new CallStatsHttp2ResponseListener() {
public void onResponse(Response response) {
int responseStatus = response.code();
BridgeStatusUpdateResponse eventResponseMessage;
try {
String responseString = response.body().string();
eventResponseMessage =
gson.fromJson(responseString, BridgeStatusUpdateResponse.class);
} catch (IOException e) {
logger.error("IO Exception " + e.getMessage(), e);
throw new RuntimeException(e);
} catch (JsonSyntaxException e) {
logger.error("Json Syntax Exception " + e.getMessage(), e);
e.printStackTrace();
throw new RuntimeException(e);
}
logger.debug("BridgeStatusUpdate Response " + eventResponseMessage.getStatus() + ":"
+ eventResponseMessage.getMsg());
httpClient.setDisrupted(false);
if (responseStatus == CallStatsResponseStatus.RESPONSE_STATUS_SUCCESS) {
sendCallStatsBridgeStatusUpdateFromQueue();
} else if (responseStatus == CallStatsResponseStatus.INVALID_AUTHENTICATION_TOKEN) {
bridgeKeepAliveManager.stopKeepAliveSender();
authenticator.doAuthentication();
} else {
httpClient.setDisrupted(true);
}
}
public void onFailure(Exception e) {
logger.error("Response exception" + e.getMessage(), e);
httpClient.setDisrupted(true);
}
});
}
private synchronized void sendCallStatsBridgeStatusUpdateFromQueue() {
if (bridgeStatusInfoQueue.getLength() < 1)
return;
while (bridgeStatusInfoQueue.getLength() > 0) {
BridgeStatusInfo bridgeStatusInfo = bridgeStatusInfoQueue.pop();
sendCallStatsBridgeStatusUpdate(bridgeStatusInfo);
}
}
public synchronized void sendCallStatsConferenceEvent(CallStatsConferenceEvents eventType,
ConferenceInfo conferenceInfo, final CallStatsStartConferenceListener listener) {
if (eventType == null || conferenceInfo == null || listener == null) {
logger.error("sendCallStatsConferenceEvent: Arguments cannot be null ");
throw new IllegalArgumentException("sendCallStatsConferenceEvent: Arguments cannot be null");
}
long apiTS = System.currentTimeMillis();
if (eventType == CallStatsConferenceEvents.CONFERENCE_SETUP) {
ConferenceSetupEvent eventMessage =
new ConferenceSetupEvent(bridgeId, conferenceInfo.getInitiatorID(), conferenceInfo.getInitiatorSiteID(), apiTS, serverInfo);
String requestMessageString = gson.toJson(eventMessage);
String url = "";
try {
url =
"/" + appId + "/conferences/" + URLEncoder.encode(conferenceInfo.getConfID(), "utf-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sendCallStatsConferenceEventMessage(url, requestMessageString, listener);
} else {
listener.onError(CallStatsErrors.CS_PROTO_ERROR, "Invaid Message type");
}
}
public synchronized void sendCallStatsConferenceEvent(CallStatsConferenceEvents eventType,
UserInfo userInfo) {
if (eventType == null || userInfo == null) {
logger.error("sendCallStatsConferenceEvent: Arguments cannot be null ");
throw new IllegalArgumentException("sendCallStatsConferenceEvent: Arguments cannot be null");
}
// long apiTS = System.currentTimeMillis();
// String token = getToken();
if (eventType == CallStatsConferenceEvents.AUDIO_MUTE
|| eventType == CallStatsConferenceEvents.AUDIO_UNMUTE
|| eventType == CallStatsConferenceEvents.VIDEO_PAUSE
|| eventType == CallStatsConferenceEvents.VIDEO_RESUME) {
// TODO send media action event
} else if (eventType == CallStatsConferenceEvents.USER_JOINED
|| eventType == CallStatsConferenceEvents.USER_LEFT) {
// TODO send user action event
} else if (eventType == CallStatsConferenceEvents.FABRIC_HOLD
|| eventType == CallStatsConferenceEvents.FABRIC_RESUME) {
// TODO send fabric action event
} else if (eventType == CallStatsConferenceEvents.CONFERENCE_SETUP_FAILED
|| eventType == CallStatsConferenceEvents.CONFERENCE_TERMINATED) {
// TODO send conference action event
}
// sendCallStatsConferenceEventMessage(userInfo.getConfID(), requestMessageString, null);
}
private synchronized void sendCallStatsConferenceEventMessage(String url, String reqMsg,
final CallStatsStartConferenceListener listener) {
String token = getToken();
if (token == null) {
logger.error("sendCallStatsConferenceEvent: Not Initialized/Token Unavaialble");
return;
}
httpClient.sendBridgeEvents(url, token, reqMsg, new CallStatsHttp2ResponseListener() {
public void onResponse(Response response) {
int responseStatus = response.code();
String responseString = "";
try {
responseString = response.body().string();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
logger.debug("received response " + responseString);
if (responseStatus == CallStatsResponseStatus.RESPONSE_STATUS_SUCCESS) {
CallStatsEventResponse eventResponseMessage;
try {
eventResponseMessage = gson.fromJson(responseString, CallStatsEventResponse.class);
} catch (JsonSyntaxException e) {
logger.error("Json Syntax Exception " + e.getMessage(), e);
e.printStackTrace();
throw new RuntimeException(e);
}
logger.debug("conference event Response status is " + eventResponseMessage.getStatus()
+ ":" + eventResponseMessage.getUcID());
if (listener != null) {
listener.onResponse(eventResponseMessage.getUcID());
}
httpClient.setDisrupted(false);
} else {
httpClient.setDisrupted(true);
}
}
public void onFailure(Exception e) {
logger.error("Response exception" + e.getMessage(), e);
httpClient.setDisrupted(true);
}
});
}
public synchronized void startStatsReportingForUser(String userID, String confID) {
if (userID == null || confID == null) {
logger.error("startStatsReportingForUser: Arguments cannot be null ");
throw new IllegalArgumentException("startStatsReportingForUser: Arguments cannot be null");
}
String key = userID + ":" + confID;
List tempStats = conferenceStatsMap.get(key);
if (tempStats == null) {
tempStats = new ArrayList();
conferenceStatsMap.put(key, tempStats);
}
}
public synchronized void stopStatsReportingForUser(String userID, String confID) {
if (userID == null || confID == null) {
logger.error("stopStatsReportingForUser: Arguments cannot be null ");
throw new IllegalArgumentException("stopStatsReportingForUser: Arguments cannot be null");
}
String key = userID + ":" + confID;
List tempStats = conferenceStatsMap.get(key);
long apiTS = System.currentTimeMillis();
if (tempStats != null && tempStats.size() > 0) {
ConferenceStats conferenceStats = tempStats.get(0);
ConferenceStatsEvent conferenceStatsEvent =
new ConferenceStatsEvent(bridgeId, conferenceStats.getRemoteUserID(),
conferenceStats.getLocalUserID(), conferenceStats.getConfID(), apiTS);
UserInfo info = new UserInfo(conferenceStats.getConfID(), conferenceStats.getRemoteUserID(),
conferenceStats.getUcID());
tempStats.forEach(new Consumer() {
public void accept(ConferenceStats stats) {
conferenceStatsEvent.addStats(stats);
}
});
String statsString = gson.toJson(conferenceStatsEvent);
logger.debug("Stats string -" + statsString);
sendCallStatsConferenceStats(statsString, info);
conferenceStatsMap.remove(key);
}
}
public synchronized void reportConferenceStats(String userID, ConferenceStats stats) {
if (stats == null || userID == null) {
logger.error("sendConferenceStats: Arguments cannot be null ");
throw new IllegalArgumentException("sendConferenceStats: Arguments cannot be null");
}
String key = userID + ":" + stats.getConfID();
List tempStats = conferenceStatsMap.get(key);
if (tempStats == null) {
// tempStats = new ArrayList();
throw new IllegalStateException(
"reportConferenceStats called without calling startStatsReportingForUser");
} else {
tempStats.add(stats);
conferenceStatsMap.put(key, tempStats);
}
}
private synchronized void startKeepAliveThread() {
if (bridgeKeepAliveManager == null) {
bridgeKeepAliveManager = new CallStatsBridgeKeepAliveManager(appId, bridgeId,
authenticator.getToken(), httpClient, new CallStatsBridgeKeepAliveStatusListener() {
public void onKeepAliveError(CallStatsErrors error, String errMsg) {
if (error == CallStatsErrors.AUTH_ERROR) {
authenticator.doAuthentication();
}
}
public void onSuccess() {
sendCallStatsBridgeStatusUpdateFromQueue();
}
});
}
bridgeKeepAliveManager.startKeepAliveSender(authenticator.getToken());
}
private synchronized void sendCallStatsConferenceStats(String stats, UserInfo userInfo) {
if (stats == null || userInfo == null) {
logger.error("sendCallStatsConferenceStats: Arguments cannot be null ");
throw new IllegalArgumentException("sendCallStatsConferenceStats: Arguments cannot be null");
}
if (userInfo.getUcID() == null) {
logger.error("sendCallStatsConferenceStats: UCID is null ");
throw new IllegalArgumentException("sendCallStatsConferenceStats: UCID is null");
}
String token = getToken();
if (token == null) {
logger.error("sendCallStatsConferenceStats: Not Initialized/Token Unavaialble");
return;
}
String url = "";
try {
url = "/" + appId + "/conferences/" + URLEncoder.encode(userInfo.getConfID(), "utf-8") + "/"
+ userInfo.getUcID() + "/stats";
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
httpClient.sendBridgeStats(url, token, stats, new CallStatsHttp2ResponseListener() {
public void onResponse(Response response) {
int responseStatus = response.code();
String responseString = "";
try {
responseString = response.body().string();
} catch (IOException e1) {
e1.printStackTrace();
}
logger.debug("sendBridgeStats : received response " + responseString);
if (responseStatus == CallStatsResponseStatus.RESPONSE_STATUS_SUCCESS) {
httpClient.setDisrupted(false);
} else {
httpClient.setDisrupted(true);
}
}
public void onFailure(Exception e) {
logger.error("Response exception" + e.getMessage(), e);
httpClient.setDisrupted(true);
}
});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy