bunite-core 0.0.1 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/src/bun/core/App.ts +155 -15
- package/src/bun/core/BrowserView.ts +124 -44
- package/src/bun/core/BrowserWindow.ts +94 -47
- package/src/bun/core/Socket.ts +2 -1
- package/src/bun/core/SurfaceBrowserIPC.ts +65 -0
- package/src/bun/core/SurfaceManager.ts +201 -0
- package/src/bun/core/SurfaceRegistry.ts +60 -0
- package/src/bun/core/Utils.ts +275 -46
- package/src/bun/events/appEvents.ts +2 -1
- package/src/bun/events/webviewEvents.ts +1 -3
- package/src/bun/events/windowEvents.ts +2 -0
- package/src/bun/index.ts +4 -3
- package/src/bun/preload/inline.ts +19 -25
- package/src/bun/proc/native.ts +158 -122
- package/src/native/shared/callbacks.h +6 -6
- package/src/native/shared/ffi_exports.h +123 -119
- package/src/native/shared/log.h +24 -0
- package/src/native/shared/webview_storage.h +5 -5
- package/src/native/win/native_host_appres.cpp +258 -0
- package/src/native/win/native_host_cef.cpp +834 -0
- package/src/native/win/native_host_ffi.cpp +935 -0
- package/src/native/win/native_host_internal.h +285 -0
- package/src/native/win/native_host_runtime.cpp +286 -0
- package/src/native/win/native_host_utils.cpp +314 -0
- package/src/native/win/process_helper_win.cpp +126 -26
- package/src/preload/runtime.built.js +1 -1
- package/src/preload/runtime.ts +65 -42
- package/src/preload/tsconfig.json +2 -1
- package/src/preload/tsconfig.tsbuildinfo +1 -0
- package/src/preload/webviewElement.ts +307 -0
- package/src/shared/cefVersion.ts +2 -0
- package/src/shared/log.ts +40 -0
- package/src/shared/paths.ts +122 -52
- package/src/shared/rpc.ts +7 -1
- package/src/shared/webviewPolyfill.ts +80 -0
- package/src/view/index.ts +8 -5
- package/src/native/shared/cef_response_filter.h +0 -116
- package/src/native/win/native_host.cpp +0 -2453
- package/src/types/config.ts +0 -29
|
@@ -1,119 +1,123 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include <stdbool.h>
|
|
4
|
-
#include <stdint.h>
|
|
5
|
-
|
|
6
|
-
#include "callbacks.h"
|
|
7
|
-
|
|
8
|
-
#if defined(_WIN32)
|
|
9
|
-
#define BUNITE_EXPORT __declspec(dllexport)
|
|
10
|
-
#else
|
|
11
|
-
#define BUNITE_EXPORT __attribute__((visibility("default")))
|
|
12
|
-
#endif
|
|
13
|
-
|
|
14
|
-
#ifdef __cplusplus
|
|
15
|
-
extern "C" {
|
|
16
|
-
#endif
|
|
17
|
-
|
|
18
|
-
BUNITE_EXPORT
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
BUNITE_EXPORT void
|
|
28
|
-
BUNITE_EXPORT void
|
|
29
|
-
BUNITE_EXPORT void
|
|
30
|
-
|
|
31
|
-
BUNITE_EXPORT void
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
double
|
|
36
|
-
double
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
bool
|
|
42
|
-
bool
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
BUNITE_EXPORT void
|
|
47
|
-
BUNITE_EXPORT void
|
|
48
|
-
BUNITE_EXPORT void
|
|
49
|
-
BUNITE_EXPORT
|
|
50
|
-
BUNITE_EXPORT void
|
|
51
|
-
BUNITE_EXPORT void
|
|
52
|
-
BUNITE_EXPORT
|
|
53
|
-
BUNITE_EXPORT
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const char*
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
BUNITE_EXPORT void
|
|
82
|
-
BUNITE_EXPORT void
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
);
|
|
89
|
-
BUNITE_EXPORT void
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
BUNITE_EXPORT void
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
);
|
|
106
|
-
BUNITE_EXPORT uint32_t
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <stdbool.h>
|
|
4
|
+
#include <stdint.h>
|
|
5
|
+
|
|
6
|
+
#include "callbacks.h"
|
|
7
|
+
|
|
8
|
+
#if defined(_WIN32)
|
|
9
|
+
#define BUNITE_EXPORT __declspec(dllexport)
|
|
10
|
+
#else
|
|
11
|
+
#define BUNITE_EXPORT __attribute__((visibility("default")))
|
|
12
|
+
#endif
|
|
13
|
+
|
|
14
|
+
#ifdef __cplusplus
|
|
15
|
+
extern "C" {
|
|
16
|
+
#endif
|
|
17
|
+
|
|
18
|
+
BUNITE_EXPORT int32_t bunite_abi_version(void);
|
|
19
|
+
BUNITE_EXPORT void bunite_set_log_level(int32_t level);
|
|
20
|
+
BUNITE_EXPORT bool bunite_init(
|
|
21
|
+
const char* process_helper_path,
|
|
22
|
+
const char* cef_dir,
|
|
23
|
+
bool hide_console,
|
|
24
|
+
bool popup_blocking,
|
|
25
|
+
const char* chromium_flags_json
|
|
26
|
+
);
|
|
27
|
+
BUNITE_EXPORT void bunite_run_loop(void);
|
|
28
|
+
BUNITE_EXPORT void bunite_quit(void);
|
|
29
|
+
BUNITE_EXPORT void bunite_free_cstring(const char* value);
|
|
30
|
+
BUNITE_EXPORT void bunite_set_webview_event_handler(BuniteWebviewEventHandler handler);
|
|
31
|
+
BUNITE_EXPORT void bunite_set_window_event_handler(BuniteWindowEventHandler handler);
|
|
32
|
+
|
|
33
|
+
BUNITE_EXPORT bool bunite_window_create(
|
|
34
|
+
uint32_t window_id,
|
|
35
|
+
double x,
|
|
36
|
+
double y,
|
|
37
|
+
double width,
|
|
38
|
+
double height,
|
|
39
|
+
const char* title,
|
|
40
|
+
const char* title_bar_style,
|
|
41
|
+
bool transparent,
|
|
42
|
+
bool hidden,
|
|
43
|
+
bool minimized,
|
|
44
|
+
bool maximized
|
|
45
|
+
);
|
|
46
|
+
BUNITE_EXPORT void bunite_window_destroy(uint32_t window_id);
|
|
47
|
+
BUNITE_EXPORT void bunite_window_reset_close_pending(uint32_t window_id);
|
|
48
|
+
BUNITE_EXPORT void bunite_window_show(uint32_t window_id);
|
|
49
|
+
BUNITE_EXPORT void bunite_window_close(uint32_t window_id);
|
|
50
|
+
BUNITE_EXPORT void bunite_window_set_title(uint32_t window_id, const char* title);
|
|
51
|
+
BUNITE_EXPORT void bunite_window_minimize(uint32_t window_id);
|
|
52
|
+
BUNITE_EXPORT void bunite_window_unminimize(uint32_t window_id);
|
|
53
|
+
BUNITE_EXPORT bool bunite_window_is_minimized(uint32_t window_id);
|
|
54
|
+
BUNITE_EXPORT void bunite_window_maximize(uint32_t window_id);
|
|
55
|
+
BUNITE_EXPORT void bunite_window_unmaximize(uint32_t window_id);
|
|
56
|
+
BUNITE_EXPORT bool bunite_window_is_maximized(uint32_t window_id);
|
|
57
|
+
BUNITE_EXPORT void bunite_window_set_frame(
|
|
58
|
+
uint32_t window_id,
|
|
59
|
+
double x,
|
|
60
|
+
double y,
|
|
61
|
+
double width,
|
|
62
|
+
double height
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
BUNITE_EXPORT bool bunite_view_create(
|
|
66
|
+
uint32_t view_id,
|
|
67
|
+
uint32_t window_id,
|
|
68
|
+
const char* url,
|
|
69
|
+
const char* html,
|
|
70
|
+
const char* preload,
|
|
71
|
+
const char* appres_root,
|
|
72
|
+
const char* navigation_rules_json,
|
|
73
|
+
double x,
|
|
74
|
+
double y,
|
|
75
|
+
double width,
|
|
76
|
+
double height,
|
|
77
|
+
bool auto_resize,
|
|
78
|
+
bool sandbox,
|
|
79
|
+
const char* preload_origins_json
|
|
80
|
+
);
|
|
81
|
+
BUNITE_EXPORT void bunite_view_execute_javascript(uint32_t view_id, const char* script);
|
|
82
|
+
BUNITE_EXPORT void bunite_view_load_url(uint32_t view_id, const char* url);
|
|
83
|
+
BUNITE_EXPORT void bunite_view_load_html(uint32_t view_id, const char* html);
|
|
84
|
+
BUNITE_EXPORT void bunite_register_appres_route(const char* path);
|
|
85
|
+
BUNITE_EXPORT void bunite_unregister_appres_route(const char* path);
|
|
86
|
+
BUNITE_EXPORT void bunite_complete_route_request(uint32_t request_id, const char* html);
|
|
87
|
+
BUNITE_EXPORT void bunite_view_set_visible(uint32_t view_id, bool visible);
|
|
88
|
+
BUNITE_EXPORT void bunite_view_bring_to_front(uint32_t view_id);
|
|
89
|
+
BUNITE_EXPORT void bunite_view_set_bounds(
|
|
90
|
+
uint32_t view_id,
|
|
91
|
+
double x,
|
|
92
|
+
double y,
|
|
93
|
+
double width,
|
|
94
|
+
double height
|
|
95
|
+
);
|
|
96
|
+
BUNITE_EXPORT void bunite_view_set_bounds_async(
|
|
97
|
+
uint32_t view_id,
|
|
98
|
+
double x,
|
|
99
|
+
double y,
|
|
100
|
+
double width,
|
|
101
|
+
double height
|
|
102
|
+
);
|
|
103
|
+
BUNITE_EXPORT void bunite_view_set_anchor(uint32_t view_id, int mode, double inset);
|
|
104
|
+
BUNITE_EXPORT void bunite_view_go_back(uint32_t view_id);
|
|
105
|
+
BUNITE_EXPORT void bunite_view_reload(uint32_t view_id);
|
|
106
|
+
BUNITE_EXPORT void bunite_view_remove(uint32_t view_id);
|
|
107
|
+
BUNITE_EXPORT void bunite_view_open_devtools(uint32_t view_id);
|
|
108
|
+
BUNITE_EXPORT void bunite_view_close_devtools(uint32_t view_id);
|
|
109
|
+
BUNITE_EXPORT void bunite_view_toggle_devtools(uint32_t view_id);
|
|
110
|
+
BUNITE_EXPORT void bunite_complete_permission_request(uint32_t request_id, uint32_t state);
|
|
111
|
+
BUNITE_EXPORT int32_t bunite_show_message_box(
|
|
112
|
+
uint32_t window_id,
|
|
113
|
+
const char* type,
|
|
114
|
+
const char* title,
|
|
115
|
+
const char* message,
|
|
116
|
+
const char* detail,
|
|
117
|
+
const char* buttons,
|
|
118
|
+
int32_t default_id,
|
|
119
|
+
int32_t cancel_id
|
|
120
|
+
);
|
|
121
|
+
#ifdef __cplusplus
|
|
122
|
+
}
|
|
123
|
+
#endif
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <cstdio>
|
|
4
|
+
#include <atomic>
|
|
5
|
+
|
|
6
|
+
enum class BuniteLogLevel : int { Debug = 0, Info = 1, Warn = 2, Error = 3, Silent = 4 };
|
|
7
|
+
|
|
8
|
+
inline std::atomic<BuniteLogLevel> g_bunite_log_level{BuniteLogLevel::Warn};
|
|
9
|
+
|
|
10
|
+
inline void buniteSetLogLevel(BuniteLogLevel level) {
|
|
11
|
+
g_bunite_log_level.store(level, std::memory_order_relaxed);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
inline bool buniteShouldLog(BuniteLogLevel level) {
|
|
15
|
+
return static_cast<int>(level) >= static_cast<int>(g_bunite_log_level.load(std::memory_order_relaxed));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
#define BUNITE_LOG(level, fmt, ...) \
|
|
19
|
+
do { if (buniteShouldLog(level)) std::fprintf(stderr, "[bunite/native] " fmt "\n", ##__VA_ARGS__); } while (0)
|
|
20
|
+
|
|
21
|
+
#define BUNITE_DEBUG(fmt, ...) BUNITE_LOG(BuniteLogLevel::Debug, fmt, ##__VA_ARGS__)
|
|
22
|
+
#define BUNITE_INFO(fmt, ...) BUNITE_LOG(BuniteLogLevel::Info, fmt, ##__VA_ARGS__)
|
|
23
|
+
#define BUNITE_WARN(fmt, ...) BUNITE_LOG(BuniteLogLevel::Warn, fmt, ##__VA_ARGS__)
|
|
24
|
+
#define BUNITE_ERROR(fmt, ...) BUNITE_LOG(BuniteLogLevel::Error, fmt, ##__VA_ARGS__)
|
|
@@ -39,13 +39,13 @@ private:
|
|
|
39
39
|
std::map<uint32_t, std::string> content_;
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
// Tracks which
|
|
42
|
+
// Tracks which appres:// paths have registered dynamic handlers on the Bun side.
|
|
43
43
|
// The actual handler function lives in JS; this only stores the set of registered paths
|
|
44
44
|
// and completed route responses.
|
|
45
|
-
class
|
|
45
|
+
class AppResRouteStorage {
|
|
46
46
|
public:
|
|
47
|
-
static
|
|
48
|
-
static
|
|
47
|
+
static AppResRouteStorage& instance() {
|
|
48
|
+
static AppResRouteStorage storage;
|
|
49
49
|
return storage;
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -79,7 +79,7 @@ public:
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
private:
|
|
82
|
-
|
|
82
|
+
AppResRouteStorage() = default;
|
|
83
83
|
|
|
84
84
|
mutable std::mutex mutex_;
|
|
85
85
|
std::set<std::string> registered_;
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
#include "native_host_internal.h"
|
|
2
|
+
|
|
3
|
+
namespace {
|
|
4
|
+
|
|
5
|
+
class BuniteSchemeHandler : public CefResourceHandler {
|
|
6
|
+
public:
|
|
7
|
+
explicit BuniteSchemeHandler(uint32_t view_id)
|
|
8
|
+
: view_id_(view_id) {}
|
|
9
|
+
|
|
10
|
+
bool Open(CefRefPtr<CefRequest> request, bool& handle_request, CefRefPtr<CefCallback> callback) override {
|
|
11
|
+
CEF_REQUIRE_IO_THREAD();
|
|
12
|
+
handle_request = true;
|
|
13
|
+
|
|
14
|
+
const std::string url = request ? request->GetURL().ToString() : "";
|
|
15
|
+
|
|
16
|
+
CefURLParts url_parts;
|
|
17
|
+
if (CefParseURL(url, url_parts)) {
|
|
18
|
+
const std::string host = CefString(&url_parts.host).ToString();
|
|
19
|
+
if (host != "app.internal") {
|
|
20
|
+
status_code_ = 403;
|
|
21
|
+
status_text_ = "Forbidden";
|
|
22
|
+
mime_type_ = "text/plain";
|
|
23
|
+
data_ = "Invalid appres host: " + host;
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const std::string normalized_path = bunite_win::normalizeAppResPath(url);
|
|
29
|
+
|
|
30
|
+
// Dynamic route: handler lives on the Bun side, request is async
|
|
31
|
+
if (bunite::AppResRouteStorage::instance().hasRoute(normalized_path)) {
|
|
32
|
+
handle_request = false; // async - we'll call callback->Continue() later
|
|
33
|
+
uint32_t request_id;
|
|
34
|
+
{
|
|
35
|
+
std::lock_guard<std::mutex> lock(g_runtime.route_mutex);
|
|
36
|
+
request_id = g_runtime.next_route_request_id++;
|
|
37
|
+
g_runtime.pending_routes[request_id] = { normalized_path, callback, request };
|
|
38
|
+
}
|
|
39
|
+
pending_route_request_id_ = request_id;
|
|
40
|
+
bunite_win::emitWebviewEvent(
|
|
41
|
+
view_id_,
|
|
42
|
+
"route-request",
|
|
43
|
+
"{\"requestId\":" + std::to_string(request_id) +
|
|
44
|
+
",\"path\":\"" + bunite_win::escapeJsonString(normalized_path) + "\"}"
|
|
45
|
+
);
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
std::string mime_type;
|
|
50
|
+
const auto content = bunite_win::loadAppResResource(view_id_, url, mime_type);
|
|
51
|
+
if (!content) {
|
|
52
|
+
const std::string appres_root = bunite_win::getAppResRootForView(view_id_);
|
|
53
|
+
BUNITE_WARN("appres:// resource not found (view=%u, url=%s, normalized=%s, root=%s)",
|
|
54
|
+
view_id_, url.c_str(), normalized_path.c_str(), appres_root.c_str());
|
|
55
|
+
status_code_ = 404;
|
|
56
|
+
status_text_ = "Not Found";
|
|
57
|
+
mime_type_ = "text/plain";
|
|
58
|
+
data_ =
|
|
59
|
+
"bunite could not resolve the requested appres:// resource.\n"
|
|
60
|
+
"url: " + url + "\n" +
|
|
61
|
+
"normalized: " + normalized_path;
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
status_code_ = 200;
|
|
66
|
+
status_text_ = "OK";
|
|
67
|
+
mime_type_ = mime_type;
|
|
68
|
+
data_ = *content;
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
void GetResponseHeaders(CefRefPtr<CefResponse> response, int64_t& response_length, CefString&) override {
|
|
73
|
+
if (pending_route_request_id_ != 0) {
|
|
74
|
+
auto content = bunite::AppResRouteStorage::instance().takeResponse(pending_route_request_id_);
|
|
75
|
+
pending_route_request_id_ = 0;
|
|
76
|
+
if (content) {
|
|
77
|
+
status_code_ = 200;
|
|
78
|
+
status_text_ = "OK";
|
|
79
|
+
mime_type_ = "text/html";
|
|
80
|
+
data_ = std::move(*content);
|
|
81
|
+
} else {
|
|
82
|
+
status_code_ = 500;
|
|
83
|
+
status_text_ = "Handler Error";
|
|
84
|
+
mime_type_ = "text/plain";
|
|
85
|
+
data_ = "Route handler did not produce a response.";
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
response->SetStatus(status_code_);
|
|
89
|
+
response->SetStatusText(status_text_);
|
|
90
|
+
response->SetMimeType(mime_type_);
|
|
91
|
+
response_length = static_cast<int64_t>(data_.size());
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
bool Read(void* data_out, int bytes_to_read, int& bytes_read, CefRefPtr<CefResourceReadCallback>) override {
|
|
95
|
+
CEF_REQUIRE_IO_THREAD();
|
|
96
|
+
bytes_read = 0;
|
|
97
|
+
if (offset_ >= data_.size()) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const size_t remaining = data_.size() - offset_;
|
|
102
|
+
const size_t count = std::min<size_t>(remaining, static_cast<size_t>(bytes_to_read));
|
|
103
|
+
std::memcpy(data_out, data_.data() + offset_, count);
|
|
104
|
+
offset_ += count;
|
|
105
|
+
bytes_read = static_cast<int>(count);
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
void Cancel() override {
|
|
110
|
+
CEF_REQUIRE_IO_THREAD();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private:
|
|
114
|
+
uint32_t view_id_;
|
|
115
|
+
uint32_t pending_route_request_id_ = 0;
|
|
116
|
+
std::string data_;
|
|
117
|
+
std::string mime_type_ = "text/plain";
|
|
118
|
+
std::string status_text_ = "OK";
|
|
119
|
+
size_t offset_ = 0;
|
|
120
|
+
int status_code_ = 200;
|
|
121
|
+
|
|
122
|
+
IMPLEMENT_REFCOUNTING(BuniteSchemeHandler);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
class BuniteSchemeHandlerFactory : public CefSchemeHandlerFactory {
|
|
126
|
+
public:
|
|
127
|
+
CefRefPtr<CefResourceHandler> Create(
|
|
128
|
+
CefRefPtr<CefBrowser> browser,
|
|
129
|
+
CefRefPtr<CefFrame>,
|
|
130
|
+
const CefString&,
|
|
131
|
+
CefRefPtr<CefRequest>
|
|
132
|
+
) override {
|
|
133
|
+
uint32_t view_id = 0;
|
|
134
|
+
if (browser) {
|
|
135
|
+
std::lock_guard<std::mutex> lock(g_runtime.object_mutex);
|
|
136
|
+
const auto it = g_runtime.browser_to_view_id.find(browser->GetIdentifier());
|
|
137
|
+
if (it != g_runtime.browser_to_view_id.end()) {
|
|
138
|
+
view_id = it->second;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return new BuniteSchemeHandler(view_id);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private:
|
|
145
|
+
IMPLEMENT_REFCOUNTING(BuniteSchemeHandlerFactory);
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
} // namespace
|
|
149
|
+
|
|
150
|
+
namespace bunite_win {
|
|
151
|
+
|
|
152
|
+
std::string normalizeAppResPath(const std::string& url) {
|
|
153
|
+
CefURLParts parts;
|
|
154
|
+
if (CefParseURL(url, parts)) {
|
|
155
|
+
std::string path = CefString(&parts.path).ToString();
|
|
156
|
+
while (!path.empty() && (path.front() == '/' || path.front() == '\\')) {
|
|
157
|
+
path.erase(path.begin());
|
|
158
|
+
}
|
|
159
|
+
while (!path.empty() && (path.back() == '/' || path.back() == '\\')) {
|
|
160
|
+
path.pop_back();
|
|
161
|
+
}
|
|
162
|
+
return path.empty() ? "index.html" : path;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
std::string path = url;
|
|
166
|
+
if (path.rfind("appres://", 0) == 0) {
|
|
167
|
+
path = path.substr(9); // "appres://" is 9 chars
|
|
168
|
+
const auto slash_pos = path.find('/');
|
|
169
|
+
path = (slash_pos != std::string::npos) ? path.substr(slash_pos + 1) : "";
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const auto query_pos = path.find_first_of("?#");
|
|
173
|
+
if (query_pos != std::string::npos) {
|
|
174
|
+
path = path.substr(0, query_pos);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
while (!path.empty() && (path.back() == '/' || path.back() == '\\')) {
|
|
178
|
+
path.pop_back();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return path.empty() ? "index.html" : path;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
std::string getMimeType(const std::filesystem::path& file_path) {
|
|
185
|
+
const auto extension = file_path.extension().string();
|
|
186
|
+
if (extension == ".html" || extension == ".htm") return "text/html";
|
|
187
|
+
if (extension == ".js" || extension == ".mjs") return "text/javascript";
|
|
188
|
+
if (extension == ".css") return "text/css";
|
|
189
|
+
if (extension == ".json") return "application/json";
|
|
190
|
+
if (extension == ".svg") return "image/svg+xml";
|
|
191
|
+
if (extension == ".png") return "image/png";
|
|
192
|
+
if (extension == ".jpg" || extension == ".jpeg") return "image/jpeg";
|
|
193
|
+
if (extension == ".woff2") return "font/woff2";
|
|
194
|
+
if (extension == ".woff") return "font/woff";
|
|
195
|
+
if (extension == ".ttf") return "font/ttf";
|
|
196
|
+
return "application/octet-stream";
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
std::string getAppResRootForView(uint32_t view_id) {
|
|
200
|
+
std::lock_guard<std::mutex> lock(g_runtime.object_mutex);
|
|
201
|
+
const auto it = g_runtime.views_by_id.find(view_id);
|
|
202
|
+
if (it == g_runtime.views_by_id.end() || !it->second) {
|
|
203
|
+
return {};
|
|
204
|
+
}
|
|
205
|
+
return it->second->appres_root;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
std::optional<std::string> loadAppResResource(uint32_t view_id, const std::string& url, std::string& mime_type) {
|
|
209
|
+
const std::string appres_root = getAppResRootForView(view_id);
|
|
210
|
+
|
|
211
|
+
const std::string path = normalizeAppResPath(url);
|
|
212
|
+
if (path == "internal/index.html") {
|
|
213
|
+
mime_type = "text/html";
|
|
214
|
+
return bunite::WebviewContentStorage::instance().get(view_id);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (appres_root.empty()) {
|
|
218
|
+
return std::nullopt;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (!std::filesystem::exists(appres_root)) {
|
|
222
|
+
return std::nullopt;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const std::filesystem::path root = std::filesystem::weakly_canonical(std::filesystem::path(appres_root));
|
|
226
|
+
std::filesystem::path candidate = std::filesystem::weakly_canonical(root / std::filesystem::path(path));
|
|
227
|
+
if (std::filesystem::exists(candidate) && std::filesystem::is_directory(candidate)) {
|
|
228
|
+
candidate = std::filesystem::weakly_canonical(candidate / "index.html");
|
|
229
|
+
} else if (!std::filesystem::exists(candidate) && !candidate.has_extension()) {
|
|
230
|
+
candidate = std::filesystem::weakly_canonical(std::filesystem::path(candidate.native() + L".html"));
|
|
231
|
+
}
|
|
232
|
+
const auto root_string = root.native();
|
|
233
|
+
const auto candidate_string = candidate.native();
|
|
234
|
+
const bool in_root = candidate_string == root_string ||
|
|
235
|
+
(candidate_string.size() > root_string.size() &&
|
|
236
|
+
candidate_string.rfind(root_string, 0) == 0 &&
|
|
237
|
+
(candidate_string[root_string.size()] == L'\\' || candidate_string[root_string.size()] == L'/'));
|
|
238
|
+
|
|
239
|
+
if (!in_root || !std::filesystem::exists(candidate) || std::filesystem::is_directory(candidate)) {
|
|
240
|
+
return std::nullopt;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
std::ifstream stream(candidate, std::ios::binary);
|
|
244
|
+
if (!stream) {
|
|
245
|
+
return std::nullopt;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
std::ostringstream contents;
|
|
249
|
+
contents << stream.rdbuf();
|
|
250
|
+
mime_type = getMimeType(candidate);
|
|
251
|
+
return contents.str();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
void registerAppResSchemeHandlers() {
|
|
255
|
+
CefRegisterSchemeHandlerFactory("appres", "", new BuniteSchemeHandlerFactory());
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
} // namespace bunite_win
|