Convert all file ops to use absolute paths
This commit is contained in:
@@ -198,6 +198,7 @@ class DialogEx extends React.Component<DialogExProps,DialogExState> implements I
|
||||
{
|
||||
this.onEnterKey();
|
||||
}
|
||||
evt.stopPropagation();
|
||||
}
|
||||
render() {
|
||||
let { tag,onClose,...extra} = this.props;
|
||||
|
||||
@@ -741,9 +741,7 @@ export default withStyles(styles, { withTheme: true })(
|
||||
}
|
||||
}
|
||||
uploadPage={
|
||||
"uploadUserFile?directory=" + encodeURIComponent(
|
||||
pathConcat(this.props.fileProperty.directory, this.state.navDirectory)
|
||||
)
|
||||
"uploadUserFile?directory=" + encodeURIComponent(this.state.navDirectory)
|
||||
+ "&ext="
|
||||
+ encodeURIComponent(this.getFileExtensionList(this.props.fileProperty))
|
||||
}
|
||||
@@ -792,7 +790,7 @@ export default withStyles(styles, { withTheme: true })(
|
||||
defaultPath={this.getDefaultPath()}
|
||||
excludeDirectory={
|
||||
this.isDirectory(this.state.selectedFile)
|
||||
? pathConcat(this.state.navDirectory, pathFileName(this.state.selectedFile)) : ""}
|
||||
? this.state.selectedFile : ""}
|
||||
onClose={() => { this.setState({ moveDialogOpen: false }); }}
|
||||
onOk={
|
||||
(path) => {
|
||||
|
||||
@@ -38,28 +38,18 @@ import { isDarkMode } from './DarkMode';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
|
||||
|
||||
function pathConcat(l: string, r: string): string
|
||||
{
|
||||
if (l.length === 0) return r;
|
||||
if (r.length === 0) return l;
|
||||
return l +'/' + r;
|
||||
}
|
||||
|
||||
class DirectoryTree {
|
||||
name: string = "";
|
||||
path: string = "";
|
||||
expanded: boolean = false;
|
||||
isProtected: boolean = true;
|
||||
children: DirectoryTree[] = [];
|
||||
|
||||
constructor(tree: FilePropertyDirectoryTree, parentTree: (DirectoryTree | null) = null) {
|
||||
this.name = tree.directoryName;
|
||||
if (parentTree) {
|
||||
this.path = pathConcat(parentTree.path,tree.directoryName);
|
||||
} else {
|
||||
this.name = "Home";
|
||||
this.path = tree.directoryName;
|
||||
this.expanded = true;
|
||||
}
|
||||
this.path = tree.directoryName;
|
||||
this.name = tree.displayName;
|
||||
this.isProtected = tree.isProtected;
|
||||
for (var treeChild of tree.children) {
|
||||
this.children.push(new DirectoryTree(treeChild, this));
|
||||
}
|
||||
@@ -143,6 +133,7 @@ export interface FilePropertyDirectorySelectDialogState {
|
||||
selectedPath: string;
|
||||
directoryTree?: DirectoryTree;
|
||||
hasSelection: boolean;
|
||||
isProtected: boolean;
|
||||
directoryTreeInvalidatecount: number;
|
||||
|
||||
};
|
||||
@@ -160,6 +151,7 @@ export default class FilePropertyDirectorySelectDialog extends ResizeResponsiveC
|
||||
selectedPath: props.defaultPath,
|
||||
directoryTree: undefined,
|
||||
hasSelection: false,
|
||||
isProtected: true,
|
||||
directoryTreeInvalidatecount: 0
|
||||
|
||||
};
|
||||
@@ -192,14 +184,19 @@ export default class FilePropertyDirectorySelectDialog extends ResizeResponsiveC
|
||||
this.model.getFilePropertyDirectoryTree(this.props.uiFileProperty)
|
||||
.then((filePropertyDirectoryTree) => {
|
||||
let myTree = new DirectoryTree(filePropertyDirectoryTree);
|
||||
if (this.props.excludeDirectory)
|
||||
if (this.props.excludeDirectory.length !== 0)
|
||||
{
|
||||
myTree.remove(this.props.excludeDirectory);
|
||||
}
|
||||
myTree.expand(this.state.selectedPath);
|
||||
|
||||
let hasSelection = myTree.find(this.state.selectedPath) != null;
|
||||
this.setState({ directoryTree: myTree, hasSelection: hasSelection });
|
||||
let selection = myTree.find(this.state.selectedPath);
|
||||
let hasSelection = !!selection;
|
||||
this.setState({
|
||||
directoryTree: myTree,
|
||||
hasSelection: hasSelection,
|
||||
isProtected: selection ? selection.isProtected : false
|
||||
});
|
||||
this.requestScroll = true;
|
||||
})
|
||||
.catch((e) => {
|
||||
@@ -223,6 +220,9 @@ export default class FilePropertyDirectorySelectDialog extends ResizeResponsiveC
|
||||
|
||||
|
||||
onOK() {
|
||||
if (this.state.isProtected) {
|
||||
return;
|
||||
}
|
||||
if (this.state.hasSelection) {
|
||||
this.props.onOk(this.state.selectedPath);
|
||||
}
|
||||
@@ -238,7 +238,11 @@ export default class FilePropertyDirectorySelectDialog extends ResizeResponsiveC
|
||||
private onTreeClick(directoryTree: DirectoryTree) {
|
||||
if (!this.state.directoryTree) return;
|
||||
this.state.directoryTree.expand(directoryTree.path);
|
||||
this.setState({ selectedPath: directoryTree.path, hasSelection: true, directoryTreeInvalidatecount: this.state.directoryTreeInvalidatecount + 1 });
|
||||
this.setState({
|
||||
selectedPath: directoryTree.path,
|
||||
hasSelection: true,
|
||||
isProtected: directoryTree.isProtected,
|
||||
directoryTreeInvalidatecount: this.state.directoryTreeInvalidatecount + 1 });
|
||||
}
|
||||
private renderTree_(directoryTree: DirectoryTree) {
|
||||
let ref: ((element: HTMLButtonElement | null) => void) | undefined = undefined;
|
||||
@@ -338,7 +342,8 @@ export default class FilePropertyDirectorySelectDialog extends ResizeResponsiveC
|
||||
<Button variant="dialogSecondary" onClick={() => { this.onClose(); }} color="primary">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button variant="dialogPrimary" onClick={() => { this.onOK(); }} color="secondary" disabled={!this.state.hasSelection} >
|
||||
<Button variant="dialogPrimary" onClick={() => { this.onOK(); }} color="secondary"
|
||||
disabled={(!this.state.hasSelection) || this.state.isProtected} >
|
||||
OK
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
export default class FilePropertyDirectoryTree {
|
||||
deserialize(input: any) : FilePropertyDirectoryTree {
|
||||
this.directoryName = input.directoryName;
|
||||
this.displayName = input.displayName;
|
||||
this.isProtected = input.isProtected;
|
||||
this.children = FilePropertyDirectoryTree.deserialize_array(input.children);
|
||||
return this;
|
||||
}
|
||||
@@ -35,5 +37,7 @@ export default class FilePropertyDirectoryTree {
|
||||
|
||||
|
||||
directoryName: string = "";
|
||||
displayName: string = "";
|
||||
isProtected: boolean = false;
|
||||
children: FilePropertyDirectoryTree[] = [];
|
||||
}
|
||||
@@ -2510,7 +2510,7 @@ export class PiPedalModel //implements PiPedalModel
|
||||
link.click();
|
||||
}
|
||||
|
||||
uploadFile(uploadPage: string, file: File, contentType: string = "application/octet-stream", abortController?: AbortController): Promise<string> {
|
||||
uploadUserFile(uploadPage: string, file: File, contentType: string = "application/octet-stream", abortController?: AbortController): Promise<string> {
|
||||
let result = new Promise<string>((resolve, reject) => {
|
||||
try {
|
||||
if (file.size > this.maxFileUploadSize) {
|
||||
@@ -2551,10 +2551,20 @@ export class PiPedalModel //implements PiPedalModel
|
||||
}
|
||||
})
|
||||
.then((json) => {
|
||||
resolve(json as string);
|
||||
let response = json as {errorMessage: string, path: string};
|
||||
if (response.errorMessage !== "")
|
||||
{
|
||||
throw new Error(response.errorMessage);
|
||||
}
|
||||
resolve(response.path);
|
||||
})
|
||||
.catch((error) => {
|
||||
reject("Upload failed. " + error);
|
||||
if (error instanceof Error)
|
||||
{
|
||||
reject("Upload failed. " + (error as Error).message);
|
||||
} else {
|
||||
reject("Upload failed. " + error);
|
||||
}
|
||||
})
|
||||
;
|
||||
} catch (error) {
|
||||
|
||||
@@ -208,7 +208,7 @@ export default class UploadFileDialog extends ResizeResponsiveComponent<UploadFi
|
||||
{
|
||||
throw new Error("Invalid file extension.");
|
||||
}
|
||||
let filename = await this.model.uploadFile(
|
||||
let filename = await this.model.uploadUserFile(
|
||||
this.props.uploadPage,
|
||||
this.uploadList[i].file,
|
||||
"application/octet-stream",
|
||||
|
||||
@@ -20,16 +20,26 @@
|
||||
#include "FilePropertyDirectoryTree.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
FilePropertyDirectoryTree::FilePropertyDirectoryTree()
|
||||
{
|
||||
}
|
||||
FilePropertyDirectoryTree::FilePropertyDirectoryTree(const std::string &directoryName)
|
||||
: directoryName_(directoryName)
|
||||
: directoryName_(directoryName),
|
||||
displayName_(fs::path(directoryName).filename().string())
|
||||
{
|
||||
}
|
||||
|
||||
FilePropertyDirectoryTree::FilePropertyDirectoryTree(const std::string &directoryName, const std::string &displayName)
|
||||
: directoryName_(directoryName),
|
||||
displayName_(displayName)
|
||||
{
|
||||
}
|
||||
|
||||
JSON_MAP_BEGIN(FilePropertyDirectoryTree)
|
||||
JSON_MAP_REFERENCE(FilePropertyDirectoryTree, directoryName)
|
||||
JSON_MAP_REFERENCE(FilePropertyDirectoryTree, displayName)
|
||||
JSON_MAP_REFERENCE(FilePropertyDirectoryTree, isProtected)
|
||||
JSON_MAP_REFERENCE(FilePropertyDirectoryTree, children)
|
||||
JSON_MAP_END()
|
||||
|
||||
@@ -29,7 +29,10 @@ namespace pipedal {
|
||||
|
||||
FilePropertyDirectoryTree();
|
||||
FilePropertyDirectoryTree(const std::string&directoryName);
|
||||
FilePropertyDirectoryTree(const std::string&directoryName,const std::string&displayName);
|
||||
std::string directoryName_;
|
||||
std::string displayName_;
|
||||
bool isProtected_ = false;
|
||||
std::vector<std::unique_ptr<FilePropertyDirectoryTree>> children_;
|
||||
|
||||
DECLARE_JSON_MAP(FilePropertyDirectoryTree);
|
||||
|
||||
+74
-34
@@ -71,6 +71,12 @@ static bool isSubdirectory(const fs::path&path, const fs::path&basePath)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool hasSyntheticModRoot(const UiFileProperty &fileProperty)
|
||||
{
|
||||
return (fileProperty.modDirectories().size() > 1 || (fileProperty.modDirectories().size() == 1 && fileProperty.useLegacyModDirectory()));
|
||||
|
||||
}
|
||||
|
||||
Storage::Storage()
|
||||
{
|
||||
SetConfigRoot("~/var/Config");
|
||||
@@ -1819,7 +1825,7 @@ FileRequestResult Storage::GetFileList2(const std::string &relativePath_,const U
|
||||
{
|
||||
ThrowPermissionDeniedError();
|
||||
}
|
||||
if (fileProperty.modDirectories().size() > 1 || (fileProperty.modDirectories().size() == 1 && fileProperty.useLegacyModDirectory()))
|
||||
if (hasSyntheticModRoot(fileProperty))
|
||||
{
|
||||
return Storage::GetModFileList2(absolutePath,fileProperty);
|
||||
}
|
||||
@@ -1873,29 +1879,32 @@ bool Storage::IsValidSampleFileName(const std::filesystem::path &fileName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!ensureNoDotDot(fileName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::filesystem::path audioFilePath = this->GetPluginUploadDirectory();
|
||||
|
||||
std::filesystem::path parentDirectory = fileName.parent_path();
|
||||
while (true)
|
||||
|
||||
auto iTarget = parentDirectory.begin();
|
||||
|
||||
for (auto i = audioFilePath.begin(); i != audioFilePath.end(); ++i)
|
||||
{
|
||||
if (!parentDirectory.has_parent_path())
|
||||
{
|
||||
if (iTarget == parentDirectory.end()) {
|
||||
return false;
|
||||
}
|
||||
std::string name = parentDirectory.filename().string();
|
||||
if (parentDirectory == audioFilePath)
|
||||
return true;
|
||||
parentDirectory = parentDirectory.parent_path();
|
||||
if (parentDirectory.string().length() < audioFilePath.string().length())
|
||||
{
|
||||
if (*i != *iTarget) {
|
||||
return false;
|
||||
}
|
||||
++iTarget;
|
||||
}
|
||||
while (iTarget != parentDirectory.end())
|
||||
{
|
||||
if (iTarget->string() == "..")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
++iTarget;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void Storage::DeleteSampleFile(const std::filesystem::path &fileName)
|
||||
{
|
||||
@@ -1936,13 +1945,13 @@ void Storage::DeleteSampleFile(const std::filesystem::path &fileName)
|
||||
}
|
||||
std::filesystem::path Storage::MakeUserFilePath(const std::string &directory, const std::string &filename)
|
||||
{
|
||||
if (!ensureNoDotDot(directory))
|
||||
{
|
||||
throw std::logic_error(SS("Invalide filename: " << filename));
|
||||
}
|
||||
std::filesystem::path filePath{filename};
|
||||
|
||||
std::filesystem::path result = this->GetPluginUploadDirectory() / directory / filename;
|
||||
std::filesystem::path result = fs::path(directory) / filename;
|
||||
if (!result.is_absolute())
|
||||
{
|
||||
result = this->GetPluginUploadDirectory() / result;
|
||||
}
|
||||
if (!this->IsValidSampleFileName(result))
|
||||
{
|
||||
throw std::logic_error(SS("Invalid upload path: " << result));
|
||||
@@ -2065,8 +2074,8 @@ void Storage::FillSampleDirectoryTree(FilePropertyDirectoryTree*node, const std:
|
||||
{
|
||||
if (child.is_directory())
|
||||
{
|
||||
const auto& childPath = child.path();
|
||||
FilePropertyDirectoryTree::ptr childTree = std::make_unique<FilePropertyDirectoryTree>(childPath.filename());
|
||||
const auto& childPath = child.path();
|
||||
FilePropertyDirectoryTree::ptr childTree = std::make_unique<FilePropertyDirectoryTree>(childPath);
|
||||
FillSampleDirectoryTree(childTree.get(),childPath);
|
||||
node->children_.push_back(std::move(childTree));
|
||||
}
|
||||
@@ -2078,22 +2087,53 @@ void Storage::FillSampleDirectoryTree(FilePropertyDirectoryTree*node, const std:
|
||||
return collator->Compare(left->directoryName_,right->directoryName_) < 0;
|
||||
});
|
||||
}
|
||||
FilePropertyDirectoryTree::ptr Storage::GetFilePropertydirectoryTree(const UiFileProperty&uiFileProperty) const
|
||||
FilePropertyDirectoryTree::ptr Storage::GetFilePropertydirectoryTree(const UiFileProperty&uiFileProperty)
|
||||
{
|
||||
FilePropertyDirectoryTree::ptr result = std::make_unique<FilePropertyDirectoryTree>("");
|
||||
if (uiFileProperty.directory().empty())
|
||||
{
|
||||
throw std::runtime_error("Invalid uiFileProperty");
|
||||
}
|
||||
if (!ensureNoDotDot(uiFileProperty.directory()))
|
||||
{
|
||||
throw std::runtime_error("Invalid uiFileProperty");
|
||||
}
|
||||
std::filesystem::path rootDirectory = this->GetPluginUploadDirectory() / uiFileProperty.directory();
|
||||
fs::path uploadDirectory = this->GetPluginUploadDirectory();
|
||||
|
||||
FillSampleDirectoryTree(result.get(),rootDirectory);
|
||||
if (hasSyntheticModRoot(uiFileProperty))
|
||||
{
|
||||
FilePropertyDirectoryTree::ptr result = std::make_unique<FilePropertyDirectoryTree>("","Home");
|
||||
result->isProtected_ = true;
|
||||
for (const auto& modDirectory: uiFileProperty.modDirectories())
|
||||
{
|
||||
auto modDirectoryInfo = ModFileTypes::GetModDirectory(modDirectory);
|
||||
if (modDirectoryInfo)
|
||||
{
|
||||
auto childPath = uploadDirectory / modDirectoryInfo->pipedalPath;
|
||||
FilePropertyDirectoryTree::ptr child = std::make_unique<FilePropertyDirectoryTree>(
|
||||
childPath,modDirectoryInfo->displayName
|
||||
);
|
||||
FillSampleDirectoryTree(child.get(),childPath);
|
||||
result->children_.push_back(std::move(child));
|
||||
}
|
||||
}
|
||||
if (uiFileProperty.useLegacyModDirectory()) {
|
||||
auto childPath = uploadDirectory / uiFileProperty.directory();
|
||||
FilePropertyDirectoryTree::ptr child = std::make_unique<FilePropertyDirectoryTree>(
|
||||
childPath
|
||||
);
|
||||
FillSampleDirectoryTree(child.get(),childPath);
|
||||
result->children_.push_back(std::move(child));
|
||||
}
|
||||
return result;
|
||||
|
||||
} else {
|
||||
if (uiFileProperty.directory().empty())
|
||||
{
|
||||
throw std::runtime_error("Invalid uiFileProperty");
|
||||
}
|
||||
if (!ensureNoDotDot(uiFileProperty.directory()))
|
||||
{
|
||||
throw std::runtime_error("Invalid uiFileProperty");
|
||||
}
|
||||
std::filesystem::path rootDirectory = uploadDirectory / uiFileProperty.directory();
|
||||
FilePropertyDirectoryTree::ptr result = std::make_unique<FilePropertyDirectoryTree>(rootDirectory.string(),"Home");
|
||||
|
||||
FillSampleDirectoryTree(result.get(),rootDirectory);
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -226,7 +226,7 @@ public:
|
||||
const std::string&oldRelativePath,
|
||||
const std::string&newRelativePath,
|
||||
const UiFileProperty&uiFileProperty);
|
||||
FilePropertyDirectoryTree::ptr GetFilePropertydirectoryTree(const UiFileProperty&uiFileProperty) const;
|
||||
FilePropertyDirectoryTree::ptr GetFilePropertydirectoryTree(const UiFileProperty&uiFileProperty);
|
||||
};
|
||||
|
||||
|
||||
|
||||
+152
-119
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2024 Robin Davies
|
||||
// Copyright (c) 2024 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "UpdaterSecurity.hpp"
|
||||
#include "TemporaryFile.hpp"
|
||||
#include "PresetBundle.hpp"
|
||||
|
||||
#include "json.hpp"
|
||||
|
||||
#define OLD_PRESET_EXTENSION ".piPreset"
|
||||
#define PRESET_EXTENSION ".piPreset"
|
||||
@@ -50,40 +50,52 @@ using namespace pipedal;
|
||||
using namespace boost::system;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
class UserUploadResponse
|
||||
{
|
||||
public:
|
||||
std::string errorMessage_;
|
||||
std::string path_;
|
||||
DECLARE_JSON_MAP(UserUploadResponse);
|
||||
};
|
||||
JSON_MAP_BEGIN(UserUploadResponse)
|
||||
JSON_MAP_REFERENCE(UserUploadResponse, errorMessage)
|
||||
JSON_MAP_REFERENCE(UserUploadResponse, path)
|
||||
JSON_MAP_END()
|
||||
|
||||
static bool IsZipFile(const std::filesystem::path &path)
|
||||
{
|
||||
std::ifstream f(path);
|
||||
if (!f.is_open()) return false;
|
||||
if (!f.is_open())
|
||||
return false;
|
||||
|
||||
char c[4];
|
||||
memset(c,0,sizeof(c));
|
||||
memset(c, 0, sizeof(c));
|
||||
|
||||
f >> c[0] >> c[1] >> c[2] >> c[3];
|
||||
|
||||
// official file header according to PKware documetnation.
|
||||
return c[0] == 0x50 && c[1] == 0x4B && c[2] == 0x03 && c[3] == 0x04;
|
||||
|
||||
|
||||
}
|
||||
|
||||
class ExtensionChecker {
|
||||
class ExtensionChecker
|
||||
{
|
||||
public:
|
||||
ExtensionChecker(const std::string&extensionList)
|
||||
:extensions(split(extensionList,','))
|
||||
ExtensionChecker(const std::string &extensionList)
|
||||
: extensions(split(extensionList, ','))
|
||||
{
|
||||
}
|
||||
bool IsValidExtension(const std::string&extension)
|
||||
bool IsValidExtension(const std::string &extension)
|
||||
{
|
||||
if (extensions.size() == 0)
|
||||
if (extensions.size() == 0)
|
||||
return true;
|
||||
for (const auto&ext: extensions)
|
||||
for (const auto &ext : extensions)
|
||||
{
|
||||
if (ext == extension)
|
||||
if (ext == extension)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> extensions;
|
||||
};
|
||||
@@ -133,7 +145,8 @@ public:
|
||||
else if (segment == "uploadBank")
|
||||
{
|
||||
return true;
|
||||
} else if (segment == "uploadUserFile")
|
||||
}
|
||||
else if (segment == "uploadUserFile")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -159,7 +172,7 @@ public:
|
||||
PluginPresets pluginPresets = model->GetPluginPresets(pluginUri);
|
||||
|
||||
std::stringstream s;
|
||||
json_writer writer(s,false);
|
||||
json_writer writer(s, false);
|
||||
writer.write(pluginPresets);
|
||||
*pContent = s.str();
|
||||
}
|
||||
@@ -176,7 +189,7 @@ public:
|
||||
file.selectedPreset(newInstanceId);
|
||||
|
||||
std::stringstream s;
|
||||
json_writer writer(s,false);
|
||||
json_writer writer(s, false);
|
||||
writer.write(file);
|
||||
*pContent = s.str();
|
||||
*pName = pedalboard.name();
|
||||
@@ -210,12 +223,11 @@ public:
|
||||
std::string content;
|
||||
GetPluginPresets(request_uri, &name, &content);
|
||||
|
||||
TemporaryFile tmpFile { WEB_TEMP_DIR};
|
||||
PresetBundleWriter::ptr presetbundleWriter = PresetBundleWriter::CreatePluginPresetsFile(*(this->model),content);
|
||||
TemporaryFile tmpFile{WEB_TEMP_DIR};
|
||||
PresetBundleWriter::ptr presetbundleWriter = PresetBundleWriter::CreatePluginPresetsFile(*(this->model), content);
|
||||
presetbundleWriter->WriteToFile(tmpFile.Path());
|
||||
size_t contentLength = std::filesystem::file_size(tmpFile.Path());
|
||||
|
||||
|
||||
res.set(HttpField::content_type, PLUGIN_PRESETS_MIME_TYPE);
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
res.setContentLength(content.length());
|
||||
@@ -228,8 +240,8 @@ public:
|
||||
std::string content;
|
||||
GetPreset(request_uri, &name, &content);
|
||||
|
||||
TemporaryFile tmpFile { WEB_TEMP_DIR};
|
||||
PresetBundleWriter::ptr presetbundleWriter = PresetBundleWriter::CreatePresetsFile(*(this->model),content);
|
||||
TemporaryFile tmpFile{WEB_TEMP_DIR};
|
||||
PresetBundleWriter::ptr presetbundleWriter = PresetBundleWriter::CreatePresetsFile(*(this->model), content);
|
||||
presetbundleWriter->WriteToFile(tmpFile.Path());
|
||||
size_t contentLength = std::filesystem::file_size(tmpFile.Path());
|
||||
|
||||
@@ -245,14 +257,11 @@ public:
|
||||
std::string content;
|
||||
GetBank(request_uri, &name, &content);
|
||||
|
||||
TemporaryFile tmpFile { WEB_TEMP_DIR};
|
||||
PresetBundleWriter::ptr presetbundleWriter = PresetBundleWriter::CreatePresetsFile(*(this->model),content);
|
||||
TemporaryFile tmpFile{WEB_TEMP_DIR};
|
||||
PresetBundleWriter::ptr presetbundleWriter = PresetBundleWriter::CreatePresetsFile(*(this->model), content);
|
||||
presetbundleWriter->WriteToFile(tmpFile.Path());
|
||||
size_t contentLength = std::filesystem::file_size(tmpFile.Path());
|
||||
|
||||
|
||||
|
||||
|
||||
res.set(HttpField::content_type, BANK_MIME_TYPE);
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
res.set(HttpField::content_disposition, GetContentDispositionHeader(name, BANK_EXTENSION));
|
||||
@@ -290,12 +299,11 @@ public:
|
||||
std::string content;
|
||||
GetPluginPresets(request_uri, &name, &content);
|
||||
|
||||
std::shared_ptr<TemporaryFile> tmpFile =std::make_shared<TemporaryFile>(WEB_TEMP_DIR);
|
||||
PresetBundleWriter::ptr presetbundleWriter = PresetBundleWriter::CreatePluginPresetsFile(*(this->model),content);
|
||||
std::shared_ptr<TemporaryFile> tmpFile = std::make_shared<TemporaryFile>(WEB_TEMP_DIR);
|
||||
PresetBundleWriter::ptr presetbundleWriter = PresetBundleWriter::CreatePluginPresetsFile(*(this->model), content);
|
||||
presetbundleWriter->WriteToFile(tmpFile->Path());
|
||||
size_t contentLength = std::filesystem::file_size(tmpFile->Path());
|
||||
|
||||
|
||||
res.set(HttpField::content_type, PLUGIN_PRESETS_MIME_TYPE);
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
res.setContentLength(contentLength);
|
||||
@@ -308,12 +316,11 @@ public:
|
||||
std::string content;
|
||||
GetPreset(request_uri, &name, &content);
|
||||
|
||||
std::shared_ptr<TemporaryFile> tmpFile =std::make_shared<TemporaryFile>(WEB_TEMP_DIR);
|
||||
PresetBundleWriter::ptr presetbundleWriter = PresetBundleWriter::CreatePresetsFile(*(this->model),content);
|
||||
std::shared_ptr<TemporaryFile> tmpFile = std::make_shared<TemporaryFile>(WEB_TEMP_DIR);
|
||||
PresetBundleWriter::ptr presetbundleWriter = PresetBundleWriter::CreatePresetsFile(*(this->model), content);
|
||||
presetbundleWriter->WriteToFile(tmpFile->Path());
|
||||
size_t contentLength = std::filesystem::file_size(tmpFile->Path());
|
||||
|
||||
|
||||
res.set(HttpField::content_type, PRESET_MIME_TYPE);
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
res.setContentLength(contentLength);
|
||||
@@ -326,13 +333,11 @@ public:
|
||||
std::string content;
|
||||
GetBank(request_uri, &name, &content);
|
||||
|
||||
std::shared_ptr<TemporaryFile> tmpFile =std::make_shared<TemporaryFile>(WEB_TEMP_DIR);
|
||||
PresetBundleWriter::ptr presetbundleWriter = PresetBundleWriter::CreatePresetsFile(*(this->model),content);
|
||||
std::shared_ptr<TemporaryFile> tmpFile = std::make_shared<TemporaryFile>(WEB_TEMP_DIR);
|
||||
PresetBundleWriter::ptr presetbundleWriter = PresetBundleWriter::CreatePresetsFile(*(this->model), content);
|
||||
presetbundleWriter->WriteToFile(tmpFile->Path());
|
||||
size_t contentLength = std::filesystem::file_size(tmpFile->Path());
|
||||
|
||||
|
||||
|
||||
res.set(HttpField::content_type, BANK_MIME_TYPE);
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
res.setContentLength(contentLength);
|
||||
@@ -356,40 +361,49 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
static std::string GetFirstFolderOrFile(const std::vector<std::string>&fileNames)
|
||||
static std::string GetFirstFolderOrFile(const std::vector<std::string> &fileNames)
|
||||
{
|
||||
for (const auto &fileName: fileNames)
|
||||
for (const auto &fileName : fileNames)
|
||||
{
|
||||
size_t nPos = fileName.find('/');
|
||||
if (nPos != std::string::npos) {
|
||||
return fileName.substr(0,nPos);
|
||||
if (nPos != std::string::npos)
|
||||
{
|
||||
return fileName.substr(0, nPos);
|
||||
}
|
||||
}
|
||||
if (fileNames.size() == 0)
|
||||
{
|
||||
return 0;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return fileNames[0];
|
||||
}
|
||||
}
|
||||
static bool HasSingleRootDirectory(ZipFileReader&zipFile) {
|
||||
static bool HasSingleRootDirectory(ZipFileReader &zipFile)
|
||||
{
|
||||
bool hasDirectory = false;
|
||||
std::string previousDirectory;
|
||||
for (auto& file: zipFile.GetFiles())
|
||||
for (auto &file : zipFile.GetFiles())
|
||||
{
|
||||
auto pos = file.find('/');
|
||||
if (pos == std::string::npos) {
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
// a file in the root.
|
||||
return false;
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string currentRootDirectory = file.substr(0,pos);
|
||||
if (hasDirectory) {
|
||||
std::string currentRootDirectory = file.substr(0, pos);
|
||||
if (hasDirectory)
|
||||
{
|
||||
if (currentRootDirectory != previousDirectory)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
hasDirectory = true;
|
||||
previousDirectory = currentRootDirectory;
|
||||
}
|
||||
@@ -412,26 +426,26 @@ public:
|
||||
{
|
||||
PluginPresets presets;
|
||||
fs::path filePath = req.get_body_temporary_file();
|
||||
if (filePath.empty())
|
||||
if (filePath.empty())
|
||||
{
|
||||
throw std::runtime_error("Unexpected.");
|
||||
}
|
||||
if (IsZipFile(filePath))
|
||||
{
|
||||
auto presetReader = PresetBundleReader::LoadPluginPresetsFile(*(this->model),filePath);
|
||||
auto presetReader = PresetBundleReader::LoadPluginPresetsFile(*(this->model), filePath);
|
||||
presetReader->ExtractMediaFiles();
|
||||
|
||||
std::stringstream ss(presetReader->GetPluginPresetsJson());
|
||||
json_reader reader(ss);
|
||||
reader.read(&presets);
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
json_reader reader(req.get_body_input_stream());
|
||||
reader.read(&presets);
|
||||
}
|
||||
model->UploadPluginPresets(presets);
|
||||
|
||||
|
||||
res.set(HttpField::content_type, "application/json");
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
std::stringstream sResult;
|
||||
@@ -447,19 +461,21 @@ public:
|
||||
BankFile bankFile;
|
||||
|
||||
fs::path filePath = req.get_body_temporary_file();
|
||||
if (filePath.empty())
|
||||
if (filePath.empty())
|
||||
{
|
||||
throw std::runtime_error("Unexpected.");
|
||||
}
|
||||
if (IsZipFile(filePath))
|
||||
{
|
||||
auto presetReader = PresetBundleReader::LoadPresetsFile(*(this->model),filePath);
|
||||
{
|
||||
auto presetReader = PresetBundleReader::LoadPresetsFile(*(this->model), filePath);
|
||||
presetReader->ExtractMediaFiles();
|
||||
|
||||
std::stringstream ss(presetReader->GetPresetJson());
|
||||
json_reader reader(ss);
|
||||
reader.read(&bankFile);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// legacy json format, no zip, no media files.
|
||||
json_reader reader(req.get_body_input_stream());
|
||||
reader.read(&bankFile);
|
||||
@@ -487,19 +503,21 @@ public:
|
||||
BankFile bankFile;
|
||||
|
||||
fs::path filePath = req.get_body_temporary_file();
|
||||
if (filePath.empty())
|
||||
if (filePath.empty())
|
||||
{
|
||||
throw std::runtime_error("Unexpected.");
|
||||
}
|
||||
if (IsZipFile(filePath))
|
||||
{
|
||||
auto presetReader = PresetBundleReader::LoadPresetsFile(*(this->model),filePath);
|
||||
{
|
||||
auto presetReader = PresetBundleReader::LoadPresetsFile(*(this->model), filePath);
|
||||
presetReader->ExtractMediaFiles();
|
||||
|
||||
std::stringstream ss(presetReader->GetPresetJson());
|
||||
json_reader reader(ss);
|
||||
reader.read(&bankFile);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// legacy json format, no zip, no media files.
|
||||
json_reader reader(req.get_body_input_stream());
|
||||
reader.read(&bankFile);
|
||||
@@ -522,70 +540,88 @@ public:
|
||||
res.setContentLength(result.length());
|
||||
|
||||
res.setBody(result);
|
||||
} else if (segment == "uploadUserFile")
|
||||
}
|
||||
else if (segment == "uploadUserFile")
|
||||
{
|
||||
res.set(HttpField::content_type, "application/json");
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
std::string instanceId = request_uri.query("id");
|
||||
std::string directory = request_uri.query("directory");
|
||||
std::string filename = request_uri.query("filename");
|
||||
std::string patchProperty = request_uri.query("property");
|
||||
|
||||
|
||||
if (patchProperty.length() == 0 && directory.length() == 0)
|
||||
UserUploadResponse result;
|
||||
try
|
||||
{
|
||||
throw PiPedalException("Malformed request.");
|
||||
|
||||
}
|
||||
res.set(HttpField::content_type, "application/json");
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
std::string instanceId = request_uri.query("id");
|
||||
std::string directory = request_uri.query("directory");
|
||||
std::string filename = request_uri.query("filename");
|
||||
std::string patchProperty = request_uri.query("property");
|
||||
|
||||
res.set(HttpField::content_type, "application/json");
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
if (patchProperty.length() == 0 && directory.length() == 0)
|
||||
{
|
||||
throw PiPedalException("Malformed request.");
|
||||
}
|
||||
|
||||
std::string outputFileName = std::filesystem::path(directory) / filename;
|
||||
res.set(HttpField::content_type, "application/json");
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
|
||||
if (filename.ends_with(".zip"))
|
||||
{
|
||||
ExtensionChecker extensionChecker { request_uri.query("ext") };
|
||||
namespace fs = std::filesystem;
|
||||
fs::path outputFileName = std::filesystem::path(directory) / filename;
|
||||
|
||||
try {
|
||||
auto zipFile = ZipFileReader::Create(req.get_body_temporary_file());
|
||||
std::vector<std::string> files = zipFile->GetFiles();
|
||||
bool hasSingleRootDirectory = HasSingleRootDirectory(*zipFile);
|
||||
if (!hasSingleRootDirectory) {
|
||||
directory = (fs::path(directory) / fs::path(filename).filename().replace_extension("")).string();
|
||||
}
|
||||
for (const auto&inputFile : files)
|
||||
if (filename.ends_with(".zip"))
|
||||
{
|
||||
ExtensionChecker extensionChecker{request_uri.query("ext")};
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
try
|
||||
{
|
||||
if (!inputFile.ends_with("/")) // don't process directory entries.
|
||||
auto zipFile = ZipFileReader::Create(req.get_body_temporary_file());
|
||||
std::vector<std::string> files = zipFile->GetFiles();
|
||||
bool hasSingleRootDirectory = HasSingleRootDirectory(*zipFile);
|
||||
if (!hasSingleRootDirectory)
|
||||
{
|
||||
fs::path inputPath { inputFile};
|
||||
std::string extension = inputPath.extension();
|
||||
if (extensionChecker.IsValidExtension(extension))
|
||||
directory = (fs::path(directory) / fs::path(filename).filename().replace_extension("")).string();
|
||||
}
|
||||
for (const auto &inputFile : files)
|
||||
{
|
||||
if (!inputFile.ends_with("/")) // don't process directory entries.
|
||||
{
|
||||
auto si = zipFile->GetFileInputStream(inputFile);
|
||||
std::string path = this->model->UploadUserFile(directory,patchProperty,inputFile, si,zipFile->GetFileSize(inputFile));
|
||||
fs::path inputPath{inputFile};
|
||||
std::string extension = inputPath.extension();
|
||||
if (extensionChecker.IsValidExtension(extension))
|
||||
{
|
||||
auto si = zipFile->GetFileInputStream(inputFile);
|
||||
std::string path = this->model->UploadUserFile(directory, patchProperty, inputFile, si, zipFile->GetFileSize(inputFile));
|
||||
}
|
||||
}
|
||||
}
|
||||
// set outputPath to the file or folder we would like focus to go to.
|
||||
// almost always a single folder in the root.
|
||||
std::string returnPath = GetFirstFolderOrFile(files);
|
||||
outputFileName = fs::path(directory) / returnPath;
|
||||
}
|
||||
// set outputPath to the file or folder we would like focus to go to.
|
||||
// almost always a single folder in the root.
|
||||
std::string returnPath = GetFirstFolderOrFile(files);
|
||||
outputFileName = this->model->GetPluginUploadDirectory() / directory / returnPath;
|
||||
} catch (const std::exception &e)
|
||||
{
|
||||
Lv2Log::error(SS("Unzip failed. " << e.what()));
|
||||
throw;
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Lv2Log::error(SS("Unzip failed. " << e.what()));
|
||||
throw;
|
||||
}
|
||||
FileSystemSync();
|
||||
}
|
||||
else
|
||||
{
|
||||
outputFileName = this->model->UploadUserFile(directory, patchProperty, filename, req.get_body_input_stream(), req.content_length());
|
||||
}
|
||||
FileSystemSync();
|
||||
|
||||
} else {
|
||||
outputFileName = this->model->UploadUserFile(directory,patchProperty,filename,req.get_body_input_stream(), req.content_length());
|
||||
if (outputFileName.is_relative())
|
||||
{
|
||||
outputFileName = this->model->GetPluginUploadDirectory() / outputFileName;
|
||||
}
|
||||
result.path_ = outputFileName.string();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
result.errorMessage_ = e.what();
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
json_writer writer(ss);
|
||||
writer.write(outputFileName);
|
||||
writer.write(result);
|
||||
std::string response = ss.str();
|
||||
|
||||
res.setContentLength(response.length());
|
||||
@@ -598,7 +634,7 @@ public:
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Lv2Log::error(SS("Error uploading file: " << e.what()) );
|
||||
Lv2Log::error(SS("Error uploading file: " << e.what()));
|
||||
if (strcmp(e.what(), "Not found") == 0)
|
||||
{
|
||||
ec = boost::system::errc::make_error_code(boost::system::errc::no_such_file_or_directory);
|
||||
@@ -611,7 +647,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static std::string StripPortNumber(const std::string &fromAddress)
|
||||
{
|
||||
std::string address = fromAddress;
|
||||
@@ -663,10 +698,10 @@ public:
|
||||
std::stringstream s;
|
||||
|
||||
s << "{ \"socket_server_port\": " << portNumber
|
||||
<< ", \"socket_server_address\": \"" << webSocketAddress
|
||||
<< ", \"socket_server_address\": \"" << webSocketAddress
|
||||
<< "\", \"ui_plugins\": [ ], \"max_upload_size\": " << maxUploadSize
|
||||
<< ", \"enable_auto_update\": " << (ENABLE_AUTO_UPDATE ? " true": "false")
|
||||
<< " }";
|
||||
<< ", \"enable_auto_update\": " << (ENABLE_AUTO_UPDATE ? " true" : "false")
|
||||
<< " }";
|
||||
|
||||
return s.str();
|
||||
}
|
||||
@@ -720,16 +755,14 @@ public:
|
||||
};
|
||||
|
||||
void pipedal::ConfigureWebServer(
|
||||
WebServer&server,
|
||||
PiPedalModel&model,
|
||||
WebServer &server,
|
||||
PiPedalModel &model,
|
||||
int port,
|
||||
size_t maxUploadSize)
|
||||
{
|
||||
std::shared_ptr<RequestHandler> interceptConfig{new InterceptConfig(port, maxUploadSize)};
|
||||
server.AddRequestHandler(interceptConfig);
|
||||
|
||||
std::shared_ptr<DownloadIntercept> downloadIntercept = std::make_shared<DownloadIntercept>(&model);
|
||||
server.AddRequestHandler(downloadIntercept);
|
||||
|
||||
std::shared_ptr<RequestHandler> interceptConfig{new InterceptConfig(port, maxUploadSize)};
|
||||
server.AddRequestHandler(interceptConfig);
|
||||
|
||||
std::shared_ptr<DownloadIntercept> downloadIntercept = std::make_shared<DownloadIntercept>(&model);
|
||||
server.AddRequestHandler(downloadIntercept);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user