mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-10-11 09:16:40 +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 {}
|
filter {}
|
||||||
|
|
||||||
self:include(includes)
|
self:include(includes)
|
||||||
|
Utils:include(includes)
|
||||||
|
json:include(includes)
|
||||||
webview:include(includes)
|
webview:include(includes)
|
||||||
|
|
||||||
|
links:linkto(Utils)
|
||||||
links:linkto(webview)
|
links:linkto(webview)
|
||||||
links:linkall()
|
links:linkall()
|
||||||
end
|
end
|
||||||
|
@@ -2,11 +2,6 @@
|
|||||||
|
|
||||||
#if defined(WEBVIEW_PLATFORM_WINDOWS) && defined(WEBVIEW_EDGE)
|
#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 "Web/UiAssets.h"
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
@@ -55,7 +50,7 @@ namespace
|
|||||||
std::wstringstream wss;
|
std::wstringstream wss;
|
||||||
|
|
||||||
wss << std::format(L"Content-Length: {}\n", contentLength);
|
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();
|
return wss.str();
|
||||||
}
|
}
|
||||||
@@ -151,7 +146,7 @@ namespace edge
|
|||||||
{
|
{
|
||||||
void InstallCustomProtocolHandler(webview::webview& wv)
|
void InstallCustomProtocolHandler(webview::webview& wv)
|
||||||
{
|
{
|
||||||
assetLookup = BuildUiFileLookup();
|
assetLookup = ui::BuildUiFileLookup();
|
||||||
|
|
||||||
const auto controller = static_cast<ICoreWebView2Controller*>(wv.browser_controller().value());
|
const auto controller = static_cast<ICoreWebView2Controller*>(wv.browser_controller().value());
|
||||||
Microsoft::WRL::ComPtr<ICoreWebView2> core;
|
Microsoft::WRL::ComPtr<ICoreWebView2> core;
|
||||||
|
@@ -4,9 +4,7 @@
|
|||||||
|
|
||||||
#if defined(WEBVIEW_PLATFORM_WINDOWS) && defined(WEBVIEW_EDGE)
|
#if defined(WEBVIEW_PLATFORM_WINDOWS) && defined(WEBVIEW_EDGE)
|
||||||
|
|
||||||
#pragma warning(push, 0)
|
#include "Web/WebViewLib.h"
|
||||||
#include <webview/webview.h>
|
|
||||||
#pragma warning(pop)
|
|
||||||
|
|
||||||
namespace edge
|
namespace edge
|
||||||
{
|
{
|
||||||
|
@@ -2,12 +2,6 @@
|
|||||||
|
|
||||||
#if defined(WEBVIEW_PLATFORM_LINUX) && defined(WEBVIEW_GTK)
|
#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 "Web/UiAssets.h"
|
||||||
|
|
||||||
#include <format>
|
#include <format>
|
||||||
@@ -27,7 +21,7 @@ namespace
|
|||||||
gsize stream_length = foundUiFile->second.dataSize;
|
gsize stream_length = foundUiFile->second.dataSize;
|
||||||
GInputStream* stream = g_memory_input_stream_new_from_data(foundUiFile->second.data, foundUiFile->second.dataSize, nullptr);
|
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);
|
g_object_unref(stream);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -48,7 +42,7 @@ namespace gtk
|
|||||||
const auto webView = WEBKIT_WEB_VIEW(widget);
|
const auto webView = WEBKIT_WEB_VIEW(widget);
|
||||||
const auto context = webkit_web_view_get_context(webView);
|
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);
|
webkit_web_context_register_uri_scheme(context, "modman", ModManUriSchemeRequestCb, NULL, nullptr);
|
||||||
}
|
}
|
||||||
|
@@ -4,10 +4,7 @@
|
|||||||
|
|
||||||
#if defined(WEBVIEW_PLATFORM_LINUX) && defined(WEBVIEW_GTK)
|
#if defined(WEBVIEW_PLATFORM_LINUX) && defined(WEBVIEW_GTK)
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
#include "Web/WebViewLib.h"
|
||||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
||||||
#include <webview/webview.h>
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
|
|
||||||
namespace gtk
|
namespace gtk
|
||||||
{
|
{
|
||||||
|
@@ -2,30 +2,33 @@
|
|||||||
|
|
||||||
#include <format>
|
#include <format>
|
||||||
|
|
||||||
std::unordered_map<std::string, UiFile> BuildUiFileLookup()
|
namespace ui
|
||||||
{
|
{
|
||||||
std::unordered_map<std::string, UiFile> result;
|
std::unordered_map<std::string, UiFile> BuildUiFileLookup()
|
||||||
|
|
||||||
for (const auto& asset : MOD_MAN_UI_FILES)
|
|
||||||
{
|
{
|
||||||
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)
|
if (fileName.ends_with(".html"))
|
||||||
{
|
mimeType = "text/html";
|
||||||
const char* mimeType;
|
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"))
|
return mimeType;
|
||||||
mimeType = "text/html";
|
}
|
||||||
else if (fileName.ends_with(".js"))
|
} // namespace ui
|
||||||
mimeType = "text/javascript";
|
|
||||||
else if (fileName.ends_with(".css"))
|
|
||||||
mimeType = "text/css";
|
|
||||||
else
|
|
||||||
mimeType = "application/octet-stream";
|
|
||||||
|
|
||||||
return mimeType;
|
|
||||||
}
|
|
||||||
|
@@ -5,5 +5,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
std::unordered_map<std::string, UiFile> BuildUiFileLookup();
|
namespace ui
|
||||||
const char* GetMimeTypeForFileName(const std::string& fileName);
|
{
|
||||||
|
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
|
#include "GitVersion.h"
|
||||||
#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 "Web/Edge/AssetHandlerEdge.h"
|
#include "Web/Edge/AssetHandlerEdge.h"
|
||||||
#include "Web/Gtk/AssetHandlerGtk.h"
|
#include "Web/Gtk/AssetHandlerGtk.h"
|
||||||
|
#include "Web/UiCommunication.h"
|
||||||
#include "Web/ViteAssets.h"
|
#include "Web/ViteAssets.h"
|
||||||
|
#include "Web/WebViewLib.h"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <format>
|
#include <format>
|
||||||
@@ -31,8 +19,10 @@ namespace
|
|||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
std::optional<webview::webview> devToolWindow;
|
std::optional<webview::webview> devToolWindow;
|
||||||
|
|
||||||
void RunDevToolsWindow(webview::webview& parent)
|
void RunDevToolsWindow()
|
||||||
{
|
{
|
||||||
|
con::debug("Creating dev tools window");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
auto& newWindow = devToolWindow.emplace(false, nullptr);
|
auto& newWindow = devToolWindow.emplace(false, nullptr);
|
||||||
@@ -50,6 +40,8 @@ namespace
|
|||||||
|
|
||||||
int RunMainWindow()
|
int RunMainWindow()
|
||||||
{
|
{
|
||||||
|
con::debug("Creating main window");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
webview::webview w(
|
webview::webview w(
|
||||||
@@ -64,32 +56,37 @@ namespace
|
|||||||
w.set_size(480, 320, WEBVIEW_HINT_MIN);
|
w.set_size(480, 320, WEBVIEW_HINT_MIN);
|
||||||
|
|
||||||
// A binding that counts up or down and immediately returns the new value.
|
// A binding that counts up or down and immediately returns the new value.
|
||||||
w.bind("greet",
|
ui::Bind<std::string, std::string>(w,
|
||||||
[&](const std::string& req) -> std::string
|
"greet",
|
||||||
{
|
[&w](std::string name) -> std::string
|
||||||
const auto name = req.substr(2, req.size() - 4);
|
{
|
||||||
w.notify("greeting", webview::json_escape(name));
|
ui::Notify(w, "greeting", name);
|
||||||
return webview::json_escape(std::format("Hello from C++ {}!", 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.
|
// A binding that creates a new thread and returns the result at a later time.
|
||||||
w.bind(
|
ui::BindAsync(w,
|
||||||
"compute",
|
"compute",
|
||||||
[&](const std::string& id, const std::string& req, void* /*arg*/)
|
[&](const std::string& id)
|
||||||
{
|
{
|
||||||
// Create a thread and forget about it for the sake of simplicity.
|
// Create a thread and forget about it for the sake of simplicity.
|
||||||
std::thread(
|
std::thread(
|
||||||
[&, id, req]
|
[&, id]
|
||||||
{
|
{
|
||||||
// Simulate load.
|
// Simulate load.
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||||
// Imagine that req is properly parsed or use your own JSON parser.
|
ui::PromiseResolve(w, id, 42);
|
||||||
const auto* result = "42";
|
})
|
||||||
w.resolve(id, 0, result);
|
.detach();
|
||||||
})
|
});
|
||||||
.detach();
|
|
||||||
},
|
|
||||||
nullptr);
|
|
||||||
|
|
||||||
#if defined(WEBVIEW_PLATFORM_WINDOWS) && defined(WEBVIEW_EDGE)
|
#if defined(WEBVIEW_PLATFORM_WINDOWS) && defined(WEBVIEW_EDGE)
|
||||||
edge::InstallCustomProtocolHandler(w);
|
edge::InstallCustomProtocolHandler(w);
|
||||||
@@ -107,9 +104,9 @@ namespace
|
|||||||
if (VITE_DEV_SERVER)
|
if (VITE_DEV_SERVER)
|
||||||
{
|
{
|
||||||
w.dispatch(
|
w.dispatch(
|
||||||
[&w]
|
[]
|
||||||
{
|
{
|
||||||
RunDevToolsWindow(w);
|
RunDevToolsWindow();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -135,6 +132,8 @@ int main()
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
con::info("Starting ModMan " GIT_VERSION);
|
||||||
|
|
||||||
const auto result = RunMainWindow();
|
const auto result = RunMainWindow();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
Reference in New Issue
Block a user