package org.deviceconnect.android.deviceplugin.awsiot.udt;
import android.util.Log;
import com.barchart.udt.lib.AndroidLoaderUDT;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class P2PConnection {
static {
AndroidLoaderUDT.load();
}
private static final boolean DEBUG = false;
private static final String TAG = "UDT";
private ScheduledExecutorService mScheduler = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture<?> mTimeoutFuture;
private RelayClient mRelayClient;
private RelayServer mRelayServer;
private int mConnectionId;
private OnP2PConnectionListener mOnP2PConnectionListener;
public P2PConnection() {
this(generateConnectionId());
}
public P2PConnection(final int connectionId) {
mConnectionId = connectionId;
}
public static int generateConnectionId() {
return (int) UUID.randomUUID().getLeastSignificantBits();
}
public int getConnectionId() {
return mConnectionId;
}
public void setConnectionId(int connectionId) {
mConnectionId = connectionId;
}
public void setOnP2PConnectionListener(final OnP2PConnectionListener listener) {
mOnP2PConnectionListener = listener;
}
public void open() throws IOException {
if (DEBUG) {
Log.i(TAG, "P2PConnection#open:");
}
if (mRelayServer != null) {
throw new IOException("RelayServer is already exist.");
}
closeClient();
try {
startTimeoutTimer();
mRelayServer = new RelayServer();
mRelayServer.setOnRelayServerListener(mOnRelayServerListener);
mRelayServer.open();
} catch (IOException e) {
closeServer();
throw e;
}
}
public void connect(final String address, final int port) throws IOException {
if (DEBUG) {
Log.i(TAG, "P2PConnection#connect:" + address + ":" + port);
}
if (mRelayClient != null) {
throw new IOException("RelayClient is already exist.");
}
closeServer();
try {
mRelayClient = new RelayClient();
mRelayClient.setOnRelayClientListener(mOnRelayClientListener);
mRelayClient.connect(address, port);
} catch (IOException e) {
closeClient();
throw e;
}
}
public void sendData(final byte[] data) throws IOException {
if (mRelayClient != null) {
mRelayClient.sendData(data);
}
if (mRelayServer != null) {
mRelayServer.sendData(data);
}
}
public void sendData(final byte[] data, final int length) throws IOException {
if (mRelayClient != null) {
mRelayClient.sendData(data, length);
}
if (mRelayServer != null) {
mRelayServer.sendData(data, length);
}
}
public void sendData(final byte[] data, final int offset, final int length) throws IOException {
if (mRelayClient != null) {
mRelayClient.sendData(data, offset, length);
}
if (mRelayServer != null) {
mRelayServer.sendData(data, offset, length);
}
}
public void close() throws IOException {
if (DEBUG) {
Log.i(TAG, "P2PConnection#close");
}
closeClient();
closeServer();
cancelTimeoutTimer();
mOnP2PConnectionListener = null;
}
private void startTimeoutTimer() {
if (mTimeoutFuture != null) {
cancelTimeoutTimer();
}
mTimeoutFuture = mScheduler.schedule(new Runnable() {
@Override
public void run() {
if (DEBUG) {
Log.w(TAG, "P2PConnection Timeout. connectionId=" + mConnectionId);
}
if (mOnP2PConnectionListener != null) {
mOnP2PConnectionListener.onTimeout();
}
try {
close();
} catch (IOException e) {
e.printStackTrace();
}
}
}, 30, TimeUnit.SECONDS);
}
private void cancelTimeoutTimer() {
if (mTimeoutFuture != null) {
mTimeoutFuture.cancel(true);
}
}
private void closeClient() throws IOException {
if (mRelayClient != null) {
mRelayClient.close();
mRelayClient = null;
}
}
private void closeServer() throws IOException {
if (mRelayServer != null) {
mRelayServer.close();
mRelayServer = null;
}
}
private final RelayClient.OnRelayClientListener mOnRelayClientListener = new RelayClient.OnRelayClientListener() {
@Override
public void onConnected(final String address, final int port) {
if (DEBUG) {
Log.i(TAG, "P2PConnection#onConnected: " + address + " " + port);
}
cancelTimeoutTimer();
if (mOnP2PConnectionListener != null) {
mOnP2PConnectionListener.onConnected(address, port);
}
}
@Override
public void onReceivedData(final byte[] data, final String address, final int port) {
if (mOnP2PConnectionListener != null) {
mOnP2PConnectionListener.onReceivedData(data, address, port);
}
}
@Override
public void onDisconnected(final String address, final int port) {
if (mOnP2PConnectionListener != null) {
mOnP2PConnectionListener.onDisconnected(address, port);
}
}
};
private final RelayServer.OnRelayServerListener mOnRelayServerListener = new RelayServer.OnRelayServerListener() {
@Override
public void onRetrievedAddress(final String address, final int port) {
if (DEBUG) {
Log.i(TAG, "P2PConnection#onRetrievedAddress: " + address + " " + port);
}
if (mOnP2PConnectionListener != null) {
mOnP2PConnectionListener.onRetrievedAddress(address, port);
}
}
@Override
public void onConnected(final String address, final int port) {
if (DEBUG) {
Log.i(TAG, "P2PConnection#onConnected: " + address + " " + port);
}
cancelTimeoutTimer();
if (mOnP2PConnectionListener != null) {
mOnP2PConnectionListener.onConnected(address, port);
}
}
@Override
public void onReceivedData(final byte[] data, final String address, final int port) {
if (mOnP2PConnectionListener != null) {
mOnP2PConnectionListener.onReceivedData(data, address, port);
}
}
@Override
public void onDisconnected(final String address, final int port) {
if (mOnP2PConnectionListener != null) {
mOnP2PConnectionListener.onDisconnected(address, port);
}
}
};
public interface OnP2PConnectionListener {
void onRetrievedAddress(final String address, final int port);
void onConnected(String address, int port);
void onReceivedData(byte[] data, String address, int port);
void onDisconnected(String address, int port);
void onTimeout();
}
}