@@ -18,6 +18,11 @@ using namespace winrt::Windows::Security::Cryptography;
18
18
using namespace winrt ::Windows::Security::Cryptography::Core;
19
19
20
20
21
+ void RNFetchBlob::Initialize (winrt::Microsoft::ReactNative::ReactContext const & reactContext) noexcept
22
+ {
23
+ m_reactContext = reactContext;
24
+ }
25
+
21
26
//
22
27
// RNFS implementations
23
28
//
@@ -297,36 +302,162 @@ try
297
302
// Generate random data and copy it to a buffer.
298
303
IBuffer buffer = Cryptography::CryptographicBuffer::GenerateRandom (length);
299
304
// Encode the buffer to a hexadecimal string (for display).
300
- std::string stringId = winrt::to_string (Cryptography::CryptographicBuffer::EncodeToHexString (buffer));
301
-
302
- RNFetchBlobStream streamInstance{ stream, append, encodingOption };
303
-
305
+ std::string streamId = winrt::to_string (Cryptography::CryptographicBuffer::EncodeToHexString (buffer));
304
306
307
+ RNFetchBlobStream streamInstance{ stream, encodingOption };
308
+ m_streamMap.try_emplace (streamId, streamInstance);
305
309
310
+ callback (" " ," " ,streamId);
306
311
}
307
312
catch (const hresult_error& ex)
308
313
{
309
- callback (" EUNSPECIFIED" , " Failed to create write stream at path ` " + path + " ` ; " + winrt::to_string (ex.message ().c_str ()), " " );
314
+ callback (" EUNSPECIFIED" , " Failed to create write stream at path ' " + path + " ' ; " + winrt::to_string (ex.message ().c_str ()), " " );
310
315
}
311
316
312
317
313
318
// writeChunk
314
- void RNFetchBlob::writeChunk (
319
+ winrt::fire_and_forget RNFetchBlob::writeChunk (
315
320
std::string streamId,
316
- std::string data,
321
+ std::wstring data,
317
322
std::function<void (std::string)> callback) noexcept
323
+ try
318
324
{
325
+ auto stream{ m_streamMap.find (streamId)->second };
326
+ Streams::IBuffer buffer;
327
+ if (stream.encoding == EncodingOptions::UTF8)
328
+ {
329
+ buffer = Cryptography::CryptographicBuffer::ConvertStringToBinary (data, BinaryStringEncoding::Utf8);
330
+ }
331
+ else if (stream.encoding == EncodingOptions::BASE64)
332
+ {
333
+ buffer = Cryptography::CryptographicBuffer::DecodeFromBase64String (data);
334
+ }
335
+ co_await stream.streamInstance .ReadAsync (buffer, buffer.Length (), Streams::InputStreamOptions::None);
336
+ callback (" " );
337
+ }
338
+ catch (const hresult_error& ex)
339
+ {
340
+ callback (winrt::to_string (ex.message ().c_str ()));
319
341
}
320
342
321
- // readStream
322
- void RNFetchBlob::readStream (
343
+ winrt::fire_and_forget RNFetchBlob::writeChunkArray (
344
+ std::string streamId,
345
+ winrt::Microsoft::ReactNative::JSValueArray dataArray,
346
+ std::function<void (std::string)> callback) noexcept
347
+ try
348
+ {
349
+ auto stream{ m_streamMap.find (streamId)->second };
350
+ std::vector<byte> data;
351
+ data.reserve (dataArray.size ());
352
+ for (auto & var : dataArray)
353
+ {
354
+ data.push_back (var.AsInt8 ());
355
+ }
356
+ Streams::IBuffer buffer{ CryptographicBuffer::CreateFromByteArray (data) };
357
+
358
+ co_await stream.streamInstance .ReadAsync (buffer, buffer.Length (), Streams::InputStreamOptions::None);
359
+ callback (" " );
360
+ }
361
+ catch (const hresult_error& ex)
362
+ {
363
+ callback (winrt::to_string (ex.message ().c_str ()));
364
+ }
365
+
366
+ // readStream - no promises, callbacks, only event emission
367
+ winrt::fire_and_forget RNFetchBlob::readStream (
323
368
std::string path,
324
369
std::string encoding,
325
- int bufferSize,
326
- int tick,
370
+ uint32_t bufferSize,
371
+ uint64_t tick,
327
372
const std::string streamId) noexcept
373
+ try
328
374
{
375
+ EncodingOptions usedEncoding;
376
+ if (encoding.compare (" utf8" ))
377
+ {
378
+ usedEncoding = EncodingOptions::UTF8;
379
+ }
380
+ else if (encoding.compare (" base64" ))
381
+ {
382
+ usedEncoding = EncodingOptions::BASE64;
383
+ }
384
+ else if (encoding.compare (" ascii" ))
385
+ {
386
+ usedEncoding = EncodingOptions::ASCII;
387
+ }
388
+ else
389
+ {
390
+ // Wrong encoding yo
391
+
392
+ co_return ;
393
+ }
394
+
395
+ uint32_t chunkSize = usedEncoding == EncodingOptions::BASE64 ? 4095 : 4096 ;
396
+ if (bufferSize > 0 )
397
+ {
398
+ chunkSize = bufferSize;
399
+ }
400
+
401
+ winrt::hstring directoryPath, fileName;
402
+ splitPath (path, directoryPath, fileName);
403
+ StorageFolder folder{ co_await StorageFolder::GetFolderFromPathAsync (directoryPath) };
404
+ StorageFile file{ co_await folder.GetFileAsync (fileName) };
405
+
406
+ Streams::IRandomAccessStream stream{ co_await file.OpenAsync (FileAccessMode::Read) };
407
+ Buffer buffer{ chunkSize };
408
+ const TimeSpan time { tick };
409
+ IAsyncAction timer;
329
410
411
+ for (;;)
412
+ {
413
+ auto readBuffer = co_await stream.ReadAsync (buffer, buffer.Capacity (), InputStreamOptions::None);
414
+ if (readBuffer.Length () == 0 )
415
+ {
416
+ break ;
417
+ }
418
+ if (usedEncoding == EncodingOptions::BASE64)
419
+ {
420
+ std::wstring base64Content{ Cryptography::CryptographicBuffer::EncodeToBase64String (readBuffer) };
421
+ m_reactContext.CallJSFunction (L" RCTDeviceEventEmitter" , L" emit" , streamId,
422
+ winrt::Microsoft::ReactNative::JSValueObject{
423
+ {" data" , base64Content},
424
+ });
425
+ }
426
+ else
427
+ {
428
+ std::wstring utf8Content{ Cryptography::CryptographicBuffer::ConvertBinaryToString (BinaryStringEncoding::Utf8, readBuffer) };
429
+ if (usedEncoding == EncodingOptions::ASCII)
430
+ {
431
+ std::string asciiContent{ winrt::to_string (utf8Content) };
432
+ std::wstring asciiResult{ winrt::to_hstring (asciiContent) };
433
+ // emit ascii content
434
+ m_reactContext.CallJSFunction (L" RCTDeviceEventEmitter" , L" emit" , streamId,
435
+ winrt::Microsoft::ReactNative::JSValueObject{
436
+ {" data" , asciiResult},
437
+ });
438
+ }
439
+ else
440
+ {
441
+ // emit utf8 content
442
+ m_reactContext.CallJSFunction (L" RCTDeviceEventEmitter" , L" emit" , streamId,
443
+ winrt::Microsoft::ReactNative::JSValueObject{
444
+ {" data" , utf8Content},
445
+ });
446
+ }
447
+ }
448
+ // sleep
449
+ if (tick > 0 )
450
+ {
451
+ std::this_thread::sleep_for (std::chrono::milliseconds (tick));
452
+ }
453
+ }
454
+ }
455
+ catch (const hresult_error& ex)
456
+ {
457
+ m_reactContext.CallJSFunction (L" RCTDeviceEventEmitter" , L" emit" , L" DownloadBegin" ,
458
+ winrt::Microsoft::ReactNative::JSValueObject{
459
+ {streamId, L" help" },
460
+ });
330
461
}
331
462
332
463
@@ -811,6 +942,13 @@ void RNFetchBlob::removeSession(
811
942
void RNFetchBlob::closeStream (
812
943
std::string streamId,
813
944
std::function<void (std::string)> callback) noexcept
945
+ try
946
+ {
947
+ auto stream{ m_streamMap.find (streamId)->second };
948
+ stream.streamInstance .Close ();
949
+ m_streamMap.extract (streamId);
950
+ }
951
+ catch (...)
814
952
{
815
953
816
954
}
@@ -827,25 +965,9 @@ void RNFetchBlob::splitPath(const std::string& fullPath, winrt::hstring& directo
827
965
828
966
829
967
830
- RNFetchBlobStream::RNFetchBlobStream (Streams::IRandomAccessStream & _streamInstance, bool _append, EncodingOptions _encoding) noexcept
968
+ RNFetchBlobStream::RNFetchBlobStream (Streams::IRandomAccessStream & _streamInstance, EncodingOptions _encoding) noexcept
831
969
: streamInstance{ std::move (_streamInstance) }
832
- , append{ _append }
833
970
, encoding{ _encoding }
834
971
{
835
972
}
836
973
837
-
838
- void RNFetchBlobStreamMap::Add (StreamId streamId, RNFetchBlobStream streamContainer) noexcept
839
- {
840
- m_streamMap.try_emplace (streamId, streamContainer);
841
- }
842
- RNFetchBlobStream& RNFetchBlobStreamMap::Get (StreamId streamId) noexcept
843
- {
844
- auto iter{ m_streamMap.find (streamId) };
845
- return iter->second ;
846
- }
847
- void RNFetchBlobStreamMap::Remove (StreamId streamId) noexcept
848
- {
849
- m_streamMap.extract (streamId);
850
- }
851
-
0 commit comments