mirror of
https://github.com/status-im/react-native-udp.git
synced 2025-02-16 10:46:37 +00:00
simplified the android code
UdpSocketClient holds onto the only DatagramSocket/MulticastSocket reference. UdpSocketClient throws IlllegalStateException if send/addMembership are called on unbound sockets. UdpReceiverTask takes it's values as a Pair parameter to execute on.
This commit is contained in:
parent
398935bb67
commit
79d6f346b6
@ -5,59 +5,44 @@
|
|||||||
* Created by Andy Prock on 9/24/15.
|
* Created by Andy Prock on 9/24/15.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.tradle.react;
|
package com.tradle.react;
|
||||||
|
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.ref.WeakReference;
|
import java.net.DatagramPacket;
|
||||||
import java.net.DatagramPacket;
|
import java.net.DatagramSocket;
|
||||||
import java.net.DatagramSocket;
|
import java.net.InetAddress;
|
||||||
import java.net.InetAddress;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a specialized AsyncTask that receives data from a socket in the background, and
|
* This is a specialized AsyncTask that receives data from a socket in the background, and
|
||||||
* notifies it's listener when data is received. This is not threadsafe, the listener
|
* notifies it's listener when data is received. This is not threadsafe, the listener
|
||||||
* should handle synchronicity.
|
* should handle synchronicity.
|
||||||
*/
|
*/
|
||||||
public class UdpReceiverTask extends AsyncTask<Void, Void, Void> {
|
public class UdpReceiverTask extends AsyncTask<Pair<DatagramSocket, UdpReceiverTask.OnDataReceivedListener>, Void, Void> {
|
||||||
private static final String TAG = "UdpReceiverTask";
|
private static final String TAG = "UdpReceiverTask";
|
||||||
private static final int MAX_UDP_DATAGRAM_LEN = 1024;
|
private static final int MAX_UDP_DATAGRAM_LEN = 1024;
|
||||||
|
|
||||||
private DatagramSocket mSocket;
|
|
||||||
private WeakReference<OnDataReceivedListener> mReceiverListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An {@link AsyncTask} that blocks to receive data from a socket.
|
|
||||||
* Received data is sent via the {@link OnDataReceivedListener}
|
|
||||||
*/
|
|
||||||
public UdpReceiverTask(DatagramSocket socket, UdpReceiverTask.OnDataReceivedListener
|
|
||||||
receiverListener) {
|
|
||||||
this.mSocket = socket;
|
|
||||||
this.mReceiverListener = new WeakReference<>(receiverListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the UdpReceiverTask's DatagramChannel.
|
|
||||||
*/
|
|
||||||
public DatagramSocket getSocket() {
|
|
||||||
return mSocket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An infinite loop to block and read data from the socket.
|
* An infinite loop to block and read data from the socket.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... a) {
|
protected Void doInBackground(Pair<DatagramSocket, UdpReceiverTask.OnDataReceivedListener>... params) {
|
||||||
OnDataReceivedListener receiverListener = mReceiverListener.get();
|
if (params.length > 1) {
|
||||||
|
throw new IllegalArgumentException("This task is only for a single socket/listener pair.");
|
||||||
|
}
|
||||||
|
|
||||||
|
DatagramSocket socket = params[0].first;
|
||||||
|
OnDataReceivedListener receiverListener = params[0].second;
|
||||||
|
|
||||||
final byte[] buffer = new byte[MAX_UDP_DATAGRAM_LEN];
|
final byte[] buffer = new byte[MAX_UDP_DATAGRAM_LEN];
|
||||||
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
|
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
|
||||||
|
|
||||||
while (!isCancelled()) {
|
while (!isCancelled()) {
|
||||||
try {
|
try {
|
||||||
mSocket.receive(packet);
|
socket.receive(packet);
|
||||||
|
|
||||||
final InetAddress address = packet.getAddress();
|
final InetAddress address = packet.getAddress();
|
||||||
final String base64Data = Base64.encodeToString(packet.getData(), packet.getOffset(),
|
final String base64Data = Base64.encodeToString(packet.getData(), packet.getOffset(),
|
||||||
@ -79,14 +64,6 @@ public class UdpReceiverTask extends AsyncTask<Void, Void, Void> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Close if cancelled.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onCancelled() {
|
|
||||||
// mSocket.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener interface for receive events.
|
* Listener interface for receive events.
|
||||||
*/
|
*/
|
||||||
|
@ -10,6 +10,7 @@ package com.tradle.react;
|
|||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Callback;
|
import com.facebook.react.bridge.Callback;
|
||||||
|
|
||||||
@ -47,11 +48,11 @@ public final class UdpSocketClient implements UdpReceiverTask.OnDataReceivedList
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks to see if client is receiving multicast packets.
|
* Checks to see if client part of a multi-cast group.
|
||||||
* @return boolean true if receiving multicast packets, else false.
|
* @return boolean true IF the socket is part of a multi-cast group.
|
||||||
*/
|
*/
|
||||||
public boolean isMulticast() {
|
public boolean isMulticast() {
|
||||||
return (mReceiverTask != null && mReceiverTask.getSocket() instanceof MulticastSocket);
|
return (mSocket != null && mSocket instanceof MulticastSocket);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,7 +70,7 @@ public final class UdpSocketClient implements UdpReceiverTask.OnDataReceivedList
|
|||||||
public void bind(Integer port, @Nullable String address) throws IOException {
|
public void bind(Integer port, @Nullable String address) throws IOException {
|
||||||
mSocket = new DatagramSocket(null);
|
mSocket = new DatagramSocket(null);
|
||||||
|
|
||||||
mReceiverTask = new UdpReceiverTask(mSocket, this);
|
mReceiverTask = new UdpReceiverTask();
|
||||||
|
|
||||||
SocketAddress socketAddress;
|
SocketAddress socketAddress;
|
||||||
if (address != null) {
|
if (address != null) {
|
||||||
@ -82,7 +83,8 @@ public final class UdpSocketClient implements UdpReceiverTask.OnDataReceivedList
|
|||||||
mSocket.bind(socketAddress);
|
mSocket.bind(socketAddress);
|
||||||
|
|
||||||
// begin listening for data in the background
|
// begin listening for data in the background
|
||||||
mReceiverTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
mReceiverTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
|
||||||
|
new Pair<DatagramSocket, UdpReceiverTask.OnDataReceivedListener>(mSocket, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,18 +94,30 @@ public final class UdpSocketClient implements UdpReceiverTask.OnDataReceivedList
|
|||||||
* @param address the multicast group to join
|
* @param address the multicast group to join
|
||||||
* @throws UnknownHostException
|
* @throws UnknownHostException
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
|
* @throws IllegalStateException if socket is not bound.
|
||||||
*/
|
*/
|
||||||
public void addMembership(String address) throws UnknownHostException, IOException {
|
public void addMembership(String address) throws UnknownHostException, IOException, IllegalStateException {
|
||||||
final int port = mReceiverTask.getSocket().getLocalPort();
|
if (null == mSocket || !mSocket.isBound()) {
|
||||||
|
throw new IllegalStateException("Socket is not bound.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(mSocket instanceof MulticastSocket)) {
|
||||||
|
// cancel the current receiver task
|
||||||
|
if (mReceiverTask != null) {
|
||||||
mReceiverTask.cancel(true);
|
mReceiverTask.cancel(true);
|
||||||
|
}
|
||||||
|
|
||||||
final MulticastSocket socket = new MulticastSocket(port);
|
// tear down the DatagramSocket, and rebuild as a MulticastSocket
|
||||||
socket.joinGroup(InetAddress.getByName(address));
|
final int port = mSocket.getLocalPort();
|
||||||
|
mSocket.close();
|
||||||
mReceiverTask = new UdpReceiverTask(socket, this);
|
mSocket = new MulticastSocket(port);
|
||||||
|
|
||||||
// begin listening for data in the background
|
// begin listening for data in the background
|
||||||
mReceiverTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
mReceiverTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
|
||||||
|
new Pair<DatagramSocket, UdpReceiverTask.OnDataReceivedListener>(mSocket, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
((MulticastSocket) mSocket).joinGroup(InetAddress.getByName(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,13 +128,8 @@ public final class UdpSocketClient implements UdpReceiverTask.OnDataReceivedList
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public void dropMembership(String address) throws UnknownHostException, IOException {
|
public void dropMembership(String address) throws UnknownHostException, IOException {
|
||||||
if (mReceiverTask != null && mReceiverTask.getSocket() instanceof MulticastSocket) {
|
if (mSocket instanceof MulticastSocket) {
|
||||||
if (!mReceiverTask.isCancelled()) {
|
((MulticastSocket) mSocket).leaveGroup(InetAddress.getByName(address));
|
||||||
mReceiverTask.cancel(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
final MulticastSocket socket = (MulticastSocket) mReceiverTask.getSocket();
|
|
||||||
socket.leaveGroup(InetAddress.getByName(address));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,10 +142,12 @@ public final class UdpSocketClient implements UdpReceiverTask.OnDataReceivedList
|
|||||||
* @param callback callback for results
|
* @param callback callback for results
|
||||||
* @throws UnknownHostException
|
* @throws UnknownHostException
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
|
* @throws IllegalStateException if socket is not bound.
|
||||||
*/
|
*/
|
||||||
public void send(String base64String, Integer port, String address, @Nullable Callback callback) throws UnknownHostException, IOException {
|
public void send(String base64String, Integer port, String address, @Nullable Callback callback)
|
||||||
|
throws UnknownHostException, IllegalStateException, IOException {
|
||||||
if (null == mSocket || !mSocket.isBound()) {
|
if (null == mSocket || !mSocket.isBound()) {
|
||||||
return;
|
throw new IllegalStateException("Socket is not bound.");
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] data = Base64.decode(base64String, Base64.NO_WRAP);
|
byte[] data = Base64.decode(base64String, Base64.NO_WRAP);
|
||||||
@ -159,11 +170,8 @@ public final class UdpSocketClient implements UdpReceiverTask.OnDataReceivedList
|
|||||||
* Sets the socket to enable broadcasts.
|
* Sets the socket to enable broadcasts.
|
||||||
*/
|
*/
|
||||||
public void setBroadcast(boolean flag) throws SocketException {
|
public void setBroadcast(boolean flag) throws SocketException {
|
||||||
if (mReceiverTask != null) {
|
if (mSocket != null) {
|
||||||
DatagramSocket socket = mReceiverTask.getSocket();
|
mSocket.setBroadcast(flag);
|
||||||
if (socket != null) {
|
|
||||||
socket.setBroadcast(flag);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,13 +180,11 @@ public final class UdpSocketClient implements UdpReceiverTask.OnDataReceivedList
|
|||||||
*/
|
*/
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (mReceiverTask != null && !mReceiverTask.isCancelled()) {
|
if (mReceiverTask != null && !mReceiverTask.isCancelled()) {
|
||||||
// stop the receiving task, and close the channel
|
// stop the receiving task
|
||||||
mReceiverTask.cancel(true);
|
mReceiverTask.cancel(true);
|
||||||
if (!mReceiverTask.getSocket().isClosed()) {
|
|
||||||
mReceiverTask.getSocket().close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// close the socket
|
||||||
if (mSocket != null && !mSocket.isClosed()) {
|
if (mSocket != null && !mSocket.isClosed()) {
|
||||||
mSocket.close();
|
mSocket.close();
|
||||||
mSocket = null;
|
mSocket = null;
|
||||||
|
@ -5,29 +5,29 @@
|
|||||||
* Created by Andy Prock on 9/24/15.
|
* Created by Andy Prock on 9/24/15.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.tradle.react;
|
package com.tradle.react;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
|
||||||
import com.facebook.common.logging.FLog;
|
import com.facebook.common.logging.FLog;
|
||||||
import com.facebook.react.bridge.Arguments;
|
import com.facebook.react.bridge.Arguments;
|
||||||
import com.facebook.react.bridge.Callback;
|
import com.facebook.react.bridge.Callback;
|
||||||
import com.facebook.react.bridge.GuardedAsyncTask;
|
import com.facebook.react.bridge.GuardedAsyncTask;
|
||||||
import com.facebook.react.bridge.ReactApplicationContext;
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
import com.facebook.react.bridge.ReactContext;
|
import com.facebook.react.bridge.ReactContext;
|
||||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||||
import com.facebook.react.bridge.ReactMethod;
|
import com.facebook.react.bridge.ReactMethod;
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
import com.facebook.react.bridge.WritableMap;
|
import com.facebook.react.bridge.WritableMap;
|
||||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The NativeModule in charge of storing active {@link UdpSocketClient}s, and acting as an api layer.
|
* The NativeModule in charge of storing active {@link UdpSocketClient}s, and acting as an api layer.
|
||||||
@ -185,6 +185,12 @@ public final class UdpSockets extends ReactContextBaseJavaModule
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
client.addMembership(multicastAddress);
|
client.addMembership(multicastAddress);
|
||||||
|
} catch (IllegalStateException ise) {
|
||||||
|
// an exception occurred
|
||||||
|
FLog.e(TAG, "addMembership", ise);
|
||||||
|
} catch (UnknownHostException uhe) {
|
||||||
|
// an exception occurred
|
||||||
|
FLog.e(TAG, "addMembership", uhe);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
// an exception occurred
|
// an exception occurred
|
||||||
FLog.e(TAG, "addMembership", ioe);
|
FLog.e(TAG, "addMembership", ioe);
|
||||||
@ -232,7 +238,9 @@ public final class UdpSockets extends ReactContextBaseJavaModule
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
client.send(base64String, port, address, callback);
|
client.send(base64String, port, address, callback);
|
||||||
} catch (UnknownHostException uhe) {
|
} catch (IllegalStateException ise) {
|
||||||
|
callback.invoke(UdpErrorUtil.getError(null, ise.getMessage()));
|
||||||
|
}catch (UnknownHostException uhe) {
|
||||||
callback.invoke(UdpErrorUtil.getError(null, uhe.getMessage()));
|
callback.invoke(UdpErrorUtil.getError(null, uhe.getMessage()));
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
// an exception occurred
|
// an exception occurred
|
||||||
|
Loading…
x
Reference in New Issue
Block a user