mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-10-09 08:16:41 +00:00
feat: add nlohmann json based wrappers for webview binds,notify
This commit is contained in:
@@ -46,8 +46,11 @@ function ModMan:project()
|
||||
filter {}
|
||||
|
||||
self:include(includes)
|
||||
Utils:include(includes)
|
||||
json:include(includes)
|
||||
webview:include(includes)
|
||||
|
||||
links:linkto(Utils)
|
||||
links:linkto(webview)
|
||||
links:linkall()
|
||||
end
|
||||
|
@@ -2,11 +2,6 @@
|
||||
|
||||
#if defined(WEBVIEW_PLATFORM_WINDOWS) && defined(WEBVIEW_EDGE)
|
||||
|
||||
#pragma warning(push, 0)
|
||||
#include <webview/macros.h>
|
||||
#include <webview/webview.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#include "Web/UiAssets.h"
|
||||
|
||||
#include <Windows.h>
|
||||
@@ -55,7 +50,7 @@ namespace
|
||||
std::wstringstream wss;
|
||||
|
||||
wss << std::format(L"Content-Length: {}\n", contentLength);
|
||||
wss << L"Content-Type: " << StringToWideString(GetMimeTypeForFileName(assetName));
|
||||
wss << L"Content-Type: " << StringToWideString(ui::GetMimeTypeForFileName(assetName));
|
||||
|
||||
return wss.str();
|
||||
}
|
||||
@@ -151,7 +146,7 @@ namespace edge
|
||||
{
|
||||
void InstallCustomProtocolHandler(webview::webview& wv)
|
||||
{
|
||||
assetLookup = BuildUiFileLookup();
|
||||
assetLookup = ui::BuildUiFileLookup();
|
||||
|
||||
const auto controller = static_cast<ICoreWebView2Controller*>(wv.browser_controller().value());
|
||||
Microsoft::WRL::ComPtr<ICoreWebView2> core;
|
||||
|
@@ -4,9 +4,7 @@
|
||||
|
||||
#if defined(WEBVIEW_PLATFORM_WINDOWS) && defined(WEBVIEW_EDGE)
|
||||
|
||||
#pragma warning(push, 0)
|
||||
#include <webview/webview.h>
|
||||
#pragma warning(pop)
|
||||
#include "Web/WebViewLib.h"
|
||||
|
||||
namespace edge
|
||||
{
|
||||
|
@@ -2,12 +2,6 @@
|
||||
|
||||
#if defined(WEBVIEW_PLATFORM_LINUX) && defined(WEBVIEW_GTK)
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#include <webview/macros.h>
|
||||
#include <webview/webview.h>
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#include "Web/UiAssets.h"
|
||||
|
||||
#include <format>
|
||||
@@ -27,7 +21,7 @@ namespace
|
||||
gsize stream_length = foundUiFile->second.dataSize;
|
||||
GInputStream* stream = g_memory_input_stream_new_from_data(foundUiFile->second.data, foundUiFile->second.dataSize, nullptr);
|
||||
|
||||
webkit_uri_scheme_request_finish(request, stream, stream_length, GetMimeTypeForFileName(foundUiFile->second.filename));
|
||||
webkit_uri_scheme_request_finish(request, stream, stream_length, ui::GetMimeTypeForFileName(foundUiFile->second.filename));
|
||||
g_object_unref(stream);
|
||||
}
|
||||
else
|
||||
@@ -48,7 +42,7 @@ namespace gtk
|
||||
const auto webView = WEBKIT_WEB_VIEW(widget);
|
||||
const auto context = webkit_web_view_get_context(webView);
|
||||
|
||||
assetLookup = BuildUiFileLookup();
|
||||
assetLookup = ui::BuildUiFileLookup();
|
||||
|
||||
webkit_web_context_register_uri_scheme(context, "modman", ModManUriSchemeRequestCb, NULL, nullptr);
|
||||
}
|
||||
|
@@ -4,10 +4,7 @@
|
||||
|
||||
#if defined(WEBVIEW_PLATFORM_LINUX) && defined(WEBVIEW_GTK)
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#include <webview/webview.h>
|
||||
#pragma GCC diagnostic pop
|
||||
#include "Web/WebViewLib.h"
|
||||
|
||||
namespace gtk
|
||||
{
|
||||
|
@@ -2,30 +2,33 @@
|
||||
|
||||
#include <format>
|
||||
|
||||
std::unordered_map<std::string, UiFile> BuildUiFileLookup()
|
||||
namespace ui
|
||||
{
|
||||
std::unordered_map<std::string, UiFile> result;
|
||||
|
||||
for (const auto& asset : MOD_MAN_UI_FILES)
|
||||
std::unordered_map<std::string, UiFile> BuildUiFileLookup()
|
||||
{
|
||||
result.emplace(std::format("/{}", asset.filename), asset);
|
||||
std::unordered_map<std::string, UiFile> result;
|
||||
|
||||
for (const auto& asset : MOD_MAN_UI_FILES)
|
||||
{
|
||||
result.emplace(std::format("/{}", asset.filename), asset);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
const char* GetMimeTypeForFileName(const std::string& fileName)
|
||||
{
|
||||
const char* mimeType;
|
||||
|
||||
const char* GetMimeTypeForFileName(const std::string& fileName)
|
||||
{
|
||||
const char* mimeType;
|
||||
if (fileName.ends_with(".html"))
|
||||
mimeType = "text/html";
|
||||
else if (fileName.ends_with(".js"))
|
||||
mimeType = "text/javascript";
|
||||
else if (fileName.ends_with(".css"))
|
||||
mimeType = "text/css";
|
||||
else
|
||||
mimeType = "application/octet-stream";
|
||||
|
||||
if (fileName.ends_with(".html"))
|
||||
mimeType = "text/html";
|
||||
else if (fileName.ends_with(".js"))
|
||||
mimeType = "text/javascript";
|
||||
else if (fileName.ends_with(".css"))
|
||||
mimeType = "text/css";
|
||||
else
|
||||
mimeType = "application/octet-stream";
|
||||
|
||||
return mimeType;
|
||||
}
|
||||
return mimeType;
|
||||
}
|
||||
} // namespace ui
|
||||
|
@@ -5,5 +5,8 @@
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
std::unordered_map<std::string, UiFile> BuildUiFileLookup();
|
||||
const char* GetMimeTypeForFileName(const std::string& fileName);
|
||||
namespace ui
|
||||
{
|
||||
std::unordered_map<std::string, UiFile> BuildUiFileLookup();
|
||||
const char* GetMimeTypeForFileName(const std::string& fileName);
|
||||
} // namespace ui
|
||||
|
0
src/ModMan/Web/UiCommunication.cpp
Normal file
0
src/ModMan/Web/UiCommunication.cpp
Normal file
142
src/ModMan/Web/UiCommunication.h
Normal file
142
src/ModMan/Web/UiCommunication.h
Normal file
@@ -0,0 +1,142 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utils/Logging/Log.h"
|
||||
#include "WebViewLib.h"
|
||||
|
||||
#pragma warning(push, 0)
|
||||
#include <nlohmann/json.hpp>
|
||||
#pragma warning(pop)
|
||||
|
||||
namespace ui
|
||||
{
|
||||
inline void Bind(webview::webview& wv, const std::string& name, std::function<void()> fn)
|
||||
{
|
||||
wv.bind(name,
|
||||
[fn](const std::string& req) -> std::string
|
||||
{
|
||||
fn();
|
||||
return "";
|
||||
});
|
||||
}
|
||||
|
||||
template<typename TInput> void Bind(webview::webview& wv, const std::string& name, std::function<void(TInput)> fn)
|
||||
{
|
||||
wv.bind(name,
|
||||
[fn](const std::string& req) -> std::string
|
||||
{
|
||||
TInput param;
|
||||
try
|
||||
{
|
||||
const auto json = nlohmann::json::parse(req);
|
||||
if (!json.is_array())
|
||||
{
|
||||
con::error("Webview params are not an array: {}", req);
|
||||
return "";
|
||||
}
|
||||
param = json.at(0).get<TInput>();
|
||||
}
|
||||
catch (const nlohmann::json::exception& e)
|
||||
{
|
||||
con::error("Failed to parse json of webview call: {}", e.what());
|
||||
return "";
|
||||
}
|
||||
|
||||
fn(std::move(param));
|
||||
|
||||
return "";
|
||||
});
|
||||
}
|
||||
|
||||
template<typename TReturn> void BindRetOnly(webview::webview& wv, const std::string& name, std::function<TReturn()> fn)
|
||||
{
|
||||
wv.bind(name,
|
||||
[fn](const std::string& req) -> std::string
|
||||
{
|
||||
auto result = fn();
|
||||
|
||||
return nlohmann::json(result).dump();
|
||||
});
|
||||
}
|
||||
|
||||
template<typename TInput, typename TReturn> void Bind(webview::webview& wv, const std::string& name, std::function<TReturn(TInput)> fn)
|
||||
{
|
||||
wv.bind(name,
|
||||
[fn](const std::string& req) -> std::string
|
||||
{
|
||||
TInput param;
|
||||
try
|
||||
{
|
||||
const auto json = nlohmann::json::parse(req);
|
||||
if (!json.is_array())
|
||||
{
|
||||
con::error("Webview params are not an array: {}", req);
|
||||
return "";
|
||||
}
|
||||
param = json.at(0).get<TInput>();
|
||||
}
|
||||
catch (const nlohmann::json::exception& e)
|
||||
{
|
||||
con::error("Failed to parse json of webview call: {}", e.what());
|
||||
return "";
|
||||
}
|
||||
|
||||
auto result = fn(std::move(param));
|
||||
|
||||
return nlohmann::json(result).dump();
|
||||
});
|
||||
}
|
||||
|
||||
inline void BindAsync(webview::webview& wv, const std::string& name, std::function<void(const std::string& id)> fn)
|
||||
{
|
||||
wv.bind(
|
||||
name,
|
||||
[fn](const std::string& id, const std::string& req, void* /* arg */)
|
||||
{
|
||||
fn(id);
|
||||
},
|
||||
nullptr);
|
||||
}
|
||||
|
||||
template<typename TInput> void BindAsync(webview::webview& wv, const std::string& name, std::function<void(const std::string& id, TInput)> fn)
|
||||
{
|
||||
wv.bind(
|
||||
name,
|
||||
[fn](const std::string& id, const std::string& req, void* /* arg */)
|
||||
{
|
||||
TInput param;
|
||||
try
|
||||
{
|
||||
const auto json = nlohmann::json::parse(req);
|
||||
if (!json.is_array())
|
||||
{
|
||||
con::error("Webview params are not an array: {}", req);
|
||||
return "";
|
||||
}
|
||||
param = json.at(0).get<TInput>();
|
||||
}
|
||||
catch (const nlohmann::json::exception& e)
|
||||
{
|
||||
con::error("Failed to parse json of webview call: {}", e.what());
|
||||
return "";
|
||||
}
|
||||
|
||||
fn(id, std::move(param));
|
||||
},
|
||||
nullptr);
|
||||
}
|
||||
|
||||
template<typename TPayload> void PromiseResolve(webview::webview& wv, const std::string& id, const TPayload& payload)
|
||||
{
|
||||
wv.resolve(id, 0, nlohmann::json(payload).dump());
|
||||
}
|
||||
|
||||
template<typename TPayload> void PromiseReject(webview::webview& wv, const std::string& id, const TPayload& payload)
|
||||
{
|
||||
wv.resolve(id, 1, nlohmann::json(payload).dump());
|
||||
}
|
||||
|
||||
template<typename TPayload> void Notify(webview::webview& wv, const std::string& eventKey, const TPayload& payload)
|
||||
{
|
||||
wv.notify(eventKey, nlohmann::json(payload).dump());
|
||||
}
|
||||
} // namespace ui
|
20
src/ModMan/Web/WebViewLib.h
Normal file
20
src/ModMan/Web/WebViewLib.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
#include <webview/webview.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#ifdef ERROR
|
||||
#undef ERROR
|
||||
#endif
|
@@ -1,21 +1,9 @@
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
#include "webview/webview.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include "GitVersion.h"
|
||||
#include "Web/Edge/AssetHandlerEdge.h"
|
||||
#include "Web/Gtk/AssetHandlerGtk.h"
|
||||
#include "Web/UiCommunication.h"
|
||||
#include "Web/ViteAssets.h"
|
||||
#include "Web/WebViewLib.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <format>
|
||||
@@ -31,8 +19,10 @@ namespace
|
||||
#ifdef _DEBUG
|
||||
std::optional<webview::webview> devToolWindow;
|
||||
|
||||
void RunDevToolsWindow(webview::webview& parent)
|
||||
void RunDevToolsWindow()
|
||||
{
|
||||
con::debug("Creating dev tools window");
|
||||
|
||||
try
|
||||
{
|
||||
auto& newWindow = devToolWindow.emplace(false, nullptr);
|
||||
@@ -50,6 +40,8 @@ namespace
|
||||
|
||||
int RunMainWindow()
|
||||
{
|
||||
con::debug("Creating main window");
|
||||
|
||||
try
|
||||
{
|
||||
webview::webview w(
|
||||
@@ -64,32 +56,37 @@ namespace
|
||||
w.set_size(480, 320, WEBVIEW_HINT_MIN);
|
||||
|
||||
// A binding that counts up or down and immediately returns the new value.
|
||||
w.bind("greet",
|
||||
[&](const std::string& req) -> std::string
|
||||
{
|
||||
const auto name = req.substr(2, req.size() - 4);
|
||||
w.notify("greeting", webview::json_escape(name));
|
||||
return webview::json_escape(std::format("Hello from C++ {}!", name));
|
||||
});
|
||||
ui::Bind<std::string, std::string>(w,
|
||||
"greet",
|
||||
[&w](std::string name) -> std::string
|
||||
{
|
||||
ui::Notify(w, "greeting", name);
|
||||
return std::format("Hello from C++ {}!", name);
|
||||
});
|
||||
|
||||
// A binding that counts up or down and immediately returns the new value.
|
||||
ui::Bind(w,
|
||||
"debug",
|
||||
[]()
|
||||
{
|
||||
con::info("Debug");
|
||||
});
|
||||
|
||||
// A binding that creates a new thread and returns the result at a later time.
|
||||
w.bind(
|
||||
"compute",
|
||||
[&](const std::string& id, const std::string& req, void* /*arg*/)
|
||||
{
|
||||
// Create a thread and forget about it for the sake of simplicity.
|
||||
std::thread(
|
||||
[&, id, req]
|
||||
{
|
||||
// Simulate load.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
// Imagine that req is properly parsed or use your own JSON parser.
|
||||
const auto* result = "42";
|
||||
w.resolve(id, 0, result);
|
||||
})
|
||||
.detach();
|
||||
},
|
||||
nullptr);
|
||||
ui::BindAsync(w,
|
||||
"compute",
|
||||
[&](const std::string& id)
|
||||
{
|
||||
// Create a thread and forget about it for the sake of simplicity.
|
||||
std::thread(
|
||||
[&, id]
|
||||
{
|
||||
// Simulate load.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
ui::PromiseResolve(w, id, 42);
|
||||
})
|
||||
.detach();
|
||||
});
|
||||
|
||||
#if defined(WEBVIEW_PLATFORM_WINDOWS) && defined(WEBVIEW_EDGE)
|
||||
edge::InstallCustomProtocolHandler(w);
|
||||
@@ -107,9 +104,9 @@ namespace
|
||||
if (VITE_DEV_SERVER)
|
||||
{
|
||||
w.dispatch(
|
||||
[&w]
|
||||
[]
|
||||
{
|
||||
RunDevToolsWindow(w);
|
||||
RunDevToolsWindow();
|
||||
});
|
||||
}
|
||||
#else
|
||||
@@ -135,6 +132,8 @@ int main()
|
||||
{
|
||||
#endif
|
||||
|
||||
con::info("Starting ModMan " GIT_VERSION);
|
||||
|
||||
const auto result = RunMainWindow();
|
||||
|
||||
return result;
|
||||
|
Reference in New Issue
Block a user