mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Download files through RN packager connection
Differential Revision: D4650999 fbshipit-source-id: 298e3e65bfc13a3610a588c9bffb4808fb2135e3
This commit is contained in:
committed by
Facebook Github Bot
parent
af590b0c74
commit
373eb61f1f
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.packagerconnection;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Base64;
|
||||
|
||||
import com.facebook.common.logging.FLog;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class FileIoHandler implements Runnable {
|
||||
private static final String TAG = JSPackagerClient.class.getSimpleName();
|
||||
private static final long FILE_TTL = 30 * 1000;
|
||||
|
||||
private static class TtlFileInputStream {
|
||||
private final FileInputStream mStream;
|
||||
private long mTtl;
|
||||
|
||||
public TtlFileInputStream(String path) throws FileNotFoundException {
|
||||
mStream = new FileInputStream(path);
|
||||
mTtl = System.currentTimeMillis() + FILE_TTL;
|
||||
}
|
||||
|
||||
private void extendTtl() {
|
||||
mTtl = System.currentTimeMillis() + FILE_TTL;
|
||||
}
|
||||
|
||||
public boolean expiredTtl() {
|
||||
return System.currentTimeMillis() >= mTtl;
|
||||
}
|
||||
|
||||
public String read(int size) throws IOException {
|
||||
extendTtl();
|
||||
byte[] buffer = new byte[size];
|
||||
int bytesRead = mStream.read(buffer);
|
||||
return Base64.encodeToString(buffer, 0, bytesRead, Base64.DEFAULT);
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
mStream.close();
|
||||
}
|
||||
};
|
||||
|
||||
private int mNextHandle;
|
||||
private final Handler mHandler;
|
||||
private final Map<Integer, TtlFileInputStream> mOpenFiles;
|
||||
private final Map<String, JSPackagerClient.RequestHandler> mRequestHandlers;
|
||||
|
||||
public FileIoHandler() {
|
||||
mNextHandle = 1;
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
mOpenFiles = new HashMap<>();
|
||||
mRequestHandlers = new HashMap<>();
|
||||
mRequestHandlers.put("fopen", new JSPackagerClient.RequestOnlyHandler() {
|
||||
@Override
|
||||
public void onRequest(
|
||||
@Nullable Object params, JSPackagerClient.Responder responder) {
|
||||
synchronized (mOpenFiles) {
|
||||
try {
|
||||
JSONObject paramsObj = (JSONObject)params;
|
||||
if (paramsObj == null) {
|
||||
throw new Exception("params must be an object { mode: string, filename: string }");
|
||||
}
|
||||
String mode = paramsObj.optString("mode");
|
||||
if (mode == null) {
|
||||
throw new Exception("missing params.mode");
|
||||
}
|
||||
String filename = paramsObj.optString("filename");
|
||||
if (filename == null) {
|
||||
throw new Exception("missing params.filename");
|
||||
}
|
||||
if (!mode.equals("r")) {
|
||||
throw new IllegalArgumentException("unsupported mode: " + mode);
|
||||
}
|
||||
|
||||
responder.respond(addOpenFile(filename));
|
||||
} catch (Exception e) {
|
||||
responder.error(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
mRequestHandlers.put("fclose", new JSPackagerClient.RequestOnlyHandler() {
|
||||
@Override
|
||||
public void onRequest(
|
||||
@Nullable Object params, JSPackagerClient.Responder responder) {
|
||||
synchronized (mOpenFiles) {
|
||||
try {
|
||||
if (!(params instanceof Number)) {
|
||||
throw new Exception("params must be a file handle");
|
||||
}
|
||||
TtlFileInputStream stream = mOpenFiles.get((int)params);
|
||||
if (stream == null) {
|
||||
throw new Exception("invalid file handle, it might have timed out");
|
||||
}
|
||||
|
||||
mOpenFiles.remove((int)params);
|
||||
stream.close();
|
||||
responder.respond("");
|
||||
} catch (Exception e) {
|
||||
responder.error(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
mRequestHandlers.put("fread", new JSPackagerClient.RequestOnlyHandler() {
|
||||
@Override
|
||||
public void onRequest(
|
||||
@Nullable Object params, JSPackagerClient.Responder responder) {
|
||||
synchronized (mOpenFiles) {
|
||||
try {
|
||||
JSONObject paramsObj = (JSONObject)params;
|
||||
if (paramsObj == null) {
|
||||
throw new Exception("params must be an object { file: handle, size: number }");
|
||||
}
|
||||
int file = paramsObj.optInt("file");
|
||||
if (file == 0) {
|
||||
throw new Exception("invalid or missing file handle");
|
||||
}
|
||||
int size = paramsObj.optInt("size");
|
||||
if (size == 0) {
|
||||
throw new Exception("invalid or missing read size");
|
||||
}
|
||||
TtlFileInputStream stream = mOpenFiles.get(file);
|
||||
if (stream == null) {
|
||||
throw new Exception("invalid file handle, it might have timed out");
|
||||
}
|
||||
|
||||
responder.respond(stream.read(size));
|
||||
} catch (Exception e) {
|
||||
responder.error(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Map<String, JSPackagerClient.RequestHandler> handlers() {
|
||||
return mRequestHandlers;
|
||||
}
|
||||
|
||||
private int addOpenFile(String filename) throws FileNotFoundException {
|
||||
int handle = mNextHandle++;
|
||||
mOpenFiles.put(handle, new TtlFileInputStream(filename));
|
||||
if (mOpenFiles.size() == 1) {
|
||||
mHandler.postDelayed(FileIoHandler.this, FILE_TTL);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// clean up files that are past their expiry date
|
||||
synchronized (mOpenFiles) {
|
||||
Iterator<TtlFileInputStream> i = mOpenFiles.values().iterator();
|
||||
while (i.hasNext()) {
|
||||
TtlFileInputStream stream = i.next();
|
||||
if (stream.expiredTtl()) {
|
||||
i.remove();
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException e) {
|
||||
FLog.e(
|
||||
TAG,
|
||||
"closing expired file failed: " + e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!mOpenFiles.isEmpty()) {
|
||||
mHandler.postDelayed(this, FILE_TTL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user