Skip to content

Commit 3eb1015

Browse files
committed
Implement filestream functions
1 parent 11febcd commit 3eb1015

File tree

4 files changed

+170
-55
lines changed

4 files changed

+170
-55
lines changed

RNFetchBlobWin/windows/RNFetchBlobWin/RNFetchBlob.cpp

Lines changed: 150 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ using namespace winrt::Windows::Security::Cryptography;
1818
using namespace winrt::Windows::Security::Cryptography::Core;
1919

2020

21+
void RNFetchBlob::Initialize(winrt::Microsoft::ReactNative::ReactContext const& reactContext) noexcept
22+
{
23+
m_reactContext = reactContext;
24+
}
25+
2126
//
2227
// RNFS implementations
2328
//
@@ -297,36 +302,162 @@ try
297302
// Generate random data and copy it to a buffer.
298303
IBuffer buffer = Cryptography::CryptographicBuffer::GenerateRandom(length);
299304
// 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));
304306

307+
RNFetchBlobStream streamInstance{ stream, encodingOption };
308+
m_streamMap.try_emplace(streamId, streamInstance);
305309

310+
callback("","",streamId);
306311
}
307312
catch (const hresult_error& ex)
308313
{
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()), "");
310315
}
311316

312317

313318
// writeChunk
314-
void RNFetchBlob::writeChunk(
319+
winrt::fire_and_forget RNFetchBlob::writeChunk(
315320
std::string streamId,
316-
std::string data,
321+
std::wstring data,
317322
std::function<void(std::string)> callback) noexcept
323+
try
318324
{
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()));
319341
}
320342

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(
323368
std::string path,
324369
std::string encoding,
325-
int bufferSize,
326-
int tick,
370+
uint32_t bufferSize,
371+
uint64_t tick,
327372
const std::string streamId) noexcept
373+
try
328374
{
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;
329410

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+
});
330461
}
331462

332463

@@ -811,6 +942,13 @@ void RNFetchBlob::removeSession(
811942
void RNFetchBlob::closeStream(
812943
std::string streamId,
813944
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 (...)
814952
{
815953

816954
}
@@ -827,25 +965,9 @@ void RNFetchBlob::splitPath(const std::string& fullPath, winrt::hstring& directo
827965

828966

829967

830-
RNFetchBlobStream::RNFetchBlobStream(Streams::IRandomAccessStream & _streamInstance, bool _append, EncodingOptions _encoding) noexcept
968+
RNFetchBlobStream::RNFetchBlobStream(Streams::IRandomAccessStream & _streamInstance, EncodingOptions _encoding) noexcept
831969
: streamInstance{ std::move(_streamInstance) }
832-
, append{ _append }
833970
, encoding{ _encoding }
834971
{
835972
}
836973

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-

RNFetchBlobWin/windows/RNFetchBlobWin/RNFetchBlob.h

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,39 +8,25 @@
88
namespace Cryptography = winrt::Windows::Security::Cryptography;
99
namespace CryptographyCore = winrt::Windows::Security::Cryptography::Core;
1010

11-
enum struct EncodingOptions { UTF8 , BASE64, ASCII, URI};
11+
enum struct EncodingOptions { UTF8 , BASE64, ASCII, URI };
1212

1313
struct RNFetchBlobStream
1414
{
1515
public:
16-
RNFetchBlobStream::RNFetchBlobStream(winrt::Windows::Storage::Streams::IRandomAccessStream& _streamInstance, bool _append, EncodingOptions _encoding) noexcept;
17-
16+
RNFetchBlobStream::RNFetchBlobStream(winrt::Windows::Storage::Streams::IRandomAccessStream& _streamInstance, EncodingOptions _encoding) noexcept;
1817
winrt::Windows::Storage::Streams::IRandomAccessStream streamInstance;
19-
const bool append;
2018
const EncodingOptions encoding;
2119
};
2220

23-
struct RNFetchBlobStreamMap
24-
{
25-
public:
26-
using StreamId = std::string;
27-
RNFetchBlobStreamMap() = default;
28-
~RNFetchBlobStreamMap() = default;
29-
void Add(StreamId streamId, RNFetchBlobStream streamContainer) noexcept;
30-
RNFetchBlobStream& Get(StreamId streamId) noexcept;
31-
void Remove(StreamId streamId) noexcept;
32-
33-
private:
34-
std::mutex m_mutex;
35-
std::map<StreamId, RNFetchBlobStream> m_streamMap;
36-
};
37-
3821

3922
REACT_MODULE(RNFetchBlob, L"RNFetchBlob");
4023
struct RNFetchBlob
4124
{
42-
4325
public:
26+
using StreamId = std::string;
27+
28+
REACT_INIT(Initialize);
29+
void RNFetchBlob::Initialize(winrt::Microsoft::ReactNative::ReactContext const& reactContext) noexcept;
4430

4531
REACT_CONSTANT_PROVIDER(ConstantsViaConstantsProvider);
4632
void RNFetchBlob::ConstantsViaConstantsProvider(
@@ -87,18 +73,24 @@ struct RNFetchBlob
8773

8874
// writeChunk
8975
REACT_METHOD(writeChunk);
90-
void RNFetchBlob::writeChunk(
76+
winrt::fire_and_forget RNFetchBlob::writeChunk(
9177
std::string streamId,
92-
std::string data,
78+
std::wstring data,
79+
std::function<void(std::string)> callback) noexcept;
80+
81+
REACT_METHOD(writeChunkArray);
82+
winrt::fire_and_forget RNFetchBlob::writeChunkArray(
83+
std::string streamId,
84+
winrt::Microsoft::ReactNative::JSValueArray dataArray,
9385
std::function<void(std::string)> callback) noexcept;
9486

9587
// readStream
9688
REACT_METHOD(readStream);
97-
void RNFetchBlob::readStream(
89+
winrt::fire_and_forget RNFetchBlob::readStream(
9890
std::string path,
9991
std::string encoding,
100-
int bufferSize,
101-
int tick,
92+
uint32_t bufferSize,
93+
uint64_t tick,
10294
const std::string streamId) noexcept;
10395

10496

@@ -248,6 +240,9 @@ struct RNFetchBlob
248240
private:
249241
constexpr static int64_t UNIX_EPOCH_IN_WINRT_SECONDS = 11644473600;
250242

243+
std::map<StreamId, RNFetchBlobStream> m_streamMap;
244+
winrt::Microsoft::ReactNative::ReactContext m_reactContext;
245+
251246
const std::map<std::string, std::function<CryptographyCore::HashAlgorithmProvider()>> availableHashes{
252247
{"md5", []() { return CryptographyCore::HashAlgorithmProvider::OpenAlgorithm(CryptographyCore::HashAlgorithmNames::Md5()); } },
253248
{"sha1", []() { return CryptographyCore::HashAlgorithmProvider::OpenAlgorithm(CryptographyCore::HashAlgorithmNames::Sha1()); } },

RNFetchBlobWin/windows/RNFetchBlobWin/RNFetchBlobWin.vcxproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@
116116
<DependentUpon>App.xaml</DependentUpon>
117117
</ClInclude>
118118
<ClInclude Include="RNFetchBlob.h" />
119-
<ClInclude Include="RNFetchBlobConst.h" />
120119
</ItemGroup>
121120
<ItemGroup>
122121
<ApplicationDefinition Include="App.xaml">

RNFetchBlobWin/windows/RNFetchBlobWin/RNFetchBlobWin.vcxproj.filters

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
<ClInclude Include="ReactPackageProvider.h" />
2121
<ClInclude Include="AutolinkedNativeModules.g.h" />
2222
<ClInclude Include="RNFetchBlob.h" />
23-
<ClInclude Include="RNFetchBlobConst.h" />
2423
</ItemGroup>
2524
<ItemGroup>
2625
<Image Include="Assets\Wide310x150Logo.scale-200.png">

0 commit comments

Comments
 (0)