Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

receiveFile refactor #82

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -360,14 +360,25 @@ _Note_: you cannot send character encoding for string and by default this librar

Same function as above but you can specify the address (a peer address in the same group as this device is).

### receiveFile(folder, fileName, forceToScanGallery)
### receiveFile(folder, fileName, forceToScanGallery, extraParams)

If you expect, that someone may send you a file - you can call this method in order to receive it.

If you want to save file with the same name as it's on client device, then before sending file you can `sendMessage` about its `fileName`.

`forceToScanGallery` is an optional parameter, which indicate whether should we scan and detect new files or not in order to show them in Gallery app. By default it's `false`.

`extraParams` is an optional parameter (object) with extra arguments. Current arguments are:

* **meta**: Metadata. If true, the message received is not a string, but an object:

```json
{
"file": "<file absolute path (string)>",
"fromAddress": "IP address of the sender"
}
```

_Note:_ if you expect file to be received you should request permissions for writing to the storage:

```javascript
Expand Down Expand Up @@ -411,6 +422,25 @@ receiveMessage()
.then(message => console.log(`Received message: ${message}`))
```

`receiveMessage` accepts an optional parameter object with extra arguments. Current arguments are:

* **meta**: Metadata. If true, the message received is not a string, but an object:

```json
{
"message": "<message sent by sendMessage/sendMessageTo (string)>",
"fromAddress": "IP address of the sender"
}
```

**Usage example:**

```javascript
receiveMessage({meta: true}).then(({fromAddress, message}) => {
console.log(`Received message (from IP ${fromAddress}): ${message}`)
})
```

### stopReceivingMessage()

If you didn't receive the message from receiveMessage() as expected, stopReceivingMessage() closes the listening port. If the port is already closed, this method does nothing.
Expand Down
96 changes: 96 additions & 0 deletions android/src/main/java/io/wifi/p2p/FileServer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package io.wifi.p2p;

import static io.wifi.p2p.Utils.copyBytes;

import android.os.Bundle;
import android.util.Log;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
* Created by kiryl on 18.7.18. Refactor by viniciuscb on 20.03.23
*
* <p>A simple server socket that accepts connection and writes some data on the stream.
*/
public class FileServer {
private static final String TAG = "RNWiFiP2P";
private final Executor executor;
private volatile ServerSocket serverSocket;

public FileServer() {
this.executor = Executors.newSingleThreadExecutor();
}

public void start(
String destination,
ReadableMap extraProps,
CustomDefinedCallback customDefinedCallback,
Callback callback) {
executor.execute(
() -> {
try {
Boolean returnMeta = false;
serverSocket = new ServerSocket(8988);
Log.i(TAG, "Server: Socket opened to receive file");

if (extraProps != null) {
Bundle bundle = Arguments.toBundle(extraProps);
returnMeta = bundle.getBoolean("meta");
}

Socket client = serverSocket.accept();
String clientAddress = client.getInetAddress().getHostAddress();
Log.i(TAG, "Server: connection done (receiveFile)");

final File f = new File(destination);
File dirs = new File(f.getParent());
if (!dirs.exists()) dirs.mkdirs();
f.createNewFile();
Log.i(TAG, "Server: copying files " + f.toString());
InputStream inputstream = client.getInputStream();
copyBytes(inputstream, new FileOutputStream(f));

client.close();

String result = f.getAbsolutePath();

Log.i(TAG, "File copied - " + result);

if (returnMeta) {
WritableMap map = Arguments.createMap();
map.putString("file", result);
map.putString("fromAddress", clientAddress);
callback.invoke(map);
} else {
callback.invoke(result);
}
customDefinedCallback.invoke(null);

this.stop();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
});
}

public void stop() {
if (serverSocket != null) {
try {
serverSocket.close();
Log.i(TAG, "Server: Socket closed to receive file");
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
}
}
}
83 changes: 0 additions & 83 deletions android/src/main/java/io/wifi/p2p/FileServerAsyncTask.java

This file was deleted.

6 changes: 3 additions & 3 deletions android/src/main/java/io/wifi/p2p/MessageServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void start(ReadableMap props, Callback callback) {
try {
Boolean returnMeta = false;
serverSocket = new ServerSocket(8988);
Log.i(TAG, "Server: Socket opened");
Log.i(TAG, "Server: Socket opened to receive message");

if (props != null) {
Bundle bundle = Arguments.toBundle(props);
Expand All @@ -45,7 +45,7 @@ public void start(ReadableMap props, Callback callback) {

Socket client = serverSocket.accept();
String clientAddress = client.getInetAddress().getHostAddress();
Log.i(TAG, "Server: connection done");
Log.i(TAG, "Server: connection done (receiveMessage)");

InputStream inputstream = client.getInputStream();
String message = convertStreamToString(inputstream);
Expand All @@ -71,7 +71,7 @@ public void stop() {
if (serverSocket != null) {
try {
serverSocket.close();
Log.i(TAG, "Server: Socket closed");
Log.i(TAG, "Server: Socket closed to receive message");
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
Expand Down
68 changes: 40 additions & 28 deletions android/src/main/java/io/wifi/p2p/WiFiP2PManagerModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public class WiFiP2PManagerModule extends ReactContextBaseJavaModule
private static final String TAG = "RNWiFiP2P";
private WiFiP2PDeviceMapper mapper = new WiFiP2PDeviceMapper();
private MessageServer messageServer;
private FileServer fileServer;

public WiFiP2PManagerModule(ReactApplicationContext reactContext) {
super(reactContext);
Expand Down Expand Up @@ -291,49 +292,60 @@ protected void onReceiveResult(int resultCode, Bundle resultData) {

@ReactMethod
public void receiveFile(
String folder, String fileName, final Boolean forceToScanGallery, final Callback callback) {
String folder,
String fileName,
final Boolean forceToScanGallery,
final ReadableMap extraProps,
final Callback callback) {
final String destination = folder + fileName;
manager.requestConnectionInfo(
channel,
new WifiP2pManager.ConnectionInfoListener() {
@Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
if (info.groupFormed) {
new FileServerAsyncTask(
getCurrentActivity(),
callback,
destination,
new CustomDefinedCallback() {
@Override
public void invoke(Object object) {
if (forceToScanGallery) { // fixes:
// https://github.com/kirillzyusko/react-native-wifi-p2p/issues/31
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
final Intent scanIntent =
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
final File file = new File(destination);
final Uri contentUri = Uri.fromFile(file);
scanIntent.setData(contentUri);
reactContext.sendBroadcast(scanIntent);
} else {
final Intent intent =
new Intent(
Intent.ACTION_MEDIA_MOUNTED,
Uri.parse(
"file://" + Environment.getExternalStorageDirectory()));
reactContext.sendBroadcast(intent);
}
}
if (fileServer == null) {
fileServer = new FileServer();
}
CustomDefinedCallback customDefinedCallback =
new CustomDefinedCallback() {
@Override
public void invoke(Object object) {
if (forceToScanGallery) { // fixes:
// https://github.com/kirillzyusko/react-native-wifi-p2p/issues/31
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
final Intent scanIntent =
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
final File file = new File(destination);
final Uri contentUri = Uri.fromFile(file);
scanIntent.setData(contentUri);
reactContext.sendBroadcast(scanIntent);
} else {
final Intent intent =
new Intent(
Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://" + Environment.getExternalStorageDirectory()));
reactContext.sendBroadcast(intent);
}
})
.execute();
}
}
};

fileServer.start(destination, extraProps, customDefinedCallback, callback);
} else {
Log.i(TAG, "You must be in a group to receive a file");
}
}
});
}

@ReactMethod
public void stopReceivingFile() {
if (fileServer != null) {
fileServer.stop();
}
}

@ReactMethod
public void sendMessage(String message, final Promise promise) {
if (wifiP2pInfo.groupOwnerAddress != null) {
Expand Down
9 changes: 6 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,19 @@ const sendFile = (pathToFile) => WiFiP2PManager.sendFile(pathToFile);

const sendFileTo = (pathToFile, address) => WiFiP2PManager.sendFileTo(pathToFile, address);

const receiveFile = (folder, fileName, forceToScanGallery = false) => new Promise((resolve, reject) => {
WiFiP2PManager.receiveFile(folder, fileName, forceToScanGallery, (pathToFile) => {
const receiveFile = (folder, fileName, forceToScanGallery = false, extraProps = {}) => new Promise((resolve, reject) => {
WiFiP2PManager.receiveFile(folder, fileName, forceToScanGallery, extraProps, (pathToFile) => {
resolve(pathToFile);
});
});

const stopReceivingFile = () => WiFiP2PManager.stopReceivingFile()

const sendMessage = (message) => WiFiP2PManager.sendMessage(message);

const sendMessageTo = (message, address) => WiFiP2PManager.sendMessageTo(message, address);

const receiveMessage = (props) => new Promise((resolve, reject) => {
const receiveMessage = (props = {}) => new Promise((resolve, reject) => {
WiFiP2PManager.receiveMessage(props, (message) => {
resolve(message);
});
Expand Down Expand Up @@ -137,6 +139,7 @@ export {
sendFile,
sendFileTo,
receiveFile,
stopReceivingFile,
sendMessage,
sendMessageTo,
receiveMessage,
Expand Down