react-native-blob-util 0.21.3 → 0.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NuGet.config +11 -0
- package/package.json +65 -52
- package/windows/ExperimentalFeatures.props +33 -0
- package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.cpp +1426 -1290
- package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.h +200 -206
- package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.rc +0 -0
- package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.vcxproj +41 -82
- package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.vcxproj.filters +32 -20
- package/windows/ReactNativeBlobUtil/ReactPackageProvider.cpp +8 -3
- package/windows/ReactNativeBlobUtil/ReactPackageProvider.h +7 -3
- package/windows/ReactNativeBlobUtil/ReactPackageProvider.idl +7 -7
- package/windows/ReactNativeBlobUtil/codegen/.clang-format +2 -0
- package/windows/ReactNativeBlobUtil/codegen/NativeBlobUtilsDataTypes.g.h +42 -0
- package/windows/ReactNativeBlobUtil/codegen/NativeBlobUtilsSpec.g.h +353 -0
- package/windows/ReactNativeBlobUtil/packages.lock.json +60 -0
- package/windows/ReactNativeBlobUtil/pch.cpp +1 -1
- package/windows/ReactNativeBlobUtil/pch.h +30 -4
- package/windows/ReactNativeBlobUtil/resource.h +5 -0
- package/windows/ReactNativeBlobUtil/targetver.h +8 -0
- package/windows/ReactNativeBlobUtil.sln +43 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include "pch.h"
|
|
2
|
+
|
|
2
3
|
#include "ReactNativeBlobUtil.h"
|
|
3
4
|
#include <winrt/Windows.ApplicationModel.Activation.h>
|
|
4
5
|
#include <winrt/Windows.Security.Cryptography.h>
|
|
@@ -9,6 +10,7 @@
|
|
|
9
10
|
#include <winrt/Windows.Web.Http.h>
|
|
10
11
|
#include <winrt/Windows.Web.Http.Headers.h>
|
|
11
12
|
#include <winrt/windows.web.http.filters.h>
|
|
13
|
+
#include <winrt/Windows.System.Threading.h>
|
|
12
14
|
#include <filesystem>
|
|
13
15
|
#include <sstream>
|
|
14
16
|
|
|
@@ -108,1406 +110,1554 @@ void TaskCancellationManager::Cancel(TaskId taskId) noexcept
|
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
ReactNativeBlobUtilConfig::ReactNativeBlobUtilConfig(
|
|
112
|
-
if (options["appendExt"].IsNull() == true)
|
|
113
|
-
{
|
|
114
|
-
appendExt = "";
|
|
115
|
-
}
|
|
116
|
-
else
|
|
117
|
-
{
|
|
118
|
-
appendExt = options["appendExt"].AsString();
|
|
119
|
-
}
|
|
120
|
-
fileCache = options["fileCache"].AsBoolean();
|
|
121
|
-
followRedirect = options["followRedirect"].AsBoolean();
|
|
122
|
-
overwrite = options["overwrite"].AsBoolean();
|
|
123
|
-
if (options["path"].IsNull() == true)
|
|
124
|
-
{
|
|
125
|
-
path = "";
|
|
126
|
-
}
|
|
127
|
-
else
|
|
128
|
-
{
|
|
129
|
-
auto filepath{ options["path"].AsString() };
|
|
130
|
-
auto fileLength{ filepath.length() };
|
|
131
|
-
bool hasTrailingSlash{ filepath[fileLength - 1] == '\\' || filepath[fileLength - 1] == '/' };
|
|
132
|
-
std::filesystem::path pathToParse{ hasTrailingSlash ? filepath.substr(0, fileLength - 1) : filepath };
|
|
133
|
-
pathToParse.make_preferred();
|
|
134
|
-
path = pathToParse.string();
|
|
135
|
-
}
|
|
136
|
-
trusty = options["trusty"].AsBoolean();
|
|
137
|
-
|
|
138
|
-
int64_t potentialTimeout{ options["timeout"].AsInt64() };
|
|
139
|
-
timeout = std::chrono::seconds{ potentialTimeout > 0 ? potentialTimeout : 60000 };
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
ReactNativeBlobUtilProgressConfig::ReactNativeBlobUtilProgressConfig(int32_t count_, int32_t interval_) : count(count_), interval(interval_) {
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
void ReactNativeBlobUtil::Initialize(winrt::Microsoft::ReactNative::ReactContext const& reactContext) noexcept
|
|
113
|
+
ReactNativeBlobUtilConfig::ReactNativeBlobUtilConfig(::React::JSValue& options)
|
|
147
114
|
{
|
|
148
|
-
|
|
115
|
+
auto getStringOrDefault = [](const winrt::Microsoft::ReactNative::JSValue& value, const std::string& defaultValue = "") -> std::string {
|
|
116
|
+
return value.IsNull() ? defaultValue : value.AsString();
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
auto getBoolOrDefault = [](const winrt::Microsoft::ReactNative::JSValue& value, bool defaultValue = false) -> bool {
|
|
120
|
+
return value.IsNull() ? defaultValue : value.AsBoolean();
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
auto getInt64OrDefault = [](const winrt::Microsoft::ReactNative::JSValue& value, int64_t defaultValue = 60000) -> int64_t {
|
|
124
|
+
return value.IsNull() ? defaultValue : value.AsInt64();
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
appendExt = getStringOrDefault(options["appendExt"]);
|
|
128
|
+
fileCache = getBoolOrDefault(options["fileCache"]);
|
|
129
|
+
followRedirect = getBoolOrDefault(options["followRedirect"]);
|
|
130
|
+
overwrite = getBoolOrDefault(options["overwrite"]);
|
|
131
|
+
trusty = getBoolOrDefault(options["trusty"]);
|
|
132
|
+
|
|
133
|
+
// Handle path sanitization
|
|
134
|
+
{
|
|
135
|
+
std::string filepath = getStringOrDefault(options["path"]);
|
|
136
|
+
if (!filepath.empty())
|
|
137
|
+
{
|
|
138
|
+
size_t fileLength = filepath.length();
|
|
139
|
+
bool hasTrailingSlash = filepath[fileLength - 1] == '\\' || filepath[fileLength - 1] == '/';
|
|
140
|
+
std::filesystem::path pathToParse = hasTrailingSlash ? filepath.substr(0, fileLength - 1) : filepath;
|
|
141
|
+
pathToParse.make_preferred();
|
|
142
|
+
path = pathToParse.string();
|
|
143
|
+
}
|
|
144
|
+
else
|
|
145
|
+
{
|
|
146
|
+
path = "";
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Timeout handling
|
|
151
|
+
int64_t potentialTimeout = getInt64OrDefault(options["timeout"]);
|
|
152
|
+
timeout = std::chrono::seconds{ potentialTimeout > 0 ? potentialTimeout : 60000 };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
ReactNativeBlobUtilProgressConfig::ReactNativeBlobUtilProgressConfig(double count_, double interval_) : count(count_), interval(interval_) {
|
|
149
156
|
}
|
|
150
157
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
void ReactNativeBlobUtil::ConstantsViaConstantsProvider(winrt::Microsoft::ReactNative::ReactConstantProvider& constants) noexcept
|
|
155
|
-
{
|
|
156
|
-
// ReactNativeBlobUtil.DocumentDir
|
|
157
|
-
constants.Add(L"DocumentDir", to_string(ApplicationData::Current().LocalFolder().Path()));
|
|
158
|
-
|
|
159
|
-
// ReactNativeBlobUtil.CacheDir
|
|
160
|
-
constants.Add(L"CacheDir", to_string(ApplicationData::Current().LocalCacheFolder().Path()));
|
|
161
|
-
|
|
162
|
-
// ReactNativeBlobUtil.PictureDir
|
|
163
|
-
constants.Add(L"PictureDir", UserDataPaths::GetDefault().Pictures());
|
|
164
|
-
|
|
165
|
-
// ReactNativeBlobUtil.MusicDir
|
|
166
|
-
constants.Add(L"MusicDir", UserDataPaths::GetDefault().Music());
|
|
167
|
-
|
|
168
|
-
// ReactNativeBlobUtil.MovieDir
|
|
169
|
-
constants.Add(L"MovieDir", UserDataPaths::GetDefault().Videos());
|
|
170
|
-
|
|
171
|
-
// ReactNativeBlobUtil.DownloadDirectoryPath - IMPLEMENT for convenience? (absent in iOS and deprecated in Android)
|
|
172
|
-
constants.Add(L"DownloadDir", UserDataPaths::GetDefault().Downloads());
|
|
173
|
-
|
|
174
|
-
// ReactNativeBlobUtil.MainBundleDir
|
|
175
|
-
constants.Add(L"MainBundleDir", to_string(Package::Current().InstalledLocation().Path()));
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// createFile
|
|
179
|
-
winrt::fire_and_forget ReactNativeBlobUtil::createFile(
|
|
180
|
-
std::string path,
|
|
181
|
-
std::wstring content,
|
|
182
|
-
std::string encoding,
|
|
183
|
-
winrt::Microsoft::ReactNative::ReactPromise<std::string> promise) noexcept
|
|
184
|
-
try
|
|
185
|
-
{
|
|
186
|
-
bool shouldExit{ false };
|
|
187
|
-
Streams::IBuffer buffer;
|
|
188
|
-
if (encoding.compare("uri") == 0)
|
|
189
|
-
{
|
|
190
|
-
try
|
|
191
|
-
{
|
|
192
|
-
winrt::hstring srcDirectoryPath, srcFileName;
|
|
193
|
-
splitPath(content, srcDirectoryPath, srcFileName);
|
|
194
|
-
StorageFolder srcFolder{ co_await StorageFolder::GetFolderFromPathAsync(srcDirectoryPath) };
|
|
195
|
-
StorageFile srcFile{ co_await srcFolder.GetFileAsync(srcFileName) };
|
|
196
|
-
buffer = co_await FileIO::ReadBufferAsync(srcFile);
|
|
197
|
-
}
|
|
198
|
-
catch (...)
|
|
199
|
-
{
|
|
200
|
-
shouldExit = true;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
else if (encoding.compare("utf8") == 0)
|
|
204
|
-
{
|
|
205
|
-
buffer = CryptographicBuffer::ConvertStringToBinary(content, BinaryStringEncoding::Utf8);
|
|
206
|
-
}
|
|
207
|
-
else if (encoding.compare("base64") == 0)
|
|
208
|
-
{
|
|
209
|
-
buffer = CryptographicBuffer::DecodeFromBase64String(content);
|
|
210
|
-
}
|
|
211
|
-
else
|
|
212
|
-
{
|
|
213
|
-
promise.Reject("Invalid encoding");
|
|
214
|
-
shouldExit = true;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
if (!shouldExit)
|
|
218
|
-
{
|
|
219
|
-
|
|
220
|
-
winrt::hstring destDirectoryPath, destFileName;
|
|
221
|
-
splitPath(path, destDirectoryPath, destFileName);
|
|
222
|
-
|
|
223
|
-
auto folder{ co_await StorageFolder::GetFolderFromPathAsync(destDirectoryPath) };
|
|
224
|
-
|
|
225
|
-
try
|
|
226
|
-
{
|
|
227
|
-
auto file{ co_await folder.CreateFileAsync(destFileName, CreationCollisionOption::FailIfExists) };
|
|
228
|
-
auto stream{ co_await file.OpenAsync(FileAccessMode::ReadWrite) };
|
|
229
|
-
co_await stream.WriteAsync(buffer);
|
|
230
|
-
}
|
|
231
|
-
catch (...)
|
|
232
|
-
{
|
|
233
|
-
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "EEXIST", "EEXIST: File already exists; " + path });
|
|
234
|
-
shouldExit = true;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
if (!shouldExit)
|
|
238
|
-
{
|
|
239
|
-
promise.Resolve(path);
|
|
240
|
-
}
|
|
241
|
-
co_return;
|
|
242
|
-
}
|
|
243
|
-
catch (const hresult_error& ex)
|
|
158
|
+
ReactNativeBlobUtilStream::ReactNativeBlobUtilStream(Streams::IRandomAccessStream& _streamInstance, EncodingOptions _encoding) noexcept
|
|
159
|
+
: streamInstance{ std::move(_streamInstance) }
|
|
160
|
+
, encoding{ _encoding }
|
|
244
161
|
{
|
|
245
|
-
hresult result{ ex.code() };
|
|
246
|
-
if (result == 0x80070002) // FileNotFoundException
|
|
247
|
-
{
|
|
248
|
-
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "ENOENT", "ENOENT: File does not exist and could not be created; " + path });
|
|
249
|
-
}
|
|
250
|
-
else
|
|
251
|
-
{
|
|
252
|
-
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "EUNSPECIFIED", "EUNSPECIFIED: " + winrt::to_string(ex.message()) + "; " + path });
|
|
253
|
-
}
|
|
254
162
|
}
|
|
255
163
|
|
|
256
|
-
winrt::
|
|
257
|
-
std::string path,
|
|
258
|
-
winrt::Microsoft::ReactNative::JSValueArray dataArray,
|
|
259
|
-
winrt::Microsoft::ReactNative::ReactPromise<std::string> promise) noexcept
|
|
260
|
-
try
|
|
164
|
+
namespace winrt::ReactNativeBlobUtil
|
|
261
165
|
{
|
|
262
|
-
std::vector<uint8_t> data;
|
|
263
|
-
data.reserve(dataArray.size());
|
|
264
|
-
for (auto& var : dataArray)
|
|
265
|
-
{
|
|
266
|
-
data.push_back(var.AsUInt8());
|
|
267
|
-
}
|
|
268
166
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
167
|
+
// See https://microsoft.github.io/react-native-windows/docs/native-modules for details on writing native modules
|
|
168
|
+
|
|
169
|
+
void ReactNativeBlobUtil::Initialize(React::ReactContext const& reactContext) noexcept {
|
|
170
|
+
m_context = reactContext;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Constants method
|
|
174
|
+
ReactNativeBlobUtilCodegen::BlobUtilsSpec_Constants ReactNativeBlobUtil::GetConstants() noexcept {
|
|
175
|
+
ReactNativeBlobUtilCodegen::BlobUtilsSpec_Constants constants;
|
|
176
|
+
constants.DocumentDir = to_string(ApplicationData::Current().LocalFolder().Path());
|
|
177
|
+
constants.CacheDir = to_string(ApplicationData::Current().LocalCacheFolder().Path());
|
|
178
|
+
constants.PictureDir = to_string(UserDataPaths::GetDefault().Pictures());
|
|
179
|
+
constants.MusicDir = to_string(UserDataPaths::GetDefault().Music());
|
|
180
|
+
constants.MovieDir = to_string(UserDataPaths::GetDefault().Videos());
|
|
181
|
+
constants.DownloadDir = to_string(UserDataPaths::GetDefault().Downloads());
|
|
182
|
+
constants.MainBundleDir = to_string(Package::Current().InstalledLocation().Path());
|
|
183
|
+
return constants;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
winrt::fire_and_forget ReactNativeBlobUtil::fetchBlobForm(
|
|
187
|
+
::React::JSValue options,
|
|
188
|
+
std::string taskId,
|
|
189
|
+
std::string method,
|
|
190
|
+
std::string url,
|
|
191
|
+
::React::JSValue headers,
|
|
192
|
+
::React::JSValueArray body,
|
|
193
|
+
std::function<void(::React::JSValueArray)> callback
|
|
194
|
+
) noexcept
|
|
195
|
+
{
|
|
196
|
+
try
|
|
197
|
+
{
|
|
198
|
+
winrt::hstring boundary{ L"-----" };
|
|
199
|
+
winrt::Windows::Web::Http::Filters::HttpBaseProtocolFilter filter;
|
|
200
|
+
ReactNativeBlobUtilConfig config{ options };
|
|
201
|
+
filter.AllowAutoRedirect(false);
|
|
202
|
+
|
|
203
|
+
if (config.trusty)
|
|
204
|
+
{
|
|
205
|
+
filter.IgnorableServerCertificateErrors().Append(
|
|
206
|
+
winrt::Windows::Security::Cryptography::Certificates::ChainValidationResult::Untrusted);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
winrt::Windows::Web::Http::HttpMethod httpMethod = winrt::Windows::Web::Http::HttpMethod::Post();
|
|
210
|
+
if (method == "DELETE" || method == "delete")
|
|
211
|
+
httpMethod = winrt::Windows::Web::Http::HttpMethod::Delete();
|
|
212
|
+
else if (method == "PUT" || method == "put")
|
|
213
|
+
httpMethod = winrt::Windows::Web::Http::HttpMethod::Put();
|
|
214
|
+
else if (method == "GET" || method == "get")
|
|
215
|
+
httpMethod = winrt::Windows::Web::Http::HttpMethod::Get();
|
|
216
|
+
else if (method != "POST" && method != "post")
|
|
217
|
+
{
|
|
218
|
+
::React::JSValueArray errorArray;
|
|
219
|
+
errorArray.push_back("Method not supported");
|
|
220
|
+
callback(std::move(errorArray));
|
|
221
|
+
co_return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
winrt::Windows::Web::Http::HttpRequestMessage requestMessage{ httpMethod, winrt::Windows::Foundation::Uri{ winrt::to_hstring(url) } };
|
|
225
|
+
winrt::Windows::Web::Http::HttpMultipartFormDataContent requestContent{ boundary };
|
|
226
|
+
|
|
227
|
+
// Add headers
|
|
228
|
+
if (headers.ItemCount() > 0)
|
|
229
|
+
{
|
|
230
|
+
for (const auto& entry : headers.AsObject())
|
|
231
|
+
{
|
|
232
|
+
if (!requestMessage.Headers().TryAppendWithoutValidation(
|
|
233
|
+
winrt::to_hstring(entry.first), winrt::to_hstring(entry.second.AsString())))
|
|
234
|
+
{
|
|
235
|
+
requestContent.Headers().TryAppendWithoutValidation(
|
|
236
|
+
winrt::to_hstring(entry.first), winrt::to_hstring(entry.second.AsString()));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Add form data
|
|
242
|
+
for (auto& entry : body)
|
|
243
|
+
{
|
|
244
|
+
auto& items = entry.AsObject();
|
|
245
|
+
auto data = items["data"].AsString();
|
|
246
|
+
|
|
247
|
+
// File upload support: expects "file://" prefix
|
|
248
|
+
bool isFile = data.rfind("file://", 0) == 0;
|
|
249
|
+
if (isFile)
|
|
250
|
+
{
|
|
251
|
+
std::string contentPath = data.substr(strlen("file://"));
|
|
252
|
+
winrt::hstring directoryPath, fileName;
|
|
253
|
+
splitPath(contentPath, directoryPath, fileName);
|
|
254
|
+
auto folder = co_await winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(directoryPath);
|
|
255
|
+
auto storageFile = co_await folder.GetFileAsync(fileName);
|
|
256
|
+
auto requestBuffer = co_await winrt::Windows::Storage::FileIO::ReadBufferAsync(storageFile);
|
|
257
|
+
|
|
258
|
+
winrt::Windows::Web::Http::HttpBufferContent requestBufferContent{ requestBuffer };
|
|
259
|
+
if (!items["type"].IsNull())
|
|
260
|
+
{
|
|
261
|
+
requestBufferContent.Headers().TryAppendWithoutValidation(
|
|
262
|
+
L"content-type", winrt::to_hstring(items["type"].AsString()));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
auto name = items["name"].IsNull() ? L"" : winrt::to_hstring(items["name"].AsString());
|
|
266
|
+
auto filename = items["filename"].IsNull() ? L"" : winrt::to_hstring(items["filename"].AsString());
|
|
267
|
+
if (name.empty())
|
|
268
|
+
{
|
|
269
|
+
requestContent.Add(requestBufferContent);
|
|
270
|
+
}
|
|
271
|
+
else if (filename.empty())
|
|
272
|
+
{
|
|
273
|
+
requestContent.Add(requestBufferContent, name);
|
|
274
|
+
}
|
|
275
|
+
else
|
|
276
|
+
{
|
|
277
|
+
requestContent.Add(requestBufferContent, name, filename);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
else
|
|
281
|
+
{
|
|
282
|
+
winrt::Windows::Web::Http::HttpStringContent dataContents{ winrt::to_hstring(data) };
|
|
283
|
+
if (!items["type"].IsNull())
|
|
284
|
+
{
|
|
285
|
+
dataContents.Headers().TryAppendWithoutValidation(
|
|
286
|
+
L"content-type", winrt::to_hstring(items["type"].AsString()));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
auto name = items["name"].IsNull() ? L"" : winrt::to_hstring(items["name"].AsString());
|
|
290
|
+
auto filename = items["filename"].IsNull() ? L"" : winrt::to_hstring(items["filename"].AsString());
|
|
291
|
+
if (name.empty())
|
|
292
|
+
{
|
|
293
|
+
requestContent.Add(dataContents);
|
|
294
|
+
}
|
|
295
|
+
else if (filename.empty())
|
|
296
|
+
{
|
|
297
|
+
requestContent.Add(dataContents, name);
|
|
298
|
+
}
|
|
299
|
+
else
|
|
300
|
+
{
|
|
301
|
+
requestContent.Add(dataContents, name, filename);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
requestMessage.Content(requestContent);
|
|
307
|
+
|
|
308
|
+
winrt::Windows::Web::Http::HttpClient httpClient{ filter };
|
|
309
|
+
auto response = co_await httpClient.SendRequestAsync(requestMessage);
|
|
310
|
+
|
|
311
|
+
std::string responseBody;
|
|
312
|
+
if (response.Content() != nullptr)
|
|
313
|
+
{
|
|
314
|
+
responseBody = winrt::to_string(co_await response.Content().ReadAsStringAsync());
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
::React::JSValueArray resultArray;
|
|
318
|
+
resultArray.push_back(responseBody);
|
|
319
|
+
callback(std::move(resultArray));
|
|
320
|
+
}
|
|
321
|
+
catch (const winrt::hresult_error& ex)
|
|
322
|
+
{
|
|
323
|
+
::React::JSValueArray errorArray;
|
|
324
|
+
errorArray.push_back("EUNSPECIFIED");
|
|
325
|
+
errorArray.push_back(winrt::to_string(ex.message()));
|
|
326
|
+
callback(std::move(errorArray));
|
|
327
|
+
}
|
|
328
|
+
catch (...)
|
|
329
|
+
{
|
|
330
|
+
::React::JSValueArray errorArray;
|
|
331
|
+
errorArray.push_back("EUNSPECIFIED");
|
|
332
|
+
errorArray.push_back("Unknown error in fetchBlobForm");
|
|
333
|
+
callback(std::move(errorArray));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
winrt::fire_and_forget ReactNativeBlobUtil::fetchBlob(
|
|
338
|
+
::React::JSValue options,
|
|
339
|
+
std::string taskId,
|
|
340
|
+
std::string method,
|
|
341
|
+
std::string url,
|
|
342
|
+
::React::JSValue headers,
|
|
343
|
+
std::string body,
|
|
344
|
+
std::function<void(::React::JSValueArray)> callback
|
|
345
|
+
) noexcept
|
|
346
|
+
{
|
|
347
|
+
// Convert rvalue references to lvalues for safe use
|
|
348
|
+
::React::JSValue& optionsRef = options;
|
|
349
|
+
::React::JSValue& headersRef = headers;
|
|
350
|
+
|
|
351
|
+
try
|
|
352
|
+
{
|
|
353
|
+
winrt::Windows::Web::Http::Filters::HttpBaseProtocolFilter filter;
|
|
354
|
+
ReactNativeBlobUtilConfig config{ optionsRef };
|
|
355
|
+
filter.AllowAutoRedirect(false);
|
|
356
|
+
if (config.trusty)
|
|
357
|
+
{
|
|
358
|
+
filter.IgnorableServerCertificateErrors().Append(Cryptography::Certificates::ChainValidationResult::Untrusted);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
winrt::Windows::Web::Http::HttpClient httpClient{ filter };
|
|
362
|
+
|
|
363
|
+
winrt::Windows::Web::Http::HttpMethod httpMethod{ winrt::Windows::Web::Http::HttpMethod::Post() };
|
|
364
|
+
if (method == "DELETE" || method == "delete")
|
|
365
|
+
{
|
|
366
|
+
httpMethod = winrt::Windows::Web::Http::HttpMethod::Delete();
|
|
367
|
+
}
|
|
368
|
+
else if (method == "PUT" || method == "put")
|
|
369
|
+
{
|
|
370
|
+
httpMethod = winrt::Windows::Web::Http::HttpMethod::Put();
|
|
371
|
+
}
|
|
372
|
+
else if (method == "GET" || method == "get")
|
|
373
|
+
{
|
|
374
|
+
httpMethod = winrt::Windows::Web::Http::HttpMethod::Get();
|
|
375
|
+
}
|
|
376
|
+
else
|
|
377
|
+
{
|
|
378
|
+
::React::JSValueArray errorArray;
|
|
379
|
+
errorArray.push_back("Method not supported");
|
|
380
|
+
callback(std::move(errorArray));
|
|
381
|
+
co_return;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
winrt::Windows::Web::Http::HttpRequestMessage requestMessage{
|
|
385
|
+
httpMethod,
|
|
386
|
+
winrt::Windows::Foundation::Uri{ winrt::to_hstring(url) }
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
std::string prefix = "file://";
|
|
390
|
+
bool pathToFile = body.rfind(prefix, 0) == 0;
|
|
391
|
+
if (pathToFile)
|
|
392
|
+
{
|
|
393
|
+
std::string contentPath = body.substr(prefix.length());
|
|
394
|
+
size_t fileLength = contentPath.length();
|
|
395
|
+
bool hasTrailingSlash = contentPath[fileLength - 1] == '\\' || contentPath[fileLength - 1] == '/';
|
|
396
|
+
winrt::hstring directoryPath, fileName;
|
|
397
|
+
splitPath(hasTrailingSlash ? contentPath.substr(0, fileLength - 1) : contentPath, directoryPath, fileName);
|
|
398
|
+
auto folder = co_await winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(directoryPath);
|
|
399
|
+
auto storageFile = co_await folder.GetFileAsync(fileName);
|
|
400
|
+
auto requestBuffer = co_await winrt::Windows::Storage::FileIO::ReadBufferAsync(storageFile);
|
|
401
|
+
|
|
402
|
+
winrt::Windows::Web::Http::HttpBufferContent requestContent{ requestBuffer };
|
|
403
|
+
|
|
404
|
+
for (const auto& entry : headersRef.AsObject())
|
|
405
|
+
{
|
|
406
|
+
if (!requestMessage.Headers().TryAppendWithoutValidation(winrt::to_hstring(entry.first), winrt::to_hstring(entry.second.AsString())))
|
|
407
|
+
{
|
|
408
|
+
requestContent.Headers().TryAppendWithoutValidation(winrt::to_hstring(entry.first), winrt::to_hstring(entry.second.AsString()));
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
requestMessage.Content(requestContent);
|
|
412
|
+
}
|
|
413
|
+
else if (!body.empty()) {
|
|
414
|
+
winrt::Windows::Web::Http::HttpStringContent requestString{ winrt::to_hstring(body) };
|
|
415
|
+
|
|
416
|
+
for (const auto& entry : headersRef.AsObject())
|
|
417
|
+
{
|
|
418
|
+
if (!requestMessage.Headers().TryAppendWithoutValidation(winrt::to_hstring(entry.first), winrt::to_hstring(entry.second.AsString())))
|
|
419
|
+
{
|
|
420
|
+
requestString.Headers().TryAppendWithoutValidation(winrt::to_hstring(entry.first), winrt::to_hstring(entry.second.AsString()));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
requestMessage.Content(requestString);
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
for (const auto& entry : headersRef.AsObject())
|
|
427
|
+
{
|
|
428
|
+
requestMessage.Headers().TryAppendWithoutValidation(winrt::to_hstring(entry.first), winrt::to_hstring(entry.second.AsString()));
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Send the request
|
|
433
|
+
auto response = co_await httpClient.SendRequestAsync(requestMessage);
|
|
434
|
+
|
|
435
|
+
std::string responseBody;
|
|
436
|
+
if (response.Content() != nullptr)
|
|
437
|
+
{
|
|
438
|
+
responseBody = winrt::to_string(co_await response.Content().ReadAsStringAsync());
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
::React::JSValueArray resultArray;
|
|
442
|
+
resultArray.push_back(responseBody);
|
|
443
|
+
callback(std::move(resultArray));
|
|
444
|
+
}
|
|
445
|
+
catch (const winrt::hresult_error& ex)
|
|
446
|
+
{
|
|
447
|
+
::React::JSValueArray errorArray;
|
|
448
|
+
errorArray.push_back("EUNSPECIFIED");
|
|
449
|
+
errorArray.push_back(winrt::to_string(ex.message()));
|
|
450
|
+
callback(std::move(errorArray));
|
|
451
|
+
}
|
|
452
|
+
catch (...)
|
|
453
|
+
{
|
|
454
|
+
::React::JSValueArray errorArray;
|
|
455
|
+
errorArray.push_back("EUNSPECIFIED");
|
|
456
|
+
errorArray.push_back("Unknown error in fetchBlob");
|
|
457
|
+
callback(std::move(errorArray));
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
winrt::fire_and_forget ReactNativeBlobUtil::createFile(
|
|
462
|
+
std::string path,
|
|
463
|
+
std::wstring content,
|
|
464
|
+
std::string encoding,
|
|
465
|
+
winrt::Microsoft::ReactNative::ReactPromise<void> promise) noexcept
|
|
466
|
+
{
|
|
467
|
+
try
|
|
468
|
+
{
|
|
469
|
+
bool shouldExit{ false };
|
|
470
|
+
Streams::IBuffer buffer;
|
|
471
|
+
if (encoding.compare("uri") == 0)
|
|
472
|
+
{
|
|
473
|
+
try
|
|
474
|
+
{
|
|
475
|
+
winrt::hstring srcDirectoryPath, srcFileName;
|
|
476
|
+
splitPath(content, srcDirectoryPath, srcFileName);
|
|
477
|
+
StorageFolder srcFolder{ co_await StorageFolder::GetFolderFromPathAsync(srcDirectoryPath) };
|
|
478
|
+
StorageFile srcFile{ co_await srcFolder.GetFileAsync(srcFileName) };
|
|
479
|
+
buffer = co_await FileIO::ReadBufferAsync(srcFile);
|
|
480
|
+
}
|
|
481
|
+
catch (...)
|
|
482
|
+
{
|
|
483
|
+
shouldExit = true;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
else if (encoding.compare("utf8") == 0)
|
|
487
|
+
{
|
|
488
|
+
buffer = CryptographicBuffer::ConvertStringToBinary(content, BinaryStringEncoding::Utf8);
|
|
489
|
+
}
|
|
490
|
+
else if (encoding.compare("base64") == 0)
|
|
491
|
+
{
|
|
492
|
+
buffer = CryptographicBuffer::DecodeFromBase64String(content);
|
|
493
|
+
}
|
|
494
|
+
else
|
|
495
|
+
{
|
|
496
|
+
promise.Reject("Invalid encoding");
|
|
497
|
+
shouldExit = true;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (!shouldExit)
|
|
501
|
+
{
|
|
502
|
+
|
|
503
|
+
winrt::hstring destDirectoryPath, destFileName;
|
|
504
|
+
splitPath(path, destDirectoryPath, destFileName);
|
|
505
|
+
|
|
506
|
+
auto folder{ co_await StorageFolder::GetFolderFromPathAsync(destDirectoryPath) };
|
|
507
|
+
|
|
508
|
+
try
|
|
509
|
+
{
|
|
510
|
+
auto file{ co_await folder.CreateFileAsync(destFileName, CreationCollisionOption::FailIfExists) };
|
|
511
|
+
auto stream{ co_await file.OpenAsync(FileAccessMode::ReadWrite) };
|
|
512
|
+
co_await stream.WriteAsync(buffer);
|
|
513
|
+
}
|
|
514
|
+
catch (...)
|
|
515
|
+
{
|
|
516
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "EEXIST", "EEXIST: File already exists; " + path });
|
|
517
|
+
shouldExit = true;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
if (!shouldExit)
|
|
521
|
+
{
|
|
522
|
+
promise.Resolve();
|
|
523
|
+
}
|
|
524
|
+
co_return;
|
|
525
|
+
}
|
|
526
|
+
catch (const hresult_error& ex)
|
|
527
|
+
{
|
|
528
|
+
hresult result{ ex.code() };
|
|
529
|
+
if (result == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) // FileNotFoundException
|
|
530
|
+
{
|
|
531
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "ENOENT", "ENOENT: File does not exist and could not be created; " + path });
|
|
532
|
+
}
|
|
533
|
+
else
|
|
534
|
+
{
|
|
535
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "EUNSPECIFIED", "EUNSPECIFIED: " + winrt::to_string(ex.message()) + "; " + path });
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
winrt::fire_and_forget ReactNativeBlobUtil::createFileASCII(
|
|
541
|
+
std::string path,
|
|
542
|
+
winrt::Microsoft::ReactNative::JSValueArray dataArray,
|
|
543
|
+
winrt::Microsoft::ReactNative::ReactPromise<void> promise) noexcept {
|
|
544
|
+
try
|
|
545
|
+
{
|
|
546
|
+
std::vector<uint8_t> data;
|
|
547
|
+
data.reserve(dataArray.size());
|
|
548
|
+
for (auto& var : dataArray)
|
|
549
|
+
{
|
|
550
|
+
data.push_back(var.AsUInt8());
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
Streams::IBuffer buffer{ CryptographicBuffer::CreateFromByteArray(data) };
|
|
554
|
+
|
|
555
|
+
winrt::hstring directoryPath, fileName;
|
|
556
|
+
splitPath(path, directoryPath, fileName);
|
|
557
|
+
|
|
558
|
+
StorageFolder folder{ co_await StorageFolder::GetFolderFromPathAsync(directoryPath) };
|
|
559
|
+
|
|
560
|
+
StorageFile file{ co_await folder.CreateFileAsync(fileName, CreationCollisionOption::FailIfExists) };
|
|
561
|
+
Streams::IRandomAccessStream stream{ co_await file.OpenAsync(FileAccessMode::ReadWrite) };
|
|
562
|
+
co_await stream.WriteAsync(buffer);
|
|
563
|
+
|
|
564
|
+
promise.Resolve();
|
|
565
|
+
}
|
|
566
|
+
catch (const hresult_error& ex)
|
|
567
|
+
{
|
|
568
|
+
hresult result{ ex.code() };
|
|
569
|
+
if (result == 0x80070002) // FileNotFoundException
|
|
570
|
+
{
|
|
571
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "ENOENT", "ENOENT: File does not exist and could not be created; " + path });
|
|
572
|
+
}
|
|
573
|
+
else if (result == 0x80070050)
|
|
574
|
+
{
|
|
575
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "EEXIST", "EEXIST: File already exists; " + path });
|
|
576
|
+
}
|
|
577
|
+
else
|
|
578
|
+
{
|
|
579
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "EUNSPECIFIED", "EUNSPECIFIED: " + winrt::to_string(ex.message()) });
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
winrt::fire_and_forget ReactNativeBlobUtil::writeFile(
|
|
585
|
+
std::string path,
|
|
586
|
+
std::string encoding,
|
|
587
|
+
std::wstring data,
|
|
588
|
+
bool transformFile,
|
|
589
|
+
bool append,
|
|
590
|
+
winrt::Microsoft::ReactNative::ReactPromise<double> promise) noexcept
|
|
591
|
+
{
|
|
592
|
+
try
|
|
593
|
+
{
|
|
594
|
+
Streams::IBuffer buffer;
|
|
595
|
+
if (encoding.compare("utf8") == 0)
|
|
596
|
+
{
|
|
597
|
+
buffer = Cryptography::CryptographicBuffer::ConvertStringToBinary(data, BinaryStringEncoding::Utf8);
|
|
598
|
+
}
|
|
599
|
+
else if (encoding.compare("base64") == 0)
|
|
600
|
+
{
|
|
601
|
+
buffer = Cryptography::CryptographicBuffer::DecodeFromBase64String(data);
|
|
602
|
+
}
|
|
603
|
+
else if (encoding.compare("uri") == 0)
|
|
604
|
+
{
|
|
605
|
+
winrt::hstring srcDirectoryPath, srcFileName;
|
|
606
|
+
splitPath(data, srcDirectoryPath, srcFileName);
|
|
607
|
+
StorageFolder srcFolder{ co_await StorageFolder::GetFolderFromPathAsync(srcDirectoryPath) };
|
|
608
|
+
StorageFile srcFile{ co_await srcFolder.GetFileAsync(srcFileName) };
|
|
609
|
+
buffer = co_await FileIO::ReadBufferAsync(srcFile);
|
|
610
|
+
}
|
|
611
|
+
else
|
|
612
|
+
{
|
|
613
|
+
auto errorMessage{ "Invalid encoding: " + encoding };
|
|
614
|
+
promise.Reject(errorMessage.c_str());
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
winrt::hstring destDirectoryPath, destFileName;
|
|
618
|
+
splitPath(path, destDirectoryPath, destFileName);
|
|
619
|
+
StorageFolder destFolder{ co_await StorageFolder::GetFolderFromPathAsync(destDirectoryPath) };
|
|
620
|
+
StorageFile destFile{ nullptr };
|
|
621
|
+
if (append)
|
|
622
|
+
{
|
|
623
|
+
destFile = co_await destFolder.CreateFileAsync(destFileName, CreationCollisionOption::OpenIfExists);
|
|
624
|
+
}
|
|
625
|
+
else
|
|
626
|
+
{
|
|
627
|
+
destFile = co_await destFolder.CreateFileAsync(destFileName, CreationCollisionOption::ReplaceExisting);
|
|
628
|
+
}
|
|
629
|
+
Streams::IRandomAccessStream stream{ co_await destFile.OpenAsync(FileAccessMode::ReadWrite) };
|
|
630
|
+
|
|
631
|
+
if (append)
|
|
632
|
+
{
|
|
633
|
+
stream.Seek(UINT64_MAX);
|
|
634
|
+
}
|
|
635
|
+
co_await stream.WriteAsync(buffer);
|
|
636
|
+
promise.Resolve(static_cast<double>(buffer.Length()));
|
|
637
|
+
}
|
|
638
|
+
catch (const hresult_error& ex)
|
|
639
|
+
{
|
|
640
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "EUNSPECIFIED", "EUNSPECIFIED: " + winrt::to_string(ex.message()) + "; " + path });
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
winrt::fire_and_forget ReactNativeBlobUtil::writeFileArray(
|
|
645
|
+
std::string path,
|
|
646
|
+
winrt::Microsoft::ReactNative::JSValueArray dataArray,
|
|
647
|
+
bool append,
|
|
648
|
+
winrt::Microsoft::ReactNative::ReactPromise<double> promise) noexcept
|
|
649
|
+
{
|
|
650
|
+
try
|
|
651
|
+
{
|
|
652
|
+
std::vector<uint8_t> data;
|
|
653
|
+
data.reserve(dataArray.size());
|
|
654
|
+
for (auto& var : dataArray)
|
|
655
|
+
{
|
|
656
|
+
data.push_back(var.AsUInt8());
|
|
657
|
+
}
|
|
658
|
+
Streams::IBuffer buffer{ CryptographicBuffer::CreateFromByteArray(data) };
|
|
659
|
+
|
|
660
|
+
winrt::hstring destDirectoryPath, destFileName;
|
|
661
|
+
splitPath(path, destDirectoryPath, destFileName);
|
|
662
|
+
StorageFolder destFolder{ co_await StorageFolder::GetFolderFromPathAsync(destDirectoryPath) };
|
|
663
|
+
StorageFile destFile{ nullptr };
|
|
664
|
+
if (append)
|
|
665
|
+
{
|
|
666
|
+
destFile = co_await destFolder.CreateFileAsync(destFileName, CreationCollisionOption::OpenIfExists);
|
|
667
|
+
}
|
|
668
|
+
else
|
|
669
|
+
{
|
|
670
|
+
destFile = co_await destFolder.CreateFileAsync(destFileName, CreationCollisionOption::ReplaceExisting);
|
|
671
|
+
}
|
|
672
|
+
Streams::IRandomAccessStream stream{ co_await destFile.OpenAsync(FileAccessMode::ReadWrite) };
|
|
673
|
+
|
|
674
|
+
if (append)
|
|
675
|
+
{
|
|
676
|
+
stream.Seek(UINT64_MAX);
|
|
677
|
+
}
|
|
678
|
+
co_await stream.WriteAsync(buffer);
|
|
679
|
+
promise.Resolve(static_cast<double>(buffer.Length()));
|
|
680
|
+
|
|
681
|
+
co_return;
|
|
682
|
+
}
|
|
683
|
+
catch (const hresult_error& ex)
|
|
684
|
+
{
|
|
685
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "EUNSPECIFIED", "EUNSPECIFIED: " + winrt::to_string(ex.message()) + "; " + path });
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
void ReactNativeBlobUtil::pathForAppGroup(
|
|
690
|
+
std::string groupName,
|
|
691
|
+
::React::ReactPromise<std::string>&& result) noexcept
|
|
283
692
|
{
|
|
284
|
-
|
|
285
|
-
if (result == 0x80070002) // FileNotFoundException
|
|
286
|
-
{
|
|
287
|
-
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "ENOENT", "ENOENT: File does not exist and could not be created; " + path });
|
|
288
|
-
}
|
|
289
|
-
else if (result == 0x80070050)
|
|
290
|
-
{
|
|
291
|
-
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "EEXIST", "EEXIST: File already exists; " + path });
|
|
292
|
-
}
|
|
293
|
-
else
|
|
294
|
-
{
|
|
295
|
-
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "EUNSPECIFIED", "EUNSPECIFIED: " + winrt::to_string(ex.message()) });
|
|
296
|
-
}
|
|
693
|
+
result.Resolve("");
|
|
297
694
|
}
|
|
298
695
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
winrt::fire_and_forget ReactNativeBlobUtil::writeFile(
|
|
302
|
-
std::string path,
|
|
303
|
-
std::string encoding,
|
|
304
|
-
std::wstring data,
|
|
305
|
-
bool append,
|
|
306
|
-
winrt::Microsoft::ReactNative::ReactPromise<int> promise) noexcept
|
|
307
|
-
try
|
|
308
|
-
{
|
|
309
|
-
Streams::IBuffer buffer;
|
|
310
|
-
if (encoding.compare("utf8") == 0)
|
|
311
|
-
{
|
|
312
|
-
buffer = Cryptography::CryptographicBuffer::ConvertStringToBinary(data, BinaryStringEncoding::Utf8);
|
|
313
|
-
}
|
|
314
|
-
else if (encoding.compare("base64") == 0)
|
|
315
|
-
{
|
|
316
|
-
buffer = Cryptography::CryptographicBuffer::DecodeFromBase64String(data);
|
|
317
|
-
}
|
|
318
|
-
else if (encoding.compare("uri") == 0)
|
|
319
|
-
{
|
|
320
|
-
winrt::hstring srcDirectoryPath, srcFileName;
|
|
321
|
-
splitPath(data, srcDirectoryPath, srcFileName);
|
|
322
|
-
StorageFolder srcFolder{ co_await StorageFolder::GetFolderFromPathAsync(srcDirectoryPath) };
|
|
323
|
-
StorageFile srcFile{ co_await srcFolder.GetFileAsync(srcFileName) };
|
|
324
|
-
buffer = co_await FileIO::ReadBufferAsync(srcFile);
|
|
325
|
-
}
|
|
326
|
-
else
|
|
327
|
-
{
|
|
328
|
-
auto errorMessage{ "Invalid encoding: " + encoding };
|
|
329
|
-
promise.Reject(errorMessage.c_str());
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
winrt::hstring destDirectoryPath, destFileName;
|
|
333
|
-
splitPath(path, destDirectoryPath, destFileName);
|
|
334
|
-
StorageFolder destFolder{ co_await StorageFolder::GetFolderFromPathAsync(destDirectoryPath) };
|
|
335
|
-
StorageFile destFile{ nullptr };
|
|
336
|
-
if (append)
|
|
337
|
-
{
|
|
338
|
-
destFile = co_await destFolder.CreateFileAsync(destFileName, CreationCollisionOption::OpenIfExists);
|
|
339
|
-
}
|
|
340
|
-
else
|
|
341
|
-
{
|
|
342
|
-
destFile = co_await destFolder.CreateFileAsync(destFileName, CreationCollisionOption::ReplaceExisting);
|
|
343
|
-
}
|
|
344
|
-
Streams::IRandomAccessStream stream{ co_await destFile.OpenAsync(FileAccessMode::ReadWrite) };
|
|
345
|
-
|
|
346
|
-
if (append)
|
|
347
|
-
{
|
|
348
|
-
stream.Seek(UINT64_MAX);
|
|
349
|
-
}
|
|
350
|
-
co_await stream.WriteAsync(buffer);
|
|
351
|
-
promise.Resolve(buffer.Length());
|
|
352
|
-
}
|
|
353
|
-
catch (const hresult_error& ex)
|
|
696
|
+
std::string ReactNativeBlobUtil::syncPathAppGroup(
|
|
697
|
+
std::string groupName) noexcept
|
|
354
698
|
{
|
|
355
|
-
|
|
699
|
+
return "";
|
|
356
700
|
}
|
|
357
701
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
bool append,
|
|
362
|
-
winrt::Microsoft::ReactNative::ReactPromise<int> promise) noexcept
|
|
363
|
-
try
|
|
702
|
+
void ReactNativeBlobUtil::exists(
|
|
703
|
+
std::string path,
|
|
704
|
+
std::function<void(std::vector<bool> const&)> const& callback) noexcept
|
|
364
705
|
{
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
}
|
|
371
|
-
Streams::IBuffer buffer{ CryptographicBuffer::CreateFromByteArray(data) };
|
|
372
|
-
|
|
373
|
-
winrt::hstring destDirectoryPath, destFileName;
|
|
374
|
-
splitPath(path, destDirectoryPath, destFileName);
|
|
375
|
-
StorageFolder destFolder{ co_await StorageFolder::GetFolderFromPathAsync(destDirectoryPath) };
|
|
376
|
-
StorageFile destFile{ nullptr };
|
|
377
|
-
if (append)
|
|
378
|
-
{
|
|
379
|
-
destFile = co_await destFolder.CreateFileAsync(destFileName, CreationCollisionOption::OpenIfExists);
|
|
380
|
-
}
|
|
381
|
-
else
|
|
382
|
-
{
|
|
383
|
-
destFile = co_await destFolder.CreateFileAsync(destFileName, CreationCollisionOption::ReplaceExisting);
|
|
384
|
-
}
|
|
385
|
-
Streams::IRandomAccessStream stream{ co_await destFile.OpenAsync(FileAccessMode::ReadWrite) };
|
|
386
|
-
|
|
387
|
-
if (append)
|
|
388
|
-
{
|
|
389
|
-
stream.Seek(UINT64_MAX);
|
|
390
|
-
}
|
|
391
|
-
co_await stream.WriteAsync(buffer);
|
|
392
|
-
promise.Resolve(buffer.Length());
|
|
706
|
+
try
|
|
707
|
+
{
|
|
708
|
+
std::filesystem::path fsPath(path);
|
|
709
|
+
bool doesExist = std::filesystem::exists(fsPath);
|
|
710
|
+
bool isDirectory = std::filesystem::is_directory(fsPath);
|
|
393
711
|
|
|
394
|
-
|
|
395
|
-
}
|
|
396
|
-
catch (const
|
|
397
|
-
{
|
|
398
|
-
|
|
712
|
+
callback(std::vector<bool>{ doesExist, isDirectory });
|
|
713
|
+
}
|
|
714
|
+
catch (const std::exception&)
|
|
715
|
+
{
|
|
716
|
+
// If something goes wrong, return false, false
|
|
717
|
+
callback(std::vector<bool>{ false, false });
|
|
718
|
+
}
|
|
399
719
|
}
|
|
400
720
|
|
|
401
|
-
|
|
402
|
-
// writeStream
|
|
403
721
|
winrt::fire_and_forget ReactNativeBlobUtil::writeStream(
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
try
|
|
722
|
+
std::string path,
|
|
723
|
+
std::string encoding,
|
|
724
|
+
bool appendData,
|
|
725
|
+
std::function<void(::React::JSValueArray)> callback) noexcept
|
|
409
726
|
{
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
727
|
+
try
|
|
728
|
+
{
|
|
729
|
+
winrt::hstring directoryPath, fileName;
|
|
730
|
+
splitPath(path, directoryPath, fileName);
|
|
731
|
+
auto folder = co_await StorageFolder::GetFolderFromPathAsync(directoryPath);
|
|
732
|
+
auto file = co_await folder.CreateFileAsync(fileName, CreationCollisionOption::OpenIfExists);
|
|
733
|
+
auto stream = co_await file.OpenAsync(FileAccessMode::ReadWrite);
|
|
734
|
+
if (appendData)
|
|
735
|
+
{
|
|
736
|
+
stream.Seek(stream.Size());
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
EncodingOptions encodingOption;
|
|
740
|
+
if (encoding == "utf8")
|
|
741
|
+
{
|
|
742
|
+
encodingOption = EncodingOptions::UTF8;
|
|
743
|
+
}
|
|
744
|
+
else if (encoding == "base64")
|
|
745
|
+
{
|
|
746
|
+
encodingOption = EncodingOptions::BASE64;
|
|
747
|
+
}
|
|
748
|
+
else if (encoding == "ascii")
|
|
749
|
+
{
|
|
750
|
+
encodingOption = EncodingOptions::ASCII;
|
|
751
|
+
}
|
|
752
|
+
else
|
|
753
|
+
{
|
|
754
|
+
// Return error as JSValueArray
|
|
755
|
+
::React::JSValueArray errorArray;
|
|
756
|
+
errorArray.push_back("EUNSPECIFIED");
|
|
757
|
+
errorArray.push_back("Invalid encoding: " + encoding);
|
|
758
|
+
errorArray.push_back("");
|
|
759
|
+
callback(std::move(errorArray));
|
|
760
|
+
co_return;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// Generate a random streamId
|
|
764
|
+
uint32_t length = 16;
|
|
765
|
+
IBuffer buffer = Cryptography::CryptographicBuffer::GenerateRandom(length);
|
|
766
|
+
std::string streamId = winrt::to_string(Cryptography::CryptographicBuffer::EncodeToHexString(buffer));
|
|
767
|
+
|
|
768
|
+
ReactNativeBlobUtilStream streamInstance{ stream, encodingOption };
|
|
769
|
+
m_streamMap.try_emplace(streamId, streamInstance);
|
|
770
|
+
|
|
771
|
+
// Return success as JSValueArray
|
|
772
|
+
::React::JSValueArray resultArray;
|
|
773
|
+
resultArray.push_back(""); // no error
|
|
774
|
+
resultArray.push_back(""); // no message
|
|
775
|
+
resultArray.push_back(streamId);
|
|
776
|
+
callback(std::move(resultArray));
|
|
777
|
+
}
|
|
778
|
+
catch (const winrt::hresult_error& ex)
|
|
779
|
+
{
|
|
780
|
+
::React::JSValueArray errorArray;
|
|
781
|
+
errorArray.push_back("EUNSPECIFIED");
|
|
782
|
+
errorArray.push_back("Failed to create write stream at path '" + path + "'; " + winrt::to_string(ex.message()));
|
|
783
|
+
errorArray.push_back("");
|
|
784
|
+
callback(std::move(errorArray));
|
|
785
|
+
}
|
|
449
786
|
}
|
|
450
|
-
|
|
787
|
+
|
|
788
|
+
void ReactNativeBlobUtil::writeArrayChunk(
|
|
789
|
+
std::string streamId,
|
|
790
|
+
::React::JSValueArray&& dataArray,
|
|
791
|
+
std::function<void(::React::JSValueArray const&)> const& callback) noexcept
|
|
451
792
|
{
|
|
452
|
-
|
|
793
|
+
try
|
|
794
|
+
{
|
|
795
|
+
auto streamIt = m_streamMap.find(streamId);
|
|
796
|
+
if (streamIt == m_streamMap.end()) {
|
|
797
|
+
::React::JSValueArray errorArray;
|
|
798
|
+
errorArray.push_back("EUNSPECIFIED");
|
|
799
|
+
errorArray.push_back("Stream not found for id: " + streamId);
|
|
800
|
+
callback(errorArray);
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
auto& stream = streamIt->second;
|
|
804
|
+
std::vector<uint8_t> data;
|
|
805
|
+
data.reserve(dataArray.size());
|
|
806
|
+
for (auto& var : dataArray)
|
|
807
|
+
{
|
|
808
|
+
data.push_back(var.AsUInt8());
|
|
809
|
+
}
|
|
810
|
+
Streams::IBuffer buffer{ CryptographicBuffer::CreateFromByteArray(data) };
|
|
811
|
+
|
|
812
|
+
stream.streamInstance.WriteAsync(buffer).get(); // Calls it synchronously
|
|
813
|
+
::React::JSValueArray resultArray;
|
|
814
|
+
callback(resultArray); // Success: empty array
|
|
815
|
+
}
|
|
816
|
+
catch (const winrt::hresult_error& ex)
|
|
817
|
+
{
|
|
818
|
+
::React::JSValueArray errorArray;
|
|
819
|
+
errorArray.push_back("EUNSPECIFIED");
|
|
820
|
+
errorArray.push_back(winrt::to_string(ex.message()));
|
|
821
|
+
callback(errorArray);
|
|
822
|
+
}
|
|
453
823
|
}
|
|
454
824
|
|
|
455
|
-
|
|
456
|
-
// writeChunk
|
|
457
825
|
void ReactNativeBlobUtil::writeChunk(
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
try
|
|
462
|
-
{
|
|
463
|
-
auto stream{ m_streamMap.find(streamId)->second };
|
|
464
|
-
Streams::IBuffer buffer;
|
|
465
|
-
if (stream.encoding == EncodingOptions::UTF8)
|
|
466
|
-
{
|
|
467
|
-
buffer = Cryptography::CryptographicBuffer::ConvertStringToBinary(data, BinaryStringEncoding::Utf8);
|
|
468
|
-
}
|
|
469
|
-
else if (stream.encoding == EncodingOptions::BASE64)
|
|
470
|
-
{
|
|
471
|
-
buffer = Cryptography::CryptographicBuffer::DecodeFromBase64String(data);
|
|
472
|
-
}
|
|
473
|
-
else
|
|
474
|
-
{
|
|
475
|
-
callback("Invalid encoding type");
|
|
476
|
-
return;
|
|
477
|
-
}
|
|
478
|
-
stream.streamInstance.WriteAsync(buffer).get(); //Calls it synchronously
|
|
479
|
-
callback("");
|
|
480
|
-
}
|
|
481
|
-
catch (const hresult_error& ex)
|
|
826
|
+
std::string streamId,
|
|
827
|
+
std::string data,
|
|
828
|
+
std::function<void(::React::JSValueArray const&)> const& callback) noexcept
|
|
482
829
|
{
|
|
483
|
-
|
|
830
|
+
try
|
|
831
|
+
{
|
|
832
|
+
auto streamIt = m_streamMap.find(streamId);
|
|
833
|
+
if (streamIt == m_streamMap.end()) {
|
|
834
|
+
::React::JSValueArray errorArray;
|
|
835
|
+
errorArray.push_back("EUNSPECIFIED");
|
|
836
|
+
errorArray.push_back("Stream not found for id: " + streamId);
|
|
837
|
+
callback(errorArray);
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
auto& stream = streamIt->second;
|
|
841
|
+
Streams::IBuffer buffer;
|
|
842
|
+
if (stream.encoding == EncodingOptions::UTF8)
|
|
843
|
+
{
|
|
844
|
+
buffer = Cryptography::CryptographicBuffer::ConvertStringToBinary(
|
|
845
|
+
winrt::to_hstring(data), BinaryStringEncoding::Utf8);
|
|
846
|
+
}
|
|
847
|
+
else if (stream.encoding == EncodingOptions::BASE64)
|
|
848
|
+
{
|
|
849
|
+
buffer = Cryptography::CryptographicBuffer::DecodeFromBase64String(winrt::to_hstring(data));
|
|
850
|
+
}
|
|
851
|
+
else
|
|
852
|
+
{
|
|
853
|
+
::React::JSValueArray errorArray;
|
|
854
|
+
errorArray.push_back("EUNSPECIFIED");
|
|
855
|
+
errorArray.push_back("Invalid encoding type");
|
|
856
|
+
callback(errorArray);
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
stream.streamInstance.WriteAsync(buffer).get(); // Synchronous write
|
|
860
|
+
::React::JSValueArray resultArray;
|
|
861
|
+
callback(resultArray); // Success: empty array
|
|
862
|
+
}
|
|
863
|
+
catch (const winrt::hresult_error& ex)
|
|
864
|
+
{
|
|
865
|
+
::React::JSValueArray errorArray;
|
|
866
|
+
errorArray.push_back("EUNSPECIFIED");
|
|
867
|
+
errorArray.push_back(winrt::to_string(ex.message()));
|
|
868
|
+
callback(errorArray);
|
|
869
|
+
}
|
|
484
870
|
}
|
|
485
871
|
|
|
486
|
-
void ReactNativeBlobUtil::
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
std::function<void(std::string)> callback) noexcept
|
|
490
|
-
try
|
|
491
|
-
{
|
|
492
|
-
auto stream{ m_streamMap.find(streamId)->second };
|
|
493
|
-
std::vector<uint8_t> data;
|
|
494
|
-
data.reserve(dataArray.size());
|
|
495
|
-
for (auto& var : dataArray)
|
|
496
|
-
{
|
|
497
|
-
data.push_back(var.AsUInt8());
|
|
498
|
-
}
|
|
499
|
-
Streams::IBuffer buffer{ CryptographicBuffer::CreateFromByteArray(data) };
|
|
500
|
-
|
|
501
|
-
stream.streamInstance.WriteAsync(buffer).get(); // Calls it synchronously
|
|
502
|
-
callback("");
|
|
503
|
-
}
|
|
504
|
-
catch (const hresult_error& ex)
|
|
872
|
+
void ReactNativeBlobUtil::closeStream(
|
|
873
|
+
std::string streamId,
|
|
874
|
+
std::function<void(::React::JSValueArray const&)> const& callback) noexcept
|
|
505
875
|
{
|
|
506
|
-
|
|
876
|
+
::React::JSValueArray resultArray;
|
|
877
|
+
try
|
|
878
|
+
{
|
|
879
|
+
auto it = m_streamMap.find(streamId);
|
|
880
|
+
if (it != m_streamMap.end()) {
|
|
881
|
+
it->second.streamInstance.Close();
|
|
882
|
+
m_streamMap.erase(it);
|
|
883
|
+
// Success: return empty array
|
|
884
|
+
callback(resultArray);
|
|
885
|
+
} else {
|
|
886
|
+
// Stream not found
|
|
887
|
+
resultArray.push_back("EUNSPECIFIED");
|
|
888
|
+
resultArray.push_back("Stream not found for id: " + streamId);
|
|
889
|
+
callback(resultArray);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
catch (const winrt::hresult_error& ex)
|
|
893
|
+
{
|
|
894
|
+
resultArray.push_back("EUNSPECIFIED");
|
|
895
|
+
resultArray.push_back(winrt::to_string(ex.message()));
|
|
896
|
+
callback(resultArray);
|
|
897
|
+
}
|
|
507
898
|
}
|
|
508
899
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
std::string encoding,
|
|
513
|
-
uint32_t bufferSize,
|
|
514
|
-
uint64_t tick,
|
|
515
|
-
const std::string streamId) noexcept
|
|
516
|
-
try
|
|
900
|
+
winrt::fire_and_forget ReactNativeBlobUtil::unlink(
|
|
901
|
+
std::string path,
|
|
902
|
+
std::function<void(::React::JSValueArray)> callback) noexcept
|
|
517
903
|
{
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
for (;;)
|
|
554
|
-
{
|
|
555
|
-
auto readBuffer = stream.ReadAsync(buffer, buffer.Capacity(), InputStreamOptions::None).get();
|
|
556
|
-
if (readBuffer.Length() == 0)
|
|
557
|
-
{
|
|
558
|
-
m_reactContext.CallJSFunction(L"RCTDeviceEventEmitter", L"emit", streamId,
|
|
559
|
-
winrt::Microsoft::ReactNative::JSValueObject{
|
|
560
|
-
{"event", "end"},
|
|
561
|
-
});
|
|
562
|
-
break;
|
|
563
|
-
}
|
|
564
|
-
if (usedEncoding == EncodingOptions::BASE64)
|
|
565
|
-
{
|
|
566
|
-
// TODO: Investigate returning wstrings as parameters
|
|
567
|
-
winrt::hstring base64Content{ Cryptography::CryptographicBuffer::EncodeToBase64String(readBuffer) };
|
|
568
|
-
//m_reactContext.CallJSFunction(L"RCTDeviceEventEmitter", L"emit", [&streamId, &base64Content](React::IJSValueWriter const& argWriter) {
|
|
569
|
-
// argWriter.WriteArrayBegin();
|
|
570
|
-
// WriteValue(argWriter, streamId);
|
|
571
|
-
// argWriter.WriteObjectBegin();
|
|
572
|
-
// React::WriteProperty(argWriter, "event", "data");
|
|
573
|
-
// React::WriteProperty(argWriter, "detail", base64Content);
|
|
574
|
-
// argWriter.WriteObjectEnd();
|
|
575
|
-
// argWriter.WriteArrayEnd();
|
|
576
|
-
// });
|
|
577
|
-
m_reactContext.CallJSFunction(L"RCTDeviceEventEmitter", L"emit", streamId,
|
|
578
|
-
winrt::Microsoft::ReactNative::JSValueObject{
|
|
579
|
-
{"event", "data"},
|
|
580
|
-
{"detail", winrt::to_string(base64Content)},
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
else
|
|
584
|
-
{
|
|
585
|
-
// TODO: Sending events not working as necessary with writers
|
|
586
|
-
std::string utf8Content{ winrt::to_string(Cryptography::CryptographicBuffer::ConvertBinaryToString(BinaryStringEncoding::Utf8, readBuffer)) };
|
|
587
|
-
if (usedEncoding == EncodingOptions::ASCII)
|
|
588
|
-
{
|
|
589
|
-
|
|
590
|
-
//std::string asciiContent{ winrt::to_string(utf8Content) };
|
|
591
|
-
std::string asciiContent{ utf8Content };
|
|
592
|
-
// emit ascii content
|
|
593
|
-
m_reactContext.CallJSFunction(L"RCTDeviceEventEmitter", L"emit", streamId,
|
|
594
|
-
winrt::Microsoft::ReactNative::JSValueObject{
|
|
595
|
-
{"event", "data"},
|
|
596
|
-
{"detail", asciiContent},
|
|
597
|
-
});
|
|
598
|
-
}
|
|
599
|
-
else
|
|
600
|
-
{
|
|
601
|
-
//emit utf8 content
|
|
602
|
-
m_reactContext.CallJSFunction(L"RCTDeviceEventEmitter", L"emit", streamId,
|
|
603
|
-
winrt::Microsoft::ReactNative::JSValueObject{
|
|
604
|
-
{"event", "data"},
|
|
605
|
-
{"detail", utf8Content},
|
|
606
|
-
});
|
|
607
|
-
//m_reactContext.CallJSFunction(L"RCTDeviceEventEmitter", L"emit", [&streamId, &utf8Content](React::IJSValueWriter const& argWriter) {
|
|
608
|
-
// WriteValue(argWriter, streamId);
|
|
609
|
-
// argWriter.WriteObjectBegin();
|
|
610
|
-
// React::WriteProperty(argWriter, "event", L"data");
|
|
611
|
-
// React::WriteProperty(argWriter, "detail", utf8Content);
|
|
612
|
-
// argWriter.WriteObjectEnd();
|
|
613
|
-
// });
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
// sleep
|
|
617
|
-
if (tick > 0)
|
|
618
|
-
{
|
|
619
|
-
std::this_thread::sleep_for(std::chrono::milliseconds(tick));
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
catch (const hresult_error& ex)
|
|
904
|
+
try
|
|
905
|
+
{
|
|
906
|
+
if (std::filesystem::is_directory(path))
|
|
907
|
+
{
|
|
908
|
+
std::filesystem::path unlinkPath(path);
|
|
909
|
+
unlinkPath.make_preferred();
|
|
910
|
+
auto folderOp = winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(
|
|
911
|
+
winrt::to_hstring(unlinkPath.c_str()));
|
|
912
|
+
co_await folderOp.get().DeleteAsync();
|
|
913
|
+
}
|
|
914
|
+
else
|
|
915
|
+
{
|
|
916
|
+
winrt::hstring directoryPath, fileName;
|
|
917
|
+
splitPath(path, directoryPath, fileName);
|
|
918
|
+
auto folder = co_await winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(directoryPath);
|
|
919
|
+
auto item = co_await folder.GetItemAsync(fileName);
|
|
920
|
+
co_await item.DeleteAsync();
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
::React::JSValueArray result;
|
|
924
|
+
result.push_back(::React::JSValue(true));
|
|
925
|
+
callback(std::move(result));
|
|
926
|
+
}
|
|
927
|
+
catch (const winrt::hresult_error& ex)
|
|
928
|
+
{
|
|
929
|
+
::React::JSValueArray errorResult;
|
|
930
|
+
errorResult.push_back(::React::JSValue(false));
|
|
931
|
+
errorResult.push_back(::React::JSValue(winrt::to_string(ex.message())));
|
|
932
|
+
callback(std::move(errorResult));
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
winrt::fire_and_forget ReactNativeBlobUtil::removeSession(::React::JSValueArray paths, std::function<void(::React::JSValueArray)> callback) noexcept
|
|
624
938
|
{
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
939
|
+
try
|
|
940
|
+
{
|
|
941
|
+
for (const auto& pathValue : paths)
|
|
942
|
+
{
|
|
943
|
+
if (pathValue)
|
|
944
|
+
{
|
|
945
|
+
std::string path = pathValue.AsString();
|
|
946
|
+
auto folder = co_await winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(winrt::to_hstring(path));
|
|
947
|
+
auto file = co_await folder.GetFileAsync(winrt::to_hstring(path));
|
|
948
|
+
co_await file.DeleteAsync();
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
::React::JSValueArray resultArray;
|
|
953
|
+
resultArray.push_back("SUCCESS");
|
|
954
|
+
callback(std::move(resultArray));
|
|
955
|
+
}
|
|
956
|
+
catch (const winrt::hresult_error& ex)
|
|
957
|
+
{
|
|
958
|
+
::React::JSValueArray errorArray;
|
|
959
|
+
errorArray.push_back("ERROR");
|
|
960
|
+
errorArray.push_back(winrt::to_string(ex.message()));
|
|
961
|
+
callback(std::move(errorArray));
|
|
962
|
+
}
|
|
963
|
+
catch (...)
|
|
964
|
+
{
|
|
965
|
+
::React::JSValueArray errorArray;
|
|
966
|
+
errorArray.push_back("ERROR");
|
|
967
|
+
errorArray.push_back("Unknown error in removeSession");
|
|
968
|
+
callback(std::move(errorArray));
|
|
969
|
+
}
|
|
642
970
|
}
|
|
643
971
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
std::string path,
|
|
648
|
-
winrt::Microsoft::ReactNative::ReactPromise<bool> promise) noexcept
|
|
649
|
-
try
|
|
650
|
-
{
|
|
651
|
-
std::filesystem::path dirPath(path);
|
|
652
|
-
dirPath.make_preferred();
|
|
653
|
-
|
|
654
|
-
// Consistent with Apple's createDirectoryAtPath method and result, but not with Android's
|
|
655
|
-
if (std::filesystem::create_directories(dirPath) == false)
|
|
656
|
-
{
|
|
657
|
-
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "ENOENT", "ENOENT: no such file or directory, open " + path });
|
|
658
|
-
}
|
|
659
|
-
else
|
|
660
|
-
{
|
|
661
|
-
promise.Resolve(true);
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
catch (const hresult_error& ex)
|
|
972
|
+
winrt::fire_and_forget ReactNativeBlobUtil::ls(
|
|
973
|
+
std::string path,
|
|
974
|
+
::React::ReactPromise<::React::JSValueArray> promise) noexcept
|
|
665
975
|
{
|
|
666
|
-
|
|
976
|
+
try
|
|
977
|
+
{
|
|
978
|
+
winrt::hstring directoryPath, fileName;
|
|
979
|
+
splitPath(path, directoryPath, fileName);
|
|
980
|
+
|
|
981
|
+
auto folder = co_await Windows::Storage::StorageFolder::GetFolderFromPathAsync(directoryPath);
|
|
982
|
+
auto items = co_await folder.GetItemsAsync();
|
|
983
|
+
|
|
984
|
+
::React::JSValueArray results;
|
|
985
|
+
for (const auto& item : items)
|
|
986
|
+
{
|
|
987
|
+
results.push_back(::React::JSValue{ winrt::to_string(item.Name()) });
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
promise.Resolve(results);
|
|
991
|
+
}
|
|
992
|
+
catch (const winrt::hresult_error& ex)
|
|
993
|
+
{
|
|
994
|
+
hresult result = ex.code();
|
|
995
|
+
if (result == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND))
|
|
996
|
+
{
|
|
997
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "ENOTDIR", "Not a directory '" + path + "'" });
|
|
998
|
+
}
|
|
999
|
+
else
|
|
1000
|
+
{
|
|
1001
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "EUNSPECIFIED", winrt::to_string(ex.message()) });
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
667
1004
|
}
|
|
668
1005
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
std::string path,
|
|
673
|
-
std::string encoding,
|
|
674
|
-
winrt::Microsoft::ReactNative::ReactPromise<std::wstring> promise) noexcept
|
|
675
|
-
try
|
|
676
|
-
{
|
|
677
|
-
winrt::hstring directoryPath, fileName;
|
|
678
|
-
splitPath(path, directoryPath, fileName);
|
|
679
|
-
|
|
680
|
-
StorageFolder folder{ co_await StorageFolder::GetFolderFromPathAsync(directoryPath) };
|
|
681
|
-
StorageFile file{ co_await folder.GetFileAsync(fileName) };
|
|
682
|
-
|
|
683
|
-
Streams::IBuffer buffer{ co_await FileIO::ReadBufferAsync(file) };
|
|
684
|
-
if (encoding.compare("base64") == 0)
|
|
685
|
-
{
|
|
686
|
-
std::wstring base64Content{ Cryptography::CryptographicBuffer::EncodeToBase64String(buffer) };
|
|
687
|
-
promise.Resolve(base64Content);
|
|
688
|
-
}
|
|
689
|
-
else
|
|
690
|
-
{
|
|
691
|
-
std::wstring utf8Content{ Cryptography::CryptographicBuffer::ConvertBinaryToString(BinaryStringEncoding::Utf8, buffer) };
|
|
692
|
-
if (encoding.compare("ascii") == 0)
|
|
693
|
-
{
|
|
694
|
-
std::string asciiContent{ winrt::to_string(utf8Content) };
|
|
695
|
-
std::wstring asciiResult{ winrt::to_hstring(asciiContent) };
|
|
696
|
-
promise.Resolve(asciiResult);
|
|
697
|
-
co_return;
|
|
698
|
-
}
|
|
699
|
-
promise.Resolve(utf8Content);
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
catch (const hresult_error& ex)
|
|
1006
|
+
winrt::fire_and_forget ReactNativeBlobUtil::stat(
|
|
1007
|
+
std::string path,
|
|
1008
|
+
std::function<void(::React::JSValueArray)> callback) noexcept
|
|
703
1009
|
{
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
1010
|
+
try
|
|
1011
|
+
{
|
|
1012
|
+
std::filesystem::path givenPath(path);
|
|
1013
|
+
givenPath.make_preferred();
|
|
1014
|
+
bool isDirectory{ std::filesystem::is_directory(path) };
|
|
1015
|
+
|
|
1016
|
+
//std::string resultPath{ winrt::to_string(givenPath.c_str()) };
|
|
1017
|
+
auto resultPath{ winrt::to_hstring(givenPath.c_str()) };
|
|
1018
|
+
|
|
1019
|
+
// Try to open as folder
|
|
1020
|
+
IStorageItem item;
|
|
1021
|
+
if (isDirectory) {
|
|
1022
|
+
item = co_await StorageFolder::GetFolderFromPathAsync(resultPath);
|
|
1023
|
+
}
|
|
1024
|
+
else {
|
|
1025
|
+
item = co_await StorageFile::GetFileFromPathAsync(resultPath);
|
|
1026
|
+
}
|
|
1027
|
+
auto properties{ co_await item.GetBasicPropertiesAsync() };
|
|
1028
|
+
winrt::Microsoft::ReactNative::JSValueObject fileInfo;
|
|
1029
|
+
fileInfo["size"] = properties.Size();
|
|
1030
|
+
fileInfo["filename"] = givenPath.filename().string();
|
|
1031
|
+
fileInfo["path"] = givenPath.string();
|
|
1032
|
+
fileInfo["lastModified"] = winrt::clock::to_time_t(properties.DateModified());;
|
|
1033
|
+
fileInfo["type"] = isDirectory ? "directory" : "file";
|
|
1034
|
+
|
|
1035
|
+
::React::JSValueArray result;
|
|
1036
|
+
result.push_back(std::move(fileInfo));
|
|
1037
|
+
callback(std::move(result));
|
|
1038
|
+
}
|
|
1039
|
+
catch (const hresult_error& ex)
|
|
1040
|
+
{
|
|
1041
|
+
::React::JSValueArray errorArray;
|
|
1042
|
+
::React::JSValueObject error;
|
|
1043
|
+
error["error"] = winrt::to_string(ex.message());
|
|
1044
|
+
errorArray.push_back(std::move(error));
|
|
1045
|
+
callback(std::move(errorArray));
|
|
1046
|
+
}
|
|
718
1047
|
}
|
|
719
1048
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
std::string path,
|
|
724
|
-
std::string algorithm,
|
|
725
|
-
winrt::Microsoft::ReactNative::ReactPromise<std::wstring> promise) noexcept
|
|
726
|
-
try
|
|
1049
|
+
winrt::fire_and_forget ReactNativeBlobUtil::lstat(
|
|
1050
|
+
std::string path,
|
|
1051
|
+
std::function<void(::React::JSValueArray)> callback) noexcept
|
|
727
1052
|
{
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
}
|
|
1053
|
+
try
|
|
1054
|
+
{
|
|
1055
|
+
std::filesystem::path directory(path);
|
|
1056
|
+
directory.make_preferred();
|
|
1057
|
+
StorageFolder targetDirectory{ co_await StorageFolder::GetFolderFromPathAsync(directory.c_str()) };
|
|
734
1058
|
|
|
735
|
-
|
|
736
|
-
splitPath(path, directoryPath, fileName);
|
|
1059
|
+
winrt::Microsoft::ReactNative::JSValueArray resultsArray;
|
|
737
1060
|
|
|
738
|
-
|
|
739
|
-
|
|
1061
|
+
auto items{ co_await targetDirectory.GetItemsAsync() };
|
|
1062
|
+
for (auto item : items)
|
|
1063
|
+
{
|
|
1064
|
+
auto properties{ co_await item.GetBasicPropertiesAsync() };
|
|
740
1065
|
|
|
741
|
-
|
|
742
|
-
if (search == availableHashes.end())
|
|
743
|
-
{
|
|
744
|
-
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "Error", "Invalid hash algorithm " + algorithm });
|
|
745
|
-
co_return;
|
|
746
|
-
}
|
|
1066
|
+
winrt::Microsoft::ReactNative::JSValueObject itemInfo;
|
|
747
1067
|
|
|
748
|
-
|
|
749
|
-
|
|
1068
|
+
itemInfo["filename"] = to_string(item.Name());
|
|
1069
|
+
itemInfo["path"] = to_string(item.Path());
|
|
1070
|
+
itemInfo["size"] = properties.Size();
|
|
1071
|
+
itemInfo["type"] = item.IsOfType(StorageItemTypes::Folder) ? "directory" : "file";
|
|
1072
|
+
itemInfo["lastModified"] = properties.DateModified().time_since_epoch() / std::chrono::seconds(1) - UNIX_EPOCH_IN_WINRT_SECONDS;
|
|
750
1073
|
|
|
751
|
-
|
|
752
|
-
|
|
1074
|
+
resultsArray.push_back(std::move(itemInfo));
|
|
1075
|
+
}
|
|
753
1076
|
|
|
754
|
-
|
|
1077
|
+
callback(std::move(resultsArray));
|
|
1078
|
+
}
|
|
1079
|
+
catch (...)
|
|
1080
|
+
{
|
|
1081
|
+
// "Failed to read directory."
|
|
1082
|
+
winrt::Microsoft::ReactNative::JSValueArray emptyArray;
|
|
1083
|
+
callback(std::move(emptyArray));
|
|
1084
|
+
}
|
|
755
1085
|
}
|
|
756
|
-
|
|
1086
|
+
|
|
1087
|
+
winrt::fire_and_forget ReactNativeBlobUtil::cp(
|
|
1088
|
+
std::string src,
|
|
1089
|
+
std::string dest,
|
|
1090
|
+
std::function<void(::React::JSValueArray)> callback) noexcept
|
|
757
1091
|
{
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
}
|
|
763
|
-
else if (result == 0x80070005) // UnauthorizedAccessException
|
|
764
|
-
{
|
|
765
|
-
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "EISDIR", "EISDIR: illegal operation on a directory, read" });
|
|
766
|
-
}
|
|
767
|
-
else
|
|
768
|
-
{
|
|
769
|
-
// "Failed to get checksum from file."
|
|
770
|
-
promise.Reject(winrt::to_string(ex.message()).c_str());
|
|
771
|
-
}
|
|
772
|
-
}
|
|
1092
|
+
try
|
|
1093
|
+
{
|
|
1094
|
+
winrt::hstring srcDirectoryPath, srcFileName;
|
|
1095
|
+
splitPath(src, srcDirectoryPath, srcFileName);
|
|
773
1096
|
|
|
1097
|
+
winrt::hstring destDirectoryPath, destFileName;
|
|
1098
|
+
splitPath(dest, destDirectoryPath, destFileName);
|
|
774
1099
|
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
std::string path,
|
|
778
|
-
winrt::Microsoft::ReactNative::ReactPromise<std::vector<std::string>> promise) noexcept
|
|
779
|
-
try
|
|
780
|
-
{
|
|
781
|
-
winrt::hstring directoryPath, fileName;
|
|
782
|
-
splitPath(path, directoryPath, fileName);
|
|
1100
|
+
StorageFolder srcFolder = co_await StorageFolder::GetFolderFromPathAsync(srcDirectoryPath);
|
|
1101
|
+
StorageFolder destFolder = co_await StorageFolder::GetFolderFromPathAsync(destDirectoryPath);
|
|
783
1102
|
|
|
784
|
-
|
|
1103
|
+
StorageFile file = co_await srcFolder.GetFileAsync(srcFileName);
|
|
1104
|
+
co_await file.CopyAsync(destFolder, destFileName, NameCollisionOption::FailIfExists);
|
|
785
1105
|
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
}
|
|
794
|
-
catch (const hresult_error& ex)
|
|
795
|
-
{
|
|
796
|
-
hresult result{ ex.code() };
|
|
797
|
-
if (result == 0x80070002) // FileNotFoundException
|
|
798
|
-
{
|
|
799
|
-
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "ENOTDIR", "Not a directory '" + path + "'" });
|
|
800
|
-
}
|
|
801
|
-
else
|
|
802
|
-
{
|
|
803
|
-
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "EUNSPECIFIED", winrt::to_string(ex.message()).c_str() });
|
|
804
|
-
}
|
|
1106
|
+
::React::JSValueArray success{};
|
|
1107
|
+
callback(std::move(success));
|
|
1108
|
+
}
|
|
1109
|
+
catch (const winrt::hresult_error& ex)
|
|
1110
|
+
{
|
|
1111
|
+
::React::JSValueArray error{ winrt::to_string(ex.message()) };
|
|
1112
|
+
callback(std::move(error));
|
|
1113
|
+
}
|
|
805
1114
|
}
|
|
806
1115
|
|
|
807
|
-
|
|
808
|
-
// mv
|
|
809
1116
|
winrt::fire_and_forget ReactNativeBlobUtil::mv(
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1117
|
+
std::string src,
|
|
1118
|
+
std::string dest,
|
|
1119
|
+
std::function<void(::React::JSValueArray)> callback) noexcept
|
|
813
1120
|
{
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
1121
|
+
try
|
|
1122
|
+
{
|
|
1123
|
+
winrt::hstring srcDirectoryPath, srcFileName;
|
|
1124
|
+
splitPath(src, srcDirectoryPath, srcFileName);
|
|
818
1125
|
|
|
819
|
-
|
|
820
|
-
|
|
1126
|
+
winrt::hstring destDirectoryPath, destFileName;
|
|
1127
|
+
splitPath(dest, destDirectoryPath, destFileName);
|
|
821
1128
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
StorageFile file{ co_await srcFolder.GetFileAsync(srcFileName) };
|
|
1129
|
+
StorageFolder srcFolder = co_await StorageFolder::GetFolderFromPathAsync(srcDirectoryPath);
|
|
1130
|
+
StorageFolder destFolder = co_await StorageFolder::GetFolderFromPathAsync(destDirectoryPath);
|
|
825
1131
|
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
}
|
|
829
|
-
catch (const hresult_error& ex)
|
|
830
|
-
{
|
|
831
|
-
hresult result{ ex.code() };
|
|
832
|
-
if (result == 0x80070002) // FileNotFoundException
|
|
833
|
-
{
|
|
834
|
-
callback("Source file not found.");
|
|
835
|
-
}
|
|
836
|
-
else
|
|
837
|
-
{
|
|
838
|
-
callback(winrt::to_string(ex.message()).c_str());
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
}
|
|
1132
|
+
StorageFile file = co_await srcFolder.GetFileAsync(srcFileName);
|
|
1133
|
+
co_await file.MoveAsync(destFolder, destFileName, NameCollisionOption::ReplaceExisting);
|
|
842
1134
|
|
|
1135
|
+
::React::JSValueArray success{}; // Success: empty array
|
|
1136
|
+
callback(std::move(success));
|
|
1137
|
+
}
|
|
1138
|
+
catch (const winrt::hresult_error& ex)
|
|
1139
|
+
{
|
|
1140
|
+
::React::JSValueArray error{ winrt::to_string(ex.message()) };
|
|
1141
|
+
callback(std::move(error));
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
843
1144
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
std::string dest, // to
|
|
848
|
-
std::function<void(std::string)> callback) noexcept
|
|
849
|
-
try
|
|
1145
|
+
void ReactNativeBlobUtil::mkdir(
|
|
1146
|
+
std::string path,
|
|
1147
|
+
::React::ReactPromise<bool>&& promise) noexcept
|
|
850
1148
|
{
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
1149
|
+
try
|
|
1150
|
+
{
|
|
1151
|
+
std::filesystem::path dirPath(path);
|
|
1152
|
+
dirPath.make_preferred();
|
|
1153
|
+
|
|
1154
|
+
// Consistent with Apple's createDirectoryAtPath method and result, but not with Android's
|
|
1155
|
+
std::error_code ec;
|
|
1156
|
+
bool created = std::filesystem::create_directories(dirPath, ec);
|
|
1157
|
+
if (!created && !std::filesystem::exists(dirPath))
|
|
1158
|
+
{
|
|
1159
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "ENOENT", "ENOENT: no such file or directory, open " + path });
|
|
1160
|
+
}
|
|
1161
|
+
else
|
|
1162
|
+
{
|
|
1163
|
+
promise.Resolve(true);
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
catch (const hresult_error& ex)
|
|
1167
|
+
{
|
|
1168
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "EUNSPECIFIED", "Error creating folder " + path + ", error: " + winrt::to_string(ex.message()) });
|
|
1169
|
+
}
|
|
864
1170
|
}
|
|
865
|
-
|
|
1171
|
+
|
|
1172
|
+
winrt::fire_and_forget ReactNativeBlobUtil::readFile(
|
|
1173
|
+
std::string path,
|
|
1174
|
+
std::string encoding,
|
|
1175
|
+
bool transformFile,
|
|
1176
|
+
::React::ReactPromise<::React::JSValueArray> promise) noexcept
|
|
866
1177
|
{
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
1178
|
+
try
|
|
1179
|
+
{
|
|
1180
|
+
winrt::hstring directoryPath, fileName;
|
|
1181
|
+
splitPath(path, directoryPath, fileName);
|
|
1182
|
+
|
|
1183
|
+
auto folder = co_await StorageFolder::GetFolderFromPathAsync(directoryPath);
|
|
1184
|
+
auto file = co_await folder.GetFileAsync(fileName);
|
|
1185
|
+
auto buffer = co_await FileIO::ReadBufferAsync(file);
|
|
1186
|
+
|
|
1187
|
+
::React::JSValueArray resultArray;
|
|
1188
|
+
if (encoding == "base64")
|
|
1189
|
+
{
|
|
1190
|
+
std::string base64Content = winrt::to_string(Cryptography::CryptographicBuffer::EncodeToBase64String(buffer));
|
|
1191
|
+
resultArray.push_back(base64Content);
|
|
1192
|
+
}
|
|
1193
|
+
else
|
|
1194
|
+
{
|
|
1195
|
+
std::string utf8Content = winrt::to_string(Cryptography::CryptographicBuffer::ConvertBinaryToString(BinaryStringEncoding::Utf8, buffer));
|
|
1196
|
+
if (encoding == "ascii")
|
|
1197
|
+
{
|
|
1198
|
+
// For ASCII, just return the utf8Content as a string
|
|
1199
|
+
resultArray.push_back(utf8Content);
|
|
1200
|
+
}
|
|
1201
|
+
else
|
|
1202
|
+
{
|
|
1203
|
+
resultArray.push_back(utf8Content);
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
promise.Resolve(resultArray);
|
|
1207
|
+
}
|
|
1208
|
+
catch (const winrt::hresult_error& ex)
|
|
1209
|
+
{
|
|
1210
|
+
hresult result{ ex.code() };
|
|
1211
|
+
if (result == 0x80070002) // FileNotFoundException
|
|
1212
|
+
{
|
|
1213
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "ENOENT", "ENOENT: no such file or directory, open " + path });
|
|
1214
|
+
}
|
|
1215
|
+
else if (result == 0x80070005) // UnauthorizedAccessException
|
|
1216
|
+
{
|
|
1217
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "EISDIR", "EISDIR: illegal operation on a directory, read" });
|
|
1218
|
+
}
|
|
1219
|
+
else
|
|
1220
|
+
{
|
|
1221
|
+
// "Failed to read file."
|
|
1222
|
+
promise.Reject(winrt::to_string(ex.message()).c_str());
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
873
1225
|
}
|
|
874
1226
|
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
std::function<void(bool, bool)> callback) noexcept
|
|
1227
|
+
winrt::fire_and_forget ReactNativeBlobUtil::hash(
|
|
1228
|
+
std::string path,
|
|
1229
|
+
std::string algorithm,
|
|
1230
|
+
::React::ReactPromise<std::string> promise) noexcept
|
|
880
1231
|
{
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
1232
|
+
try
|
|
1233
|
+
{
|
|
1234
|
+
// Note: SHA224 is not part of winrt
|
|
1235
|
+
if (algorithm.compare("sha224") == 0)
|
|
1236
|
+
{
|
|
1237
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "Error", "WinRT does not offer sha224 encryption." });
|
|
1238
|
+
co_return;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
winrt::hstring directoryPath, fileName;
|
|
1242
|
+
splitPath(path, directoryPath, fileName);
|
|
1243
|
+
|
|
1244
|
+
StorageFolder folder{ co_await StorageFolder::GetFolderFromPathAsync(directoryPath) };
|
|
1245
|
+
StorageFile file{ co_await folder.GetFileAsync(fileName) };
|
|
1246
|
+
|
|
1247
|
+
auto search{ availableHashes.find(algorithm) };
|
|
1248
|
+
if (search == availableHashes.end())
|
|
1249
|
+
{
|
|
1250
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "Error", "Invalid hash algorithm " + algorithm });
|
|
1251
|
+
co_return;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
CryptographyCore::HashAlgorithmProvider provider{ search->second() };
|
|
1255
|
+
Streams::IBuffer buffer{ co_await FileIO::ReadBufferAsync(file) };
|
|
1256
|
+
|
|
1257
|
+
auto hashedBuffer{ provider.HashData(buffer) };
|
|
1258
|
+
std::wstring result{ Cryptography::CryptographicBuffer::EncodeToHexString(hashedBuffer) };
|
|
1259
|
+
std::string sResult = winrt::to_string(result);
|
|
1260
|
+
promise.Resolve(sResult);
|
|
1261
|
+
}
|
|
1262
|
+
catch (const hresult_error& ex)
|
|
1263
|
+
{
|
|
1264
|
+
hresult result{ ex.code() };
|
|
1265
|
+
if (result == 0x80070002) // FileNotFoundException
|
|
1266
|
+
{
|
|
1267
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "ENOENT", "ENOENT: no such file or directory, open " + path });
|
|
1268
|
+
}
|
|
1269
|
+
else if (result == 0x80070005) // UnauthorizedAccessException
|
|
1270
|
+
{
|
|
1271
|
+
promise.Reject(winrt::Microsoft::ReactNative::ReactError{ "EISDIR", "EISDIR: illegal operation on a directory, read" });
|
|
1272
|
+
}
|
|
1273
|
+
else
|
|
1274
|
+
{
|
|
1275
|
+
// "Failed to get checksum from file."
|
|
1276
|
+
promise.Reject(winrt::to_string(ex.message()).c_str());
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
winrt::fire_and_forget ReactNativeBlobUtil::readStream(
|
|
1282
|
+
std::string path,
|
|
1283
|
+
std::string encoding,
|
|
1284
|
+
double bufferSize,
|
|
1285
|
+
double tick,
|
|
1286
|
+
std::string streamId) noexcept
|
|
1287
|
+
{
|
|
1288
|
+
try
|
|
1289
|
+
{
|
|
1290
|
+
EncodingOptions usedEncoding;
|
|
1291
|
+
if (encoding == "utf8")
|
|
1292
|
+
{
|
|
1293
|
+
usedEncoding = EncodingOptions::UTF8;
|
|
1294
|
+
}
|
|
1295
|
+
else if (encoding == "base64")
|
|
1296
|
+
{
|
|
1297
|
+
usedEncoding = EncodingOptions::BASE64;
|
|
1298
|
+
}
|
|
1299
|
+
else if (encoding == "ascii")
|
|
1300
|
+
{
|
|
1301
|
+
usedEncoding = EncodingOptions::ASCII;
|
|
1302
|
+
}
|
|
1303
|
+
else
|
|
1304
|
+
{
|
|
1305
|
+
// Invalid encoding
|
|
1306
|
+
m_reactContext.CallJSFunction(L"RCTDeviceEventEmitter", L"emit", streamId,
|
|
1307
|
+
winrt::Microsoft::ReactNative::JSValueObject{
|
|
1308
|
+
{"event", "error"},
|
|
1309
|
+
{"EINVAL", "Unsupported encoding: " + encoding}
|
|
1310
|
+
});
|
|
1311
|
+
co_return;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
uint32_t chunkSize = (usedEncoding == EncodingOptions::BASE64) ? 4095 : 4096;
|
|
1315
|
+
if (bufferSize > 0)
|
|
1316
|
+
{
|
|
1317
|
+
chunkSize = static_cast<uint32_t>(bufferSize);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
winrt::hstring directoryPath, fileName;
|
|
1321
|
+
splitPath(path, directoryPath, fileName);
|
|
1322
|
+
|
|
1323
|
+
StorageFolder folder = co_await StorageFolder::GetFolderFromPathAsync(directoryPath);
|
|
1324
|
+
StorageFile file = co_await folder.GetFileAsync(fileName);
|
|
1325
|
+
Streams::IRandomAccessStream stream = co_await file.OpenAsync(FileAccessMode::Read);
|
|
1326
|
+
|
|
1327
|
+
Buffer buffer{ chunkSize };
|
|
1328
|
+
|
|
1329
|
+
for (;;)
|
|
1330
|
+
{
|
|
1331
|
+
auto readBuffer = co_await stream.ReadAsync(buffer, buffer.Capacity(), InputStreamOptions::None);
|
|
1332
|
+
if (readBuffer.Length() == 0)
|
|
1333
|
+
{
|
|
1334
|
+
m_reactContext.CallJSFunction(L"RCTDeviceEventEmitter", L"emit", streamId,
|
|
1335
|
+
winrt::Microsoft::ReactNative::JSValueObject{
|
|
1336
|
+
{"event", "end"}
|
|
1337
|
+
});
|
|
1338
|
+
break;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
if (usedEncoding == EncodingOptions::BASE64)
|
|
1342
|
+
{
|
|
1343
|
+
winrt::hstring base64Content = Cryptography::CryptographicBuffer::EncodeToBase64String(readBuffer);
|
|
1344
|
+
m_reactContext.CallJSFunction(L"RCTDeviceEventEmitter", L"emit", streamId,
|
|
1345
|
+
winrt::Microsoft::ReactNative::JSValueObject{
|
|
1346
|
+
{"event", "data"},
|
|
1347
|
+
{"detail", winrt::to_string(base64Content)}
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
else
|
|
1351
|
+
{
|
|
1352
|
+
winrt::hstring stringContent = Cryptography::CryptographicBuffer::ConvertBinaryToString(
|
|
1353
|
+
BinaryStringEncoding::Utf8, readBuffer);
|
|
1354
|
+
std::string utf8Content = winrt::to_string(stringContent);
|
|
1355
|
+
|
|
1356
|
+
// For ASCII, trim to 7-bit range
|
|
1357
|
+
if (usedEncoding == EncodingOptions::ASCII)
|
|
1358
|
+
{
|
|
1359
|
+
for (char& c : utf8Content)
|
|
1360
|
+
{
|
|
1361
|
+
c &= 0x7F;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
m_reactContext.CallJSFunction(L"RCTDeviceEventEmitter", L"emit", streamId,
|
|
1366
|
+
winrt::Microsoft::ReactNative::JSValueObject{
|
|
1367
|
+
{"event", "data"},
|
|
1368
|
+
{"detail", utf8Content}
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
if (tick > 0)
|
|
1373
|
+
{
|
|
1374
|
+
std::this_thread::sleep_for(std::chrono::milliseconds(static_cast<int64_t>(tick)));
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
catch (const hresult_error& ex)
|
|
1379
|
+
{
|
|
1380
|
+
hresult result = ex.code();
|
|
1381
|
+
if (result == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) // 0x80070002
|
|
1382
|
+
{
|
|
1383
|
+
m_reactContext.CallJSFunction(L"RCTDeviceEventEmitter", L"emit", streamId,
|
|
1384
|
+
winrt::Microsoft::ReactNative::JSValueObject{
|
|
1385
|
+
{"event", "error"},
|
|
1386
|
+
{"ENOENT", "No such file: " + path}
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
else
|
|
1390
|
+
{
|
|
1391
|
+
m_reactContext.CallJSFunction(L"RCTDeviceEventEmitter", L"emit", streamId,
|
|
1392
|
+
winrt::Microsoft::ReactNative::JSValueObject{
|
|
1393
|
+
{"event", "error"},
|
|
1394
|
+
{"EUNSPECIFIED", winrt::to_string(ex.message())}
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
void ReactNativeBlobUtil::getEnvironmentDirs(
|
|
1401
|
+
std::function<void(::React::JSValueArray const&)> const& callback) noexcept
|
|
1402
|
+
{
|
|
1403
|
+
callback(::React::JSValueArray{});
|
|
886
1404
|
}
|
|
887
1405
|
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
std::string path,
|
|
892
|
-
std::function<void(std::string, bool)> callback) noexcept
|
|
893
|
-
try
|
|
1406
|
+
void ReactNativeBlobUtil::cancelRequest(
|
|
1407
|
+
std::string taskId,
|
|
1408
|
+
std::function<void(::React::JSValueArray const&)> const& callback) noexcept
|
|
894
1409
|
{
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
co_await target.DeleteAsync();
|
|
909
|
-
}
|
|
910
|
-
callback("", true);
|
|
1410
|
+
::React::JSValueArray resultArray;
|
|
1411
|
+
try
|
|
1412
|
+
{
|
|
1413
|
+
m_tasks.Cancel(taskId);
|
|
1414
|
+
// Success: return empty array
|
|
1415
|
+
callback(resultArray);
|
|
1416
|
+
}
|
|
1417
|
+
catch (const winrt::hresult_error& ex)
|
|
1418
|
+
{
|
|
1419
|
+
resultArray.push_back("EUNSPECIFIED");
|
|
1420
|
+
resultArray.push_back(winrt::to_string(ex.message()));
|
|
1421
|
+
callback(resultArray);
|
|
1422
|
+
}
|
|
911
1423
|
}
|
|
912
|
-
|
|
1424
|
+
|
|
1425
|
+
void ReactNativeBlobUtil::enableProgressReport(
|
|
1426
|
+
std::string taskId,
|
|
1427
|
+
double interval,
|
|
1428
|
+
double count) noexcept
|
|
913
1429
|
{
|
|
914
|
-
|
|
1430
|
+
ReactNativeBlobUtilProgressConfig config{ count, interval };
|
|
1431
|
+
std::scoped_lock lock{ m_mutex };
|
|
1432
|
+
downloadProgressMap.try_emplace(taskId, config);
|
|
915
1433
|
}
|
|
916
1434
|
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
std::function<void(std::string, winrt::Microsoft::ReactNative::JSValueArray&)> callback) noexcept
|
|
922
|
-
try
|
|
1435
|
+
void ReactNativeBlobUtil::enableUploadProgressReport(
|
|
1436
|
+
std::string taskId,
|
|
1437
|
+
double interval,
|
|
1438
|
+
double count) noexcept
|
|
923
1439
|
{
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
winrt::Microsoft::ReactNative::JSValueArray resultsArray;
|
|
929
|
-
|
|
930
|
-
auto items{ co_await targetDirectory.GetItemsAsync() };
|
|
931
|
-
for (auto item : items)
|
|
932
|
-
{
|
|
933
|
-
auto properties{ co_await item.GetBasicPropertiesAsync() };
|
|
934
|
-
|
|
935
|
-
winrt::Microsoft::ReactNative::JSValueObject itemInfo;
|
|
936
|
-
|
|
937
|
-
itemInfo["filename"] = to_string(item.Name());
|
|
938
|
-
itemInfo["path"] = to_string(item.Path());
|
|
939
|
-
itemInfo["size"] = properties.Size();
|
|
940
|
-
itemInfo["type"] = item.IsOfType(StorageItemTypes::Folder) ? "directory" : "file";
|
|
941
|
-
itemInfo["lastModified"] = properties.DateModified().time_since_epoch() / std::chrono::seconds(1) - UNIX_EPOCH_IN_WINRT_SECONDS;
|
|
942
|
-
|
|
943
|
-
resultsArray.push_back(std::move(itemInfo));
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
callback("", resultsArray);
|
|
1440
|
+
ReactNativeBlobUtilProgressConfig config{ count, interval };
|
|
1441
|
+
std::scoped_lock lock{ m_mutex };
|
|
1442
|
+
uploadProgressMap.try_emplace(taskId, config);
|
|
947
1443
|
}
|
|
948
|
-
|
|
1444
|
+
|
|
1445
|
+
winrt::fire_and_forget ReactNativeBlobUtil::slice(
|
|
1446
|
+
std::string src,
|
|
1447
|
+
std::string dest,
|
|
1448
|
+
double start,
|
|
1449
|
+
double end,
|
|
1450
|
+
::React::ReactPromise<std::string> promise) noexcept
|
|
949
1451
|
{
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1452
|
+
try
|
|
1453
|
+
{
|
|
1454
|
+
winrt::hstring srcDirectoryPath, srcFileName, destDirectoryPath, destFileName;
|
|
1455
|
+
splitPath(src, srcDirectoryPath, srcFileName);
|
|
1456
|
+
splitPath(src, destDirectoryPath, destFileName);
|
|
1457
|
+
|
|
1458
|
+
StorageFolder srcFolder{ co_await StorageFolder::GetFolderFromPathAsync(srcDirectoryPath) };
|
|
1459
|
+
StorageFolder destFolder{ co_await StorageFolder::GetFolderFromPathAsync(destDirectoryPath) };
|
|
1460
|
+
|
|
1461
|
+
StorageFile srcFile{ co_await srcFolder.GetFileAsync(srcFileName) };
|
|
1462
|
+
StorageFile destFile{ co_await destFolder.CreateFileAsync(destFileName, CreationCollisionOption::OpenIfExists) };
|
|
1463
|
+
|
|
1464
|
+
uint64_t uStart = static_cast<uint64_t>(start);
|
|
1465
|
+
uint64_t uEnd = static_cast<uint64_t>(end);
|
|
1466
|
+
uint32_t length = static_cast<uint32_t>(uEnd > uStart ? uEnd - uStart : 0);
|
|
1467
|
+
|
|
1468
|
+
if (length == 0) {
|
|
1469
|
+
promise.Reject("Invalid slice range");
|
|
1470
|
+
co_return;
|
|
1471
|
+
}
|
|
1472
|
+
Streams::IBuffer buffer;
|
|
1473
|
+
Streams::IRandomAccessStream stream{ co_await srcFile.OpenAsync(FileAccessMode::Read) };
|
|
1474
|
+
stream.Seek(start);
|
|
1475
|
+
stream.ReadAsync(buffer, length, Streams::InputStreamOptions::None);
|
|
1476
|
+
co_await FileIO::WriteBufferAsync(destFile, buffer);
|
|
1477
|
+
|
|
1478
|
+
promise.Resolve(dest);
|
|
1479
|
+
}
|
|
1480
|
+
catch (...)
|
|
1481
|
+
{
|
|
1482
|
+
promise.Reject("Unable to slice file");
|
|
1483
|
+
}
|
|
953
1484
|
}
|
|
954
1485
|
|
|
1486
|
+
IAsyncAction setTimeout(std::chrono::seconds time) {
|
|
1487
|
+
co_await time;
|
|
1488
|
+
}
|
|
955
1489
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
try
|
|
1490
|
+
void ReactNativeBlobUtil::presentOptionsMenu(
|
|
1491
|
+
std::string uri,
|
|
1492
|
+
std::string scheme,
|
|
1493
|
+
::React::ReactPromise<::React::JSValueArray>&& result) noexcept
|
|
961
1494
|
{
|
|
962
|
-
|
|
963
|
-
givenPath.make_preferred();
|
|
964
|
-
bool isDirectory{ std::filesystem::is_directory(path) };
|
|
965
|
-
|
|
966
|
-
//std::string resultPath{ winrt::to_string(givenPath.c_str()) };
|
|
967
|
-
auto resultPath{ winrt::to_hstring(givenPath.c_str()) };
|
|
968
|
-
|
|
969
|
-
// Try to open as folder
|
|
970
|
-
IStorageItem item;
|
|
971
|
-
if (isDirectory) {
|
|
972
|
-
item = co_await StorageFolder::GetFolderFromPathAsync(resultPath);
|
|
973
|
-
}
|
|
974
|
-
else {
|
|
975
|
-
item = co_await StorageFile::GetFileFromPathAsync(resultPath);
|
|
976
|
-
}
|
|
977
|
-
auto properties{ co_await item.GetBasicPropertiesAsync() };
|
|
978
|
-
winrt::Microsoft::ReactNative::JSValueObject fileInfo;
|
|
979
|
-
fileInfo["size"] = properties.Size();
|
|
980
|
-
fileInfo["filename"] = givenPath.filename().string();
|
|
981
|
-
fileInfo["path"] = givenPath.string();
|
|
982
|
-
fileInfo["lastModified"] = winrt::clock::to_time_t(properties.DateModified());;
|
|
983
|
-
fileInfo["type"] = isDirectory ? "directory" : "file";
|
|
984
|
-
|
|
985
|
-
callback("", fileInfo);
|
|
1495
|
+
result.Resolve(::React::JSValueArray{});
|
|
986
1496
|
}
|
|
987
|
-
|
|
1497
|
+
|
|
1498
|
+
void ReactNativeBlobUtil::presentOpenInMenu(
|
|
1499
|
+
std::string uri,
|
|
1500
|
+
std::string scheme,
|
|
1501
|
+
::React::ReactPromise<::React::JSValueArray>&& result) noexcept
|
|
988
1502
|
{
|
|
989
|
-
|
|
990
|
-
callback(winrt::to_string(ex.message()).c_str(), emptyObject);
|
|
1503
|
+
result.Resolve(::React::JSValueArray{});
|
|
991
1504
|
}
|
|
992
1505
|
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
try
|
|
1506
|
+
void ReactNativeBlobUtil::presentPreview(
|
|
1507
|
+
std::string uri,
|
|
1508
|
+
std::string scheme,
|
|
1509
|
+
::React::ReactPromise<::React::JSValueArray>&& result) noexcept
|
|
998
1510
|
{
|
|
999
|
-
|
|
1000
|
-
auto properties{ co_await localFolder.Properties().RetrievePropertiesAsync({L"System.FreeSpace", L"System.Capacity"}) };
|
|
1001
|
-
|
|
1002
|
-
winrt::Microsoft::ReactNative::JSValueObject result;
|
|
1003
|
-
result["free"] = unbox_value<uint64_t>(properties.Lookup(L"System.FreeSpace"));
|
|
1004
|
-
result["total"] = unbox_value<uint64_t>(properties.Lookup(L"System.Capacity"));
|
|
1005
|
-
callback("", result);
|
|
1511
|
+
result.Resolve(::React::JSValueArray{});
|
|
1006
1512
|
}
|
|
1007
|
-
|
|
1513
|
+
|
|
1514
|
+
void ReactNativeBlobUtil::excludeFromBackupKey(
|
|
1515
|
+
std::string url,
|
|
1516
|
+
::React::ReactPromise<::React::JSValueArray>&& result) noexcept
|
|
1008
1517
|
{
|
|
1009
|
-
|
|
1010
|
-
callback("Failed to get storage usage.", emptyObject);
|
|
1518
|
+
result.Resolve(::React::JSValueArray{});
|
|
1011
1519
|
}
|
|
1012
1520
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1521
|
+
winrt::fire_and_forget ReactNativeBlobUtil::df(
|
|
1522
|
+
std::function<void(::React::JSValueArray)> callback) noexcept
|
|
1523
|
+
{
|
|
1524
|
+
try
|
|
1525
|
+
{
|
|
1526
|
+
auto localFolder = winrt::Windows::Storage::ApplicationData::Current().LocalFolder();
|
|
1527
|
+
auto properties{ co_await localFolder.Properties().RetrievePropertiesAsync({L"System.FreeSpace", L"System.Capacity"}) };
|
|
1528
|
+
|
|
1529
|
+
winrt::Microsoft::ReactNative::JSValueObject result;
|
|
1530
|
+
result["free"] = winrt::unbox_value<uint64_t>(properties.Lookup(L"System.FreeSpace"));
|
|
1531
|
+
result["total"] = winrt::unbox_value<uint64_t>(properties.Lookup(L"System.Capacity"));
|
|
1532
|
+
|
|
1533
|
+
::React::JSValueArray arr;
|
|
1534
|
+
arr.push_back(::React::JSValueObject(std::move(result)));
|
|
1535
|
+
callback(std::move(arr));
|
|
1536
|
+
}
|
|
1537
|
+
catch (...)
|
|
1538
|
+
{
|
|
1539
|
+
::React::JSValueArray arr;
|
|
1540
|
+
winrt::Microsoft::ReactNative::JSValueObject error;
|
|
1541
|
+
error["error"] = "Failed to get storage usage.";
|
|
1542
|
+
arr.push_back(::React::JSValueObject(std::move(error)));
|
|
1543
|
+
callback(std::move(arr));
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
void ReactNativeBlobUtil::emitExpiredEvent(
|
|
1549
|
+
std::function<void(std::string)> const& callback) noexcept
|
|
1021
1550
|
{
|
|
1022
|
-
|
|
1023
|
-
splitPath(src, srcDirectoryPath, srcFileName);
|
|
1024
|
-
splitPath(src, destDirectoryPath, destFileName);
|
|
1025
|
-
|
|
1026
|
-
StorageFolder srcFolder{ co_await StorageFolder::GetFolderFromPathAsync(srcDirectoryPath) };
|
|
1027
|
-
StorageFolder destFolder{ co_await StorageFolder::GetFolderFromPathAsync(destDirectoryPath) };
|
|
1028
|
-
|
|
1029
|
-
StorageFile srcFile{ co_await srcFolder.GetFileAsync(srcFileName) };
|
|
1030
|
-
StorageFile destFile{ co_await destFolder.CreateFileAsync(destFileName, CreationCollisionOption::OpenIfExists) };
|
|
1031
|
-
|
|
1032
|
-
uint32_t length{ end - start };
|
|
1033
|
-
Streams::IBuffer buffer;
|
|
1034
|
-
Streams::IRandomAccessStream stream{ co_await srcFile.OpenAsync(FileAccessMode::Read) };
|
|
1035
|
-
stream.Seek(start);
|
|
1036
|
-
stream.ReadAsync(buffer, length, Streams::InputStreamOptions::None);
|
|
1037
|
-
co_await FileIO::WriteBufferAsync(destFile, buffer);
|
|
1038
|
-
|
|
1039
|
-
promise.Resolve(dest);
|
|
1551
|
+
callback("");
|
|
1040
1552
|
}
|
|
1041
|
-
|
|
1553
|
+
|
|
1554
|
+
void ReactNativeBlobUtil::actionViewIntent(
|
|
1555
|
+
std::string path,
|
|
1556
|
+
std::string mime,
|
|
1557
|
+
std::string chooserTitle,
|
|
1558
|
+
::React::ReactPromise<void>&& result) noexcept
|
|
1042
1559
|
{
|
|
1043
|
-
|
|
1560
|
+
// No-op: Android API
|
|
1561
|
+
result.Resolve();
|
|
1044
1562
|
}
|
|
1045
1563
|
|
|
1564
|
+
void ReactNativeBlobUtil::addCompleteDownload(
|
|
1565
|
+
::React::JSValue&& config,
|
|
1566
|
+
::React::ReactPromise<void>&& result) noexcept
|
|
1567
|
+
{
|
|
1568
|
+
// No-op: Android API
|
|
1569
|
+
result.Resolve();
|
|
1570
|
+
}
|
|
1046
1571
|
|
|
1047
|
-
|
|
1048
|
-
|
|
1572
|
+
void ReactNativeBlobUtil::copyToInternal(
|
|
1573
|
+
std::string contentUri,
|
|
1574
|
+
std::string destpath,
|
|
1575
|
+
::React::ReactPromise<std::string>&& result) noexcept
|
|
1576
|
+
{
|
|
1577
|
+
// No-op: Android API
|
|
1578
|
+
result.Resolve("");
|
|
1049
1579
|
}
|
|
1050
1580
|
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
winrt::Microsoft::ReactNative::JSValueObject headers,
|
|
1057
|
-
std::string body,
|
|
1058
|
-
std::function<void(std::string, std::string, std::string)> callback) noexcept
|
|
1581
|
+
void ReactNativeBlobUtil::copyToMediaStore(
|
|
1582
|
+
::React::JSValue&& filedata,
|
|
1583
|
+
std::string mt,
|
|
1584
|
+
std::string path,
|
|
1585
|
+
::React::ReactPromise<std::string>&& result) noexcept
|
|
1059
1586
|
{
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
filter.AllowAutoRedirect(false);
|
|
1063
|
-
if (config.trusty)
|
|
1064
|
-
{
|
|
1065
|
-
filter.IgnorableServerCertificateErrors().Append(Cryptography::Certificates::ChainValidationResult::Untrusted);
|
|
1066
|
-
}
|
|
1067
|
-
ReactNativeBlobUtilState eventState;
|
|
1068
|
-
|
|
1069
|
-
winrt::Windows::Web::Http::HttpClient httpClient{ filter };
|
|
1070
|
-
|
|
1071
|
-
winrt::Windows::Web::Http::HttpMethod httpMethod{ winrt::Windows::Web::Http::HttpMethod::Post() };
|
|
1072
|
-
// Delete, Patch, Post, Put, Get, Options, Head
|
|
1073
|
-
if (method.compare("DELETE") == 0 || method.compare("delete") == 0)
|
|
1074
|
-
{
|
|
1075
|
-
httpMethod = winrt::Windows::Web::Http::HttpMethod::Delete();
|
|
1076
|
-
}
|
|
1077
|
-
else if (method.compare("PUT") == 0 || method.compare("put") == 0)
|
|
1078
|
-
{
|
|
1079
|
-
httpMethod = winrt::Windows::Web::Http::HttpMethod::Put();
|
|
1080
|
-
}
|
|
1081
|
-
else if (method.compare("GET") == 0 || method.compare("get") == 0)
|
|
1082
|
-
{
|
|
1083
|
-
httpMethod = winrt::Windows::Web::Http::HttpMethod::Get();
|
|
1084
|
-
}
|
|
1085
|
-
else
|
|
1086
|
-
{
|
|
1087
|
-
callback("Method not supported", "error", "");
|
|
1088
|
-
co_return;
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
winrt::Windows::Web::Http::HttpRequestMessage requestMessage{ httpMethod, Uri{url} };
|
|
1092
|
-
bool pathToFile{ body.rfind(prefix, 0) == 0 };
|
|
1093
|
-
if (pathToFile)
|
|
1094
|
-
{
|
|
1095
|
-
std::string contentPath{ body.substr(prefix.length()) };
|
|
1096
|
-
size_t fileLength = contentPath.length();
|
|
1097
|
-
bool hasTrailingSlash{ contentPath[fileLength - 1] == '\\' || contentPath[fileLength - 1] == '/' };
|
|
1098
|
-
winrt::hstring directoryPath, fileName;
|
|
1099
|
-
splitPath(hasTrailingSlash ? contentPath.substr(0, fileLength - 1) : contentPath, directoryPath, fileName);
|
|
1100
|
-
StorageFolder folder{ co_await StorageFolder::GetFolderFromPathAsync(directoryPath) };
|
|
1101
|
-
StorageFile storageFile{ co_await folder.CreateFileAsync(fileName, CreationCollisionOption::OpenIfExists) };
|
|
1102
|
-
IBuffer requestBuffer{ co_await FileIO::ReadBufferAsync(storageFile) };
|
|
1103
|
-
|
|
1104
|
-
winrt::Windows::Web::Http::HttpBufferContent requestContent{ requestBuffer };
|
|
1105
|
-
|
|
1106
|
-
for (auto const& entry : headers)
|
|
1107
|
-
{
|
|
1108
|
-
if (!requestMessage.Headers().TryAppendWithoutValidation(winrt::to_hstring(entry.first), winrt::to_hstring(entry.second.AsString())))
|
|
1109
|
-
{
|
|
1110
|
-
requestContent.Headers().TryAppendWithoutValidation(winrt::to_hstring(entry.first), winrt::to_hstring(entry.second.AsString()));
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
requestMessage.Content(requestContent);
|
|
1114
|
-
}
|
|
1115
|
-
else if (!body.empty()) {
|
|
1116
|
-
winrt::Windows::Web::Http::HttpStringContent requestString{ winrt::to_hstring(body) };
|
|
1117
|
-
|
|
1118
|
-
for (auto const& entry : headers)
|
|
1119
|
-
{
|
|
1120
|
-
if (!requestMessage.Headers().TryAppendWithoutValidation(winrt::to_hstring(entry.first), winrt::to_hstring(entry.second.AsString())))
|
|
1121
|
-
{
|
|
1122
|
-
requestString.Headers().TryAppendWithoutValidation(winrt::to_hstring(entry.first), winrt::to_hstring(entry.second.AsString()));
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
requestMessage.Content(requestString);
|
|
1126
|
-
}
|
|
1127
|
-
else {
|
|
1128
|
-
for (auto const& entry : headers)
|
|
1129
|
-
{
|
|
1130
|
-
requestMessage.Headers().TryAppendWithoutValidation(winrt::to_hstring(entry.first), winrt::to_hstring(entry.second.AsString()));
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
auto exists{ uploadProgressMap.find(taskId) };
|
|
1135
|
-
if (exists != uploadProgressMap.end()) {
|
|
1136
|
-
auto progress{ uploadProgressMap[taskId] };
|
|
1137
|
-
uint64_t bodySize{ (co_await requestMessage.Content().ReadAsBufferAsync()).Length() };
|
|
1138
|
-
auto contentStream{ co_await requestMessage.Content().ReadAsInputStreamAsync() };
|
|
1139
|
-
Buffer buffer{ 10 * 1024 };
|
|
1140
|
-
uint64_t read{ 0 };
|
|
1141
|
-
|
|
1142
|
-
if (progress.count > -1) {
|
|
1143
|
-
uint64_t progressInterval{ bodySize / 100 * progress.count };
|
|
1144
|
-
for (;;) {
|
|
1145
|
-
|
|
1146
|
-
buffer.Length(0);
|
|
1147
|
-
auto readBuffer = co_await contentStream.ReadAsync(buffer, buffer.Capacity(), InputStreamOptions::None);
|
|
1148
|
-
read += readBuffer.Length();
|
|
1149
|
-
|
|
1150
|
-
if (readBuffer.Length() == 0)
|
|
1151
|
-
{
|
|
1152
|
-
break;
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
if (read >= progressInterval) {
|
|
1156
|
-
m_reactContext.CallJSFunction(L"RCTDeviceEventEmitter", L"emit", L"ReactNativeBlobUtilProgress-upload",
|
|
1157
|
-
Microsoft::ReactNative::JSValueObject{
|
|
1158
|
-
{ "taskId", taskId },
|
|
1159
|
-
{ "written", read },
|
|
1160
|
-
{ "total", bodySize },
|
|
1161
|
-
});
|
|
1162
|
-
read = 0;
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
else if (progress.interval > -1) {
|
|
1167
|
-
int64_t initialProgressTime{ winrt::clock::now().time_since_epoch().count() / 10000 };
|
|
1168
|
-
int64_t currentProgressTime;
|
|
1169
|
-
for (;;) {
|
|
1170
|
-
buffer.Length(0);
|
|
1171
|
-
|
|
1172
|
-
auto readBuffer = co_await contentStream.ReadAsync(buffer, buffer.Capacity(), InputStreamOptions::None);
|
|
1173
|
-
read += readBuffer.Length();
|
|
1174
|
-
|
|
1175
|
-
if (readBuffer.Length() == 0)
|
|
1176
|
-
{
|
|
1177
|
-
break;
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
currentProgressTime = winrt::clock::now().time_since_epoch().count() / 10000;
|
|
1181
|
-
if (currentProgressTime - initialProgressTime >= progress.interval) {
|
|
1182
|
-
m_reactContext.CallJSFunction(L"RCTDeviceEventEmitter", L"emit", L"ReactNativeBlobUtilProgress-upload",
|
|
1183
|
-
Microsoft::ReactNative::JSValueObject{
|
|
1184
|
-
{ "taskId", taskId },
|
|
1185
|
-
{ "written", read },
|
|
1186
|
-
{ "total", bodySize },
|
|
1187
|
-
});
|
|
1188
|
-
initialProgressTime = winrt::clock::now().time_since_epoch().count() / 10000;
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
std::string error;
|
|
1195
|
-
auto cancellationTimer{ setTimeout(config.timeout) };
|
|
1196
|
-
cancellationTimer.Completed([weak_this = weak_from_this(), taskId, error](IAsyncAction const& action, AsyncStatus status) {
|
|
1197
|
-
if (status == AsyncStatus::Completed) {
|
|
1198
|
-
auto strong_this{ weak_this.lock() };
|
|
1199
|
-
if (strong_this) {
|
|
1200
|
-
strong_this->m_tasks.Cancel(taskId);
|
|
1201
|
-
{
|
|
1202
|
-
std::scoped_lock lock{ strong_this->m_mutex };
|
|
1203
|
-
strong_this->uploadProgressMap.extract(taskId);
|
|
1204
|
-
strong_this->downloadProgressMap.extract(taskId);
|
|
1205
|
-
}
|
|
1206
|
-
}
|
|
1207
|
-
}
|
|
1208
|
-
});
|
|
1209
|
-
try {
|
|
1210
|
-
co_await m_tasks.Add(taskId, ProcessRequestAsync(taskId, filter, requestMessage, config, callback, error));
|
|
1211
|
-
}
|
|
1212
|
-
catch (...) {
|
|
1213
|
-
|
|
1214
|
-
}
|
|
1215
|
-
if (!error.empty()) {
|
|
1216
|
-
if (cancellationTimer.Status() != AsyncStatus::Completed) {
|
|
1217
|
-
callback(error, "error", "");
|
|
1218
|
-
}
|
|
1219
|
-
else {
|
|
1220
|
-
callback("React-native-blobl-util request timed out", "error", "");
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
cancellationTimer.Cancel();
|
|
1225
|
-
m_tasks.Cancel(taskId);
|
|
1226
|
-
{
|
|
1227
|
-
std::scoped_lock lock{ m_mutex };
|
|
1228
|
-
uploadProgressMap.extract(taskId);
|
|
1229
|
-
downloadProgressMap.extract(taskId);
|
|
1230
|
-
}
|
|
1587
|
+
// No-op: Android API
|
|
1588
|
+
result.Resolve("");
|
|
1231
1589
|
}
|
|
1232
1590
|
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
std::wstring url,
|
|
1238
|
-
winrt::Microsoft::ReactNative::JSValueObject headers,
|
|
1239
|
-
winrt::Microsoft::ReactNative::JSValueArray body,
|
|
1240
|
-
std::function<void(std::string, std::string, std::string)> callback) noexcept
|
|
1591
|
+
void ReactNativeBlobUtil::createMediaFile(
|
|
1592
|
+
::React::JSValue&& filedata,
|
|
1593
|
+
std::string mt,
|
|
1594
|
+
::React::ReactPromise<std::string>&& result) noexcept
|
|
1241
1595
|
{
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
ReactNativeBlobUtilConfig config{ options };
|
|
1246
|
-
|
|
1247
|
-
filter.AllowAutoRedirect(false);
|
|
1248
|
-
|
|
1249
|
-
if (config.trusty)
|
|
1250
|
-
{
|
|
1251
|
-
filter.IgnorableServerCertificateErrors().Append(Cryptography::Certificates::ChainValidationResult::Untrusted);
|
|
1252
|
-
}
|
|
1253
|
-
|
|
1254
|
-
winrt::Windows::Web::Http::HttpClient httpClient{ filter };
|
|
1255
|
-
|
|
1256
|
-
winrt::Windows::Web::Http::HttpMethod httpMethod{ winrt::Windows::Web::Http::HttpMethod::Post() };
|
|
1257
|
-
// Delete, Patch, Post, Put, Get, Options, Head
|
|
1258
|
-
if (method.compare("DELETE") == 0 || method.compare("delete") == 0)
|
|
1259
|
-
{
|
|
1260
|
-
httpMethod = winrt::Windows::Web::Http::HttpMethod::Delete();
|
|
1261
|
-
}
|
|
1262
|
-
else if (method.compare("PUT") == 0 || method.compare("put") == 0)
|
|
1263
|
-
{
|
|
1264
|
-
httpMethod = winrt::Windows::Web::Http::HttpMethod::Put();
|
|
1265
|
-
}
|
|
1266
|
-
else if (method.compare("GET") == 0 || method.compare("get") == 0)
|
|
1267
|
-
{
|
|
1268
|
-
httpMethod = winrt::Windows::Web::Http::HttpMethod::Get();
|
|
1269
|
-
}
|
|
1270
|
-
else if (method.compare("POST") != 0 && method.compare("post") != 0)
|
|
1271
|
-
{
|
|
1272
|
-
callback("Method not supported", "error", "");
|
|
1273
|
-
co_return;
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
|
-
winrt::Windows::Web::Http::HttpRequestMessage requestMessage{ httpMethod, Uri{url} };
|
|
1277
|
-
winrt::Windows::Web::Http::HttpMultipartFormDataContent requestContent{ boundary };
|
|
1278
|
-
|
|
1279
|
-
for (auto const& entry : headers)
|
|
1280
|
-
{
|
|
1281
|
-
if (!requestMessage.Headers().TryAppendWithoutValidation(winrt::to_hstring(entry.first), winrt::to_hstring(entry.second.AsString())))
|
|
1282
|
-
{
|
|
1283
|
-
requestContent.Headers().TryAppendWithoutValidation(winrt::to_hstring(entry.first), winrt::to_hstring(entry.second.AsString()));
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
|
|
1287
|
-
for (auto& entry : body) {
|
|
1288
|
-
auto& items{ entry.AsObject() };
|
|
1289
|
-
|
|
1290
|
-
auto data{ items["data"].AsString() };
|
|
1291
|
-
bool pathToFile{ data.rfind(prefix, 0) == 0 };
|
|
1292
|
-
if (pathToFile)
|
|
1293
|
-
{
|
|
1294
|
-
std::string contentPath{ data.substr(prefix.length()) };
|
|
1295
|
-
size_t fileLength = contentPath.length();
|
|
1296
|
-
bool hasTrailingSlash{ contentPath[fileLength - 1] == '\\' || contentPath[fileLength - 1] == '/' };
|
|
1297
|
-
winrt::hstring directoryPath, fileName;
|
|
1298
|
-
splitPath(hasTrailingSlash ? contentPath.substr(0, fileLength - 1) : contentPath, directoryPath, fileName);
|
|
1299
|
-
StorageFolder folder{ co_await StorageFolder::GetFolderFromPathAsync(directoryPath) };
|
|
1300
|
-
StorageFile storageFile = co_await folder.CreateFileAsync(fileName, CreationCollisionOption::OpenIfExists);
|
|
1301
|
-
IBuffer requestBuffer{ co_await FileIO::ReadBufferAsync(storageFile) };
|
|
1302
|
-
|
|
1303
|
-
winrt::Windows::Web::Http::HttpBufferContent requestBufferContent{ requestBuffer };
|
|
1304
|
-
|
|
1305
|
-
if (!items["type"].IsNull()) {
|
|
1306
|
-
requestBufferContent.Headers().TryAppendWithoutValidation(L"content-type", winrt::to_hstring(items["type"].AsString()));
|
|
1307
|
-
}
|
|
1308
|
-
|
|
1309
|
-
auto name{ items["name"].IsNull() ? L"" : winrt::to_hstring(items["name"].AsString()) };
|
|
1310
|
-
if (name.size() <= 0) {
|
|
1311
|
-
requestContent.Add(requestBufferContent);
|
|
1312
|
-
continue;
|
|
1313
|
-
}
|
|
1314
|
-
auto filename{ items["filename"].IsNull() ? L"" : winrt::to_hstring(items["filename"].AsString()) };
|
|
1315
|
-
if (filename.size() <= 0) {
|
|
1316
|
-
requestContent.Add(requestBufferContent, name);
|
|
1317
|
-
}
|
|
1318
|
-
else {
|
|
1319
|
-
requestContent.Add(requestBufferContent, name, filename);
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
else {
|
|
1323
|
-
winrt::Windows::Web::Http::HttpStringContent dataContents{ winrt::to_hstring(data) };
|
|
1324
|
-
if (!items["type"].IsNull()) {
|
|
1325
|
-
dataContents.Headers().TryAppendWithoutValidation(L"content-type", winrt::to_hstring(items["type"].AsString()));
|
|
1326
|
-
}
|
|
1327
|
-
|
|
1328
|
-
auto name{ items["name"].IsNull() ? L"" : winrt::to_hstring(items["name"].AsString()) };
|
|
1329
|
-
if (name.size() <= 0) {
|
|
1330
|
-
requestContent.Add(dataContents);
|
|
1331
|
-
continue;
|
|
1332
|
-
}
|
|
1333
|
-
auto filename{ items["filename"].IsNull() ? L"" : winrt::to_hstring(items["filename"].AsString()) };
|
|
1334
|
-
if (filename.size() <= 0) {
|
|
1335
|
-
requestContent.Add(dataContents, name);
|
|
1336
|
-
}
|
|
1337
|
-
else {
|
|
1338
|
-
requestContent.Add(dataContents, name, filename);
|
|
1339
|
-
}
|
|
1340
|
-
}
|
|
1341
|
-
}
|
|
1342
|
-
requestMessage.Content(requestContent);
|
|
1343
|
-
|
|
1344
|
-
auto exists{ uploadProgressMap.find(taskId) };
|
|
1345
|
-
if (exists != uploadProgressMap.end()) {
|
|
1346
|
-
auto progress{ uploadProgressMap[taskId] };
|
|
1347
|
-
uint64_t bodySize{ (co_await requestMessage.Content().ReadAsBufferAsync()).Length() };
|
|
1348
|
-
auto contentStream{ co_await requestMessage.Content().ReadAsInputStreamAsync() };
|
|
1349
|
-
Buffer buffer{ 10 * 1024 };
|
|
1350
|
-
uint64_t read{ 0 };
|
|
1351
|
-
|
|
1352
|
-
if (progress.count > -1) {
|
|
1353
|
-
uint64_t progressInterval{ bodySize / 100 * progress.count };
|
|
1354
|
-
for (;;) {
|
|
1355
|
-
|
|
1356
|
-
buffer.Length(0);
|
|
1357
|
-
auto readBuffer = co_await contentStream.ReadAsync(buffer, buffer.Capacity(), InputStreamOptions::None);
|
|
1358
|
-
read += readBuffer.Length();
|
|
1359
|
-
|
|
1360
|
-
if (readBuffer.Length() == 0)
|
|
1361
|
-
{
|
|
1362
|
-
break;
|
|
1363
|
-
}
|
|
1364
|
-
|
|
1365
|
-
if (read >= progressInterval) {
|
|
1366
|
-
m_reactContext.CallJSFunction(L"RCTDeviceEventEmitter", L"emit", L"ReactNativeBlobUtilProgress-upload",
|
|
1367
|
-
Microsoft::ReactNative::JSValueObject{
|
|
1368
|
-
{ "taskId", taskId },
|
|
1369
|
-
{ "written", read },
|
|
1370
|
-
{ "total", bodySize },
|
|
1371
|
-
});
|
|
1372
|
-
read = 0;
|
|
1373
|
-
}
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
else if (progress.interval > -1) {
|
|
1377
|
-
int64_t initialProgressTime{ winrt::clock::now().time_since_epoch().count() / 10000 };
|
|
1378
|
-
int64_t currentProgressTime;
|
|
1379
|
-
for (;;) {
|
|
1380
|
-
buffer.Length(0);
|
|
1381
|
-
|
|
1382
|
-
auto readBuffer = co_await contentStream.ReadAsync(buffer, buffer.Capacity(), InputStreamOptions::None);
|
|
1383
|
-
read += readBuffer.Length();
|
|
1384
|
-
|
|
1385
|
-
if (readBuffer.Length() == 0)
|
|
1386
|
-
{
|
|
1387
|
-
break;
|
|
1388
|
-
}
|
|
1389
|
-
|
|
1390
|
-
currentProgressTime = winrt::clock::now().time_since_epoch().count() / 10000;
|
|
1391
|
-
if (currentProgressTime - initialProgressTime >= progress.interval) {
|
|
1392
|
-
m_reactContext.CallJSFunction(L"RCTDeviceEventEmitter", L"emit", L"ReactNativeBlobUtilProgress-upload",
|
|
1393
|
-
Microsoft::ReactNative::JSValueObject{
|
|
1394
|
-
{ "taskId", taskId },
|
|
1395
|
-
{ "written", read },
|
|
1396
|
-
{ "total", bodySize },
|
|
1397
|
-
});
|
|
1398
|
-
initialProgressTime = winrt::clock::now().time_since_epoch().count() / 10000;
|
|
1399
|
-
}
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
|
|
1404
|
-
std::string error;
|
|
1405
|
-
auto cancellationTimer{ setTimeout(config.timeout) };
|
|
1406
|
-
cancellationTimer.Completed([weak_this = weak_from_this(), taskId, error](IAsyncAction const& action, AsyncStatus status) {
|
|
1407
|
-
if (status == AsyncStatus::Completed) {
|
|
1408
|
-
auto strong_this{ weak_this.lock() };
|
|
1409
|
-
if (strong_this) {
|
|
1410
|
-
strong_this->m_tasks.Cancel(taskId);
|
|
1411
|
-
{
|
|
1412
|
-
std::scoped_lock lock{ strong_this->m_mutex };
|
|
1413
|
-
strong_this->uploadProgressMap.extract(taskId);
|
|
1414
|
-
strong_this->downloadProgressMap.extract(taskId);
|
|
1415
|
-
}
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
});
|
|
1419
|
-
try {
|
|
1420
|
-
co_await m_tasks.Add(taskId, ProcessRequestAsync(taskId, filter, requestMessage, config, callback, error));
|
|
1421
|
-
}
|
|
1422
|
-
catch (...) {
|
|
1423
|
-
|
|
1424
|
-
}
|
|
1425
|
-
if (!error.empty()) {
|
|
1426
|
-
if (cancellationTimer.Status() != AsyncStatus::Completed) {
|
|
1427
|
-
callback(error, "error", "");
|
|
1428
|
-
}
|
|
1429
|
-
else {
|
|
1430
|
-
callback("ReactNativeBlobUtil request timed out", "error", "");
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
|
|
1434
|
-
cancellationTimer.Cancel();
|
|
1435
|
-
m_tasks.Cancel(taskId);
|
|
1436
|
-
{
|
|
1437
|
-
std::scoped_lock lock{ m_mutex };
|
|
1438
|
-
uploadProgressMap.extract(taskId);
|
|
1439
|
-
downloadProgressMap.extract(taskId);
|
|
1440
|
-
}
|
|
1596
|
+
// No-op: Android API
|
|
1597
|
+
result.Resolve("");
|
|
1441
1598
|
}
|
|
1442
1599
|
|
|
1443
|
-
void ReactNativeBlobUtil::
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1600
|
+
void ReactNativeBlobUtil::getBlob(
|
|
1601
|
+
std::string contentUri,
|
|
1602
|
+
std::string encoding,
|
|
1603
|
+
::React::ReactPromise<::React::JSValueArray>&& result) noexcept
|
|
1604
|
+
{
|
|
1605
|
+
// No-op: Android API
|
|
1606
|
+
result.Resolve(::React::JSValueArray{});
|
|
1450
1607
|
}
|
|
1451
1608
|
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
std::scoped_lock lock{ m_mutex };
|
|
1459
|
-
uploadProgressMap.try_emplace(taskId, config);
|
|
1609
|
+
void ReactNativeBlobUtil::getContentIntent(
|
|
1610
|
+
std::string mime,
|
|
1611
|
+
::React::ReactPromise<std::string>&& result) noexcept
|
|
1612
|
+
{
|
|
1613
|
+
// No-op: Android API
|
|
1614
|
+
result.Resolve("");
|
|
1460
1615
|
}
|
|
1461
1616
|
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
std::string taskId,
|
|
1465
|
-
std::function<void(std::string, std::string)> callback) noexcept
|
|
1466
|
-
try
|
|
1617
|
+
void ReactNativeBlobUtil::getSDCardDir(
|
|
1618
|
+
::React::ReactPromise<std::string>&& result) noexcept
|
|
1467
1619
|
{
|
|
1468
|
-
|
|
1469
|
-
|
|
1620
|
+
// No-op: Android API
|
|
1621
|
+
result.Resolve("");
|
|
1470
1622
|
}
|
|
1471
|
-
|
|
1623
|
+
|
|
1624
|
+
void ReactNativeBlobUtil::getSDCardApplicationDir(
|
|
1625
|
+
::React::ReactPromise<std::string>&& result) noexcept
|
|
1472
1626
|
{
|
|
1473
|
-
|
|
1627
|
+
// No-op: Android API
|
|
1628
|
+
result.Resolve("");
|
|
1474
1629
|
}
|
|
1475
1630
|
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
try
|
|
1631
|
+
void ReactNativeBlobUtil::scanFile(
|
|
1632
|
+
::React::JSValueArray&& pairs,
|
|
1633
|
+
std::function<void(::React::JSValueArray const&)> const& callback) noexcept
|
|
1480
1634
|
{
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
std::filesystem::path toDelete{ path.AsString() };
|
|
1484
|
-
toDelete.make_preferred();
|
|
1485
|
-
StorageFile file{ co_await StorageFile::GetFileFromPathAsync(winrt::to_hstring(toDelete.c_str())) };
|
|
1486
|
-
co_await file.DeleteAsync();
|
|
1487
|
-
}
|
|
1488
|
-
callback("");
|
|
1635
|
+
// No-op: Android API
|
|
1636
|
+
callback(::React::JSValueArray{});
|
|
1489
1637
|
}
|
|
1490
|
-
|
|
1638
|
+
|
|
1639
|
+
void ReactNativeBlobUtil::writeToMediaFile(
|
|
1640
|
+
std::string fileUri,
|
|
1641
|
+
std::string path,
|
|
1642
|
+
bool transformFile,
|
|
1643
|
+
::React::ReactPromise<std::string>&& result) noexcept
|
|
1491
1644
|
{
|
|
1492
|
-
|
|
1645
|
+
// No-op: Android API
|
|
1646
|
+
result.Resolve("");
|
|
1493
1647
|
}
|
|
1494
1648
|
|
|
1495
|
-
void ReactNativeBlobUtil::
|
|
1496
|
-
|
|
1497
|
-
std::function<void(std::string)> callback) noexcept
|
|
1498
|
-
try
|
|
1649
|
+
void ReactNativeBlobUtil::addListener(
|
|
1650
|
+
std::string eventName) noexcept
|
|
1499
1651
|
{
|
|
1500
|
-
|
|
1501
|
-
stream.streamInstance.Close();
|
|
1502
|
-
m_streamMap.extract(streamId);
|
|
1503
|
-
callback("");
|
|
1652
|
+
// No-op
|
|
1504
1653
|
}
|
|
1505
|
-
|
|
1654
|
+
|
|
1655
|
+
void ReactNativeBlobUtil::removeListeners(
|
|
1656
|
+
double count) noexcept
|
|
1506
1657
|
{
|
|
1507
|
-
|
|
1658
|
+
// No-op
|
|
1508
1659
|
}
|
|
1509
1660
|
|
|
1510
|
-
|
|
1511
1661
|
void ReactNativeBlobUtil::splitPath(const std::string& fullPath, winrt::hstring& directoryPath, winrt::hstring& fileName) noexcept
|
|
1512
1662
|
{
|
|
1513
1663
|
std::filesystem::path path{ fullPath };
|
|
@@ -1526,14 +1676,6 @@ void ReactNativeBlobUtil::splitPath(const std::wstring& fullPath, winrt::hstring
|
|
|
1526
1676
|
fileName = path.has_filename() ? winrt::to_hstring(path.filename().c_str()) : L"";
|
|
1527
1677
|
}
|
|
1528
1678
|
|
|
1529
|
-
void ReactNativeBlobUtil::addListener(std::string eventName) noexcept
|
|
1530
|
-
{
|
|
1531
|
-
}
|
|
1532
|
-
|
|
1533
|
-
void ReactNativeBlobUtil::removeListeners(double count) noexcept
|
|
1534
|
-
{
|
|
1535
|
-
}
|
|
1536
|
-
|
|
1537
1679
|
winrt::Windows::Foundation::IAsyncAction ReactNativeBlobUtil::ProcessRequestAsync(
|
|
1538
1680
|
const std::string& taskId,
|
|
1539
1681
|
const winrt::Windows::Web::Http::Filters::HttpBaseProtocolFilter& filter,
|
|
@@ -1692,10 +1834,4 @@ catch (...) {
|
|
|
1692
1834
|
co_return;
|
|
1693
1835
|
}
|
|
1694
1836
|
|
|
1695
|
-
|
|
1696
|
-
ReactNativeBlobUtilStream::ReactNativeBlobUtilStream(Streams::IRandomAccessStream& _streamInstance, EncodingOptions _encoding) noexcept
|
|
1697
|
-
: streamInstance{ std::move(_streamInstance) }
|
|
1698
|
-
, encoding{ _encoding }
|
|
1699
|
-
{
|
|
1700
|
-
}
|
|
1701
|
-
|
|
1837
|
+
} // namespace winrt::ReactNativeBlobUtil
|