Skip to content

Commit

Permalink
Add file streams support
Browse files Browse the repository at this point in the history
  • Loading branch information
shalithasuranga committed Nov 8, 2022
1 parent 7872519 commit 8766c27
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 1 deletion.
159 changes: 159 additions & 0 deletions api/filesystem/filesystem.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include <map>
#include <mutex>
#include <iostream>
#include <fstream>

Expand Down Expand Up @@ -26,12 +28,57 @@
#include "errors.h"
#include "api/filesystem/filesystem.h"
#include "api/os/os.h"
#include "api/events/events.h"

using namespace std;
using json = nlohmann::json;

map<int, ifstream*> openedFiles;
mutex openedFilesLock;

#define NEU_DEFAULT_STREAM_BUF_SIZE 256

namespace fs {

void __dispatchOpenedFileEvt(int virtualFileId, const string &action, const json &data) {
json evt;
evt["id"] = virtualFileId;
evt["action"] = action;
evt["data"] = data;
events::dispatch("openedFile", evt);
}

void __readStreamBlock(const OpenedFileEvent &evt, ifstream *reader, vector<char> &buffer) {
long long size = evt.size > -1 ? evt.size : NEU_DEFAULT_STREAM_BUF_SIZE;

buffer.clear();
buffer.resize(size);
reader->read(buffer.data(), size);
string result(buffer.begin(), buffer.end());

__dispatchOpenedFileEvt(evt.id, "data", result);
}

void __readStream(const OpenedFileEvent &evt, ifstream *reader) {
if(reader->eof()) {
__dispatchOpenedFileEvt(evt.id, "end", nullptr);
return;
}

vector<char> buffer;
while(reader->peek() != char_traits<char>::eof()) {
__readStreamBlock(evt, reader, buffer);

if(evt.type == "read") {
break;
}
}

if(reader->eof()) {
__dispatchOpenedFileEvt(evt.id, "end", nullptr);
}
}

#if defined(_WIN32)
// From: https://stackoverflow.com/a/6161842/3565513
long long __winTickToUnixMS(long long windowsTicks) {
Expand Down Expand Up @@ -131,6 +178,44 @@ bool writeFile(const fs::FileWriterOptions &fileWriterOptions) {
return true;
}

int openFile(const string &filename) {
int virtualFileId = openedFiles.size();
ifstream *reader = new ifstream(filename.c_str(), ios::binary);
if(!reader->is_open()) {
delete reader;
return -1;
}
lock_guard<mutex> guard(openedFilesLock);
openedFiles[virtualFileId] = reader;
return virtualFileId;
}

bool updateOpenedFile(const OpenedFileEvent &evt) {
lock_guard<mutex> guard(openedFilesLock);
if(openedFiles.find(evt.id) == openedFiles.end()) {
return false;
}
ifstream *reader = openedFiles[evt.id];

if(evt.type == "close") {
reader->close();
delete reader;
openedFiles.erase(evt.id);
}
else if(evt.type == "read" || evt.type == "readAll") {
__readStream(evt, reader);
}
else if(evt.type == "seek") {
long long pos = evt.pos > -1 ? evt.pos : 0;
reader->clear();
reader->seekg(pos, ios::beg);
}
else {
return false;
}
return true;
}

fs::FileStats getStats(const string &path) {
fs::FileStats fileStats;
#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
Expand Down Expand Up @@ -370,6 +455,80 @@ json appendBinaryFile(const json &input) {
return __writeOrAppendBinaryFile(input, true);
}

json openFile(const json &input) {
json output;
if(!helpers::hasRequiredFields(input, {"path"})) {
output["error"] = errors::makeMissingArgErrorPayload();
return output;
}
string path = input["path"].get<string>();
int fileId = fs::openFile(path);
if(fileId == -1) {
output["error"] = errors::makeErrorPayload(errors::NE_FS_FILOPER, path);
}
else {
output["returnValue"] = fileId;
output["success"] = true;
}
return output;
}

json updateOpenedFile(const json &input) {
json output;
if(!helpers::hasRequiredFields(input, {"id", "event"})) {
output["error"] = errors::makeMissingArgErrorPayload();
return output;
}

fs::OpenedFileEvent fileEvt;
fileEvt.id = input["id"].get<int>();
fileEvt.type = input["event"].get<string>();

if(helpers::hasField(input, "data")) {
if(fileEvt.type == "read" || fileEvt.type == "readAll") {
fileEvt.size = input["data"].get<long long>();
}
else if(fileEvt.type == "seek") {
fileEvt.pos = input["data"].get<long long>();
}
}

if(fs::updateOpenedFile(fileEvt)) {
output["success"] = true;
}
else {
output["error"] = errors::makeErrorPayload(errors::NE_FS_UNLTOUP, to_string(fileEvt.id));
}
return output;
}

json getOpenedFileInfo(const json &input) {
json output;
lock_guard<mutex> guard(openedFilesLock);

if(!helpers::hasRequiredFields(input, {"id"})) {
output["error"] = errors::makeMissingArgErrorPayload();
return output;
}
int fileId = input["id"].get<int>();

if(openedFiles.find(fileId) == openedFiles.end()) {
output["error"] = errors::makeErrorPayload(errors::NE_FS_UNLTFOP, to_string(fileId));
return output;
}
ifstream *reader = openedFiles[fileId];
long long pos = reader->tellg();

json file;
file["id"] = fileId;
file["eof"] = reader->eof();
file["pos"] = pos;

output["returnValue"] = file;
output["success"] = true;
return output;
}

json removeFile(const json &input) {
json output;
if(!helpers::hasRequiredFields(input, {"path"})) {
Expand Down
12 changes: 12 additions & 0 deletions api/filesystem/filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ struct FileWriterOptions {
bool append = false;
};

struct OpenedFileEvent {
int id = -1;
string type = "";
long long pos = -1;
long long size = -1;
};

enum EntryType { EntryTypeFile, EntryTypeDir, EntryTypeOther };

struct FileStats {
Expand Down Expand Up @@ -55,6 +62,8 @@ bool writeFile(const fs::FileWriterOptions &fileWriterOptions);
string getDirectoryName(const string &filename);
string getCurrentDirectory();
string getFullPathFromRelative(const string &path);
int openFile(const string &path);
bool updateOpenedFile(const OpenedFileEvent &evt);
fs::FileStats getStats(const string &path);
fs::DirReaderResult readDirectory(const string &path);

Expand All @@ -68,6 +77,9 @@ json appendFile(const json &input);
json appendBinaryFile(const json &input);
json readFile(const json &input);
json readBinaryFile(const json &input);
json openFile(const json &input);
json updateOpenedFile(const json &input);
json getOpenedFileInfo(const json &input);
json removeFile(const json &input);
json readDirectory(const json &input);
json copyFile(const json &input);
Expand Down
12 changes: 12 additions & 0 deletions bin/resources/js/neutralino.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion bin/resources/js/neutralino.js.map

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions errors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ string __getStatusCodeString(const errors::StatusCode code) {
case errors::NE_FS_NOPATHE: return "NE_FS_NOPATHE";
case errors::NE_FS_COPYFER: return "NE_FS_COPYFER";
case errors::NE_FS_MOVEFER: return "NE_FS_MOVEFER";
case errors::NE_FS_FILOPER: return "NE_FS_FILOPER";
case errors::NE_FS_UNLTOUP: return "NE_FS_UNLTOUP";
case errors::NE_FS_UNLTFOP: return "NE_FS_UNLTFOP";
// router
case errors::NE_RT_INVTOKN: return "NE_RT_INVTOKN";
case errors::NE_RT_APIPRME: return "NE_RT_APIPRME";
Expand Down Expand Up @@ -80,6 +83,9 @@ string __findStatusCodeDesc(errors::StatusCode code) {
case errors::NE_FS_NOPATHE: return "Unable to open path %1";
case errors::NE_FS_COPYFER: return "Cannot perform copy: %1";
case errors::NE_FS_MOVEFER: return "Cannot perform move: %1";
case errors::NE_FS_FILOPER: return "Unable to open file: %1";
case errors::NE_FS_UNLTOUP: return "Unable to update opened file id: %1";
case errors::NE_FS_UNLTFOP: return "Unable to find opened file id: %1";
// router
case errors::NE_RT_INVTOKN: return "Invalid or expired NL_TOKEN value from client";
case errors::NE_RT_APIPRME: return "Missing permission to access Native API";
Expand Down
3 changes: 3 additions & 0 deletions errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ enum StatusCode {
NE_FS_NOPATHE,
NE_FS_COPYFER,
NE_FS_MOVEFER,
NE_FS_FILOPER,
NE_FS_UNLTOUP,
NE_FS_UNLTFOP,
// router
NE_RT_INVTOKN,
NE_RT_APIPRME,
Expand Down
3 changes: 3 additions & 0 deletions server/router.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ map<string, router::NativeMethod> methodMap = {
{"filesystem.writeBinaryFile", fs::controllers::writeBinaryFile},
{"filesystem.appendFile", fs::controllers::appendFile},
{"filesystem.appendBinaryFile", fs::controllers::appendBinaryFile},
{"filesystem.openFile", fs::controllers::openFile},
{"filesystem.updateOpenedFile", fs::controllers::updateOpenedFile},
{"filesystem.getOpenedFileInfo", fs::controllers::getOpenedFileInfo},
{"filesystem.removeFile", fs::controllers::removeFile},
{"filesystem.readDirectory", fs::controllers::readDirectory},
{"filesystem.copyFile", fs::controllers::copyFile},
Expand Down

0 comments on commit 8766c27

Please sign in to comment.