sparkbun 0.1.0
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/bin/sparkbun.cjs +18 -0
- package/dist-linux-arm64/bsdiff +0 -0
- package/dist-linux-arm64/bspatch +0 -0
- package/dist-linux-arm64/libElectrobunCore.so +0 -0
- package/dist-linux-arm64/libNativeWrapper.so +0 -0
- package/dist-linux-arm64/libasar.so +0 -0
- package/dist-linux-x64/bsdiff +0 -0
- package/dist-linux-x64/bspatch +0 -0
- package/dist-linux-x64/libElectrobunCore.so +0 -0
- package/dist-linux-x64/libNativeWrapper.so +0 -0
- package/dist-linux-x64/libasar.so +0 -0
- package/dist-macos-arm64/bsdiff +0 -0
- package/dist-macos-arm64/bspatch +0 -0
- package/dist-macos-arm64/libElectrobunCore.dylib +0 -0
- package/dist-macos-arm64/libNativeWrapper.dylib +0 -0
- package/dist-macos-arm64/libasar.dylib +0 -0
- package/dist-macos-arm64/libwebgpu_dawn.dylib +0 -0
- package/dist-macos-arm64/preload-full.js +885 -0
- package/dist-macos-arm64/preload-sandboxed.js +111 -0
- package/dist-macos-arm64/process_helper +0 -0
- package/dist-win-x64/ElectrobunCore.dll +0 -0
- package/dist-win-x64/WebView2Loader.dll +0 -0
- package/dist-win-x64/bsdiff.exe +0 -0
- package/dist-win-x64/bspatch.exe +0 -0
- package/dist-win-x64/libNativeWrapper.dll +0 -0
- package/dist-win-x64/zig-asar/arm64/libasar.dll +0 -0
- package/dist-win-x64/zig-asar/x64/libasar.dll +0 -0
- package/package.json +47 -0
- package/scripts/build-and-upload-artifacts.js +207 -0
- package/scripts/gen-webgpu-ffi.mjs +162 -0
- package/scripts/install-windows-deps.ps1 +80 -0
- package/scripts/package-release.js +237 -0
- package/scripts/push-version.js +84 -0
- package/scripts/update-bun-version.ts +122 -0
- package/scripts/update-cef-version.ts +145 -0
- package/src/browser/builtinrpcSchema.ts +19 -0
- package/src/browser/global.d.ts +36 -0
- package/src/browser/index.ts +234 -0
- package/src/browser/webviewtag.ts +88 -0
- package/src/browser/wgputag.ts +48 -0
- package/src/bun/SparkBunConfig.ts +497 -0
- package/src/bun/__tests__/ffi-contract.test.ts +105 -0
- package/src/bun/core/ApplicationMenu.ts +70 -0
- package/src/bun/core/BrowserView.ts +416 -0
- package/src/bun/core/BrowserWindow.ts +396 -0
- package/src/bun/core/BuildConfig.ts +71 -0
- package/src/bun/core/ContextMenu.ts +75 -0
- package/src/bun/core/GpuWindow.ts +289 -0
- package/src/bun/core/Paths.ts +5 -0
- package/src/bun/core/Socket.ts +22 -0
- package/src/bun/core/Tray.ts +197 -0
- package/src/bun/core/Updater.ts +1131 -0
- package/src/bun/core/Utils.ts +487 -0
- package/src/bun/core/WGPUView.ts +167 -0
- package/src/bun/core/menuRoles.ts +181 -0
- package/src/bun/events/ApplicationEvents.ts +22 -0
- package/src/bun/events/event.ts +27 -0
- package/src/bun/events/eventEmitter.ts +45 -0
- package/src/bun/events/trayEvents.ts +11 -0
- package/src/bun/events/webviewEvents.ts +39 -0
- package/src/bun/events/windowEvents.ts +23 -0
- package/src/bun/index.ts +120 -0
- package/src/bun/preload/.generated/compiled.ts +2 -0
- package/src/bun/preload/build.ts +65 -0
- package/src/bun/preload/dragRegions.ts +41 -0
- package/src/bun/preload/encryption.ts +86 -0
- package/src/bun/preload/events.ts +171 -0
- package/src/bun/preload/globals.d.ts +45 -0
- package/src/bun/preload/index-sandboxed.ts +28 -0
- package/src/bun/preload/index.ts +77 -0
- package/src/bun/preload/internalRpc.ts +80 -0
- package/src/bun/preload/overlaySync.ts +107 -0
- package/src/bun/preload/webviewTag.ts +451 -0
- package/src/bun/preload/wgpuTag.ts +246 -0
- package/src/bun/proc/linux.md +43 -0
- package/src/bun/proc/native.ts +3253 -0
- package/src/bun/webGPU.ts +346 -0
- package/src/bun/webgpuAdapter.ts +3011 -0
- package/src/cli/bun.lockb +0 -0
- package/src/cli/index.ts +4653 -0
- package/src/cli/package-lock.json +81 -0
- package/src/cli/package.json +11 -0
- package/src/cli/templates/embedded.ts +2 -0
- package/src/core/build.zig +16 -0
- package/src/core/main.zig +3378 -0
- package/src/extractor/build.zig +22 -0
- package/src/installer/installer-template.ts +216 -0
- package/src/launcher/main.ts +221 -0
- package/src/native/build/libNativeWrapper.so +0 -0
- package/src/native/linux/build/nativeWrapper.o +0 -0
- package/src/native/linux/cef_loader.cpp +110 -0
- package/src/native/linux/cef_loader.h +28 -0
- package/src/native/linux/cef_process_helper_linux.cpp +160 -0
- package/src/native/linux/nativeWrapper.cpp +11768 -0
- package/src/native/macos/cef_process_helper_mac.cc +160 -0
- package/src/native/macos/nativeWrapper.mm +9172 -0
- package/src/native/shared/accelerator_parser.h +72 -0
- package/src/native/shared/app_paths.h +110 -0
- package/src/native/shared/asar.h +35 -0
- package/src/native/shared/cache_migration.h +244 -0
- package/src/native/shared/callbacks.h +57 -0
- package/src/native/shared/cef_response_filter.h +189 -0
- package/src/native/shared/chromium_flags.h +181 -0
- package/src/native/shared/config.h +66 -0
- package/src/native/shared/download_event.h +197 -0
- package/src/native/shared/ffi_helpers.h +139 -0
- package/src/native/shared/glob_match.h +59 -0
- package/src/native/shared/json_menu_parser.h +223 -0
- package/src/native/shared/mime_types.h +101 -0
- package/src/native/shared/navigation_rules.h +98 -0
- package/src/native/shared/partition_context.h +137 -0
- package/src/native/shared/pending_resize_queue.h +45 -0
- package/src/native/shared/permissions.h +118 -0
- package/src/native/shared/permissions_cef.h +74 -0
- package/src/native/shared/preload_script.h +71 -0
- package/src/native/shared/shutdown_guard.h +134 -0
- package/src/native/shared/thread_safe_map.h +138 -0
- package/src/native/shared/webview_storage.h +91 -0
- package/src/native/win/cef_process_helper_win.cpp +143 -0
- package/src/native/win/dcomp_compositor.h +352 -0
- package/src/native/win/nativeWrapper.cpp +12434 -0
- package/src/npmbin/index.js +34 -0
- package/src/shared/bun-version.ts +3 -0
- package/src/shared/cef-version.ts +5 -0
- package/src/shared/naming.test.ts +327 -0
- package/src/shared/naming.ts +188 -0
- package/src/shared/platform.ts +48 -0
- package/src/shared/rpc.ts +541 -0
- package/src/shared/sparkbun-version.ts +2 -0
- package/src/types/three.d.ts +1 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
// cef_response_filter.h - Cross-platform CEF response filter for preload script injection
|
|
2
|
+
// Injects preload scripts into HTML responses before any page scripts execute
|
|
3
|
+
// Used across Windows, macOS, and Linux CEF implementations
|
|
4
|
+
//
|
|
5
|
+
// This is a header-only implementation to avoid build complexity.
|
|
6
|
+
// Requires CEF headers to be included before this file.
|
|
7
|
+
|
|
8
|
+
#ifndef ELECTROBUN_CEF_RESPONSE_FILTER_H
|
|
9
|
+
#define ELECTROBUN_CEF_RESPONSE_FILTER_H
|
|
10
|
+
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <algorithm>
|
|
13
|
+
#include <cstring>
|
|
14
|
+
#include "preload_script.h"
|
|
15
|
+
|
|
16
|
+
namespace electrobun {
|
|
17
|
+
|
|
18
|
+
// CEF Response Filter that injects preload scripts into HTML responses
|
|
19
|
+
// Injection happens right after <head> tag to ensure scripts run before page scripts
|
|
20
|
+
class ElectrobunResponseFilter : public CefResponseFilter {
|
|
21
|
+
private:
|
|
22
|
+
std::string buffer_;
|
|
23
|
+
bool injected_;
|
|
24
|
+
PreloadScript electrobun_script_;
|
|
25
|
+
PreloadScript custom_script_;
|
|
26
|
+
|
|
27
|
+
public:
|
|
28
|
+
// Constructor with PreloadScript structs (preferred)
|
|
29
|
+
ElectrobunResponseFilter(const PreloadScript& electrobunScript,
|
|
30
|
+
const PreloadScript& customScript)
|
|
31
|
+
: injected_(false),
|
|
32
|
+
electrobun_script_(electrobunScript),
|
|
33
|
+
custom_script_(customScript) {}
|
|
34
|
+
|
|
35
|
+
// Constructor with raw strings (for compatibility)
|
|
36
|
+
ElectrobunResponseFilter(const std::string& electrobunScript,
|
|
37
|
+
const std::string& customScript = "")
|
|
38
|
+
: injected_(false),
|
|
39
|
+
electrobun_script_(electrobunScript),
|
|
40
|
+
custom_script_(customScript) {}
|
|
41
|
+
|
|
42
|
+
// Single script constructor (for simpler use cases)
|
|
43
|
+
explicit ElectrobunResponseFilter(const std::string& script)
|
|
44
|
+
: injected_(false),
|
|
45
|
+
electrobun_script_(script) {}
|
|
46
|
+
|
|
47
|
+
bool InitFilter() override {
|
|
48
|
+
buffer_.clear();
|
|
49
|
+
injected_ = false;
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
FilterStatus Filter(void* data_in,
|
|
54
|
+
size_t data_in_size,
|
|
55
|
+
size_t& data_in_read,
|
|
56
|
+
void* data_out,
|
|
57
|
+
size_t data_out_size,
|
|
58
|
+
size_t& data_out_written) override {
|
|
59
|
+
|
|
60
|
+
// If no scripts to inject, pass through directly
|
|
61
|
+
if (electrobun_script_.empty() && custom_script_.empty()) {
|
|
62
|
+
size_t copy_size = std::min(data_in_size, data_out_size);
|
|
63
|
+
std::memcpy(data_out, data_in, copy_size);
|
|
64
|
+
data_in_read = copy_size;
|
|
65
|
+
data_out_written = copy_size;
|
|
66
|
+
return RESPONSE_FILTER_DONE;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Append incoming data to buffer
|
|
70
|
+
if (data_in_size > 0) {
|
|
71
|
+
buffer_.append(static_cast<char*>(data_in), data_in_size);
|
|
72
|
+
data_in_read = data_in_size;
|
|
73
|
+
} else {
|
|
74
|
+
data_in_read = 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// If already injected, just output buffered data
|
|
78
|
+
if (injected_) {
|
|
79
|
+
return OutputBufferedData(data_out, data_out_size, data_out_written);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Try to inject scripts
|
|
83
|
+
TryInjectScripts();
|
|
84
|
+
|
|
85
|
+
// Output buffered data
|
|
86
|
+
return OutputBufferedData(data_out, data_out_size, data_out_written);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private:
|
|
90
|
+
void TryInjectScripts() {
|
|
91
|
+
if (injected_) return;
|
|
92
|
+
|
|
93
|
+
std::string script_tag = BuildScriptTag();
|
|
94
|
+
if (script_tag.empty()) return;
|
|
95
|
+
|
|
96
|
+
// Strategy 1: Look for <head> tag (most common case)
|
|
97
|
+
size_t head_pos = FindTagCaseInsensitive("<head>");
|
|
98
|
+
if (head_pos != std::string::npos) {
|
|
99
|
+
// Find the end of <head> or <head ...>
|
|
100
|
+
size_t insert_pos = buffer_.find('>', head_pos);
|
|
101
|
+
if (insert_pos != std::string::npos) {
|
|
102
|
+
buffer_.insert(insert_pos + 1, script_tag);
|
|
103
|
+
injected_ = true;
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Strategy 2: Look for <head with attributes (e.g., <head class="...">)
|
|
109
|
+
head_pos = FindTagCaseInsensitive("<head ");
|
|
110
|
+
if (head_pos != std::string::npos) {
|
|
111
|
+
size_t insert_pos = buffer_.find('>', head_pos);
|
|
112
|
+
if (insert_pos != std::string::npos) {
|
|
113
|
+
buffer_.insert(insert_pos + 1, script_tag);
|
|
114
|
+
injected_ = true;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// If buffer is large enough, try fallback strategies
|
|
120
|
+
if (buffer_.size() > 1024) {
|
|
121
|
+
// Strategy 3: Look for <html> and create a <head> section
|
|
122
|
+
size_t html_pos = FindTagCaseInsensitive("<html");
|
|
123
|
+
if (html_pos != std::string::npos) {
|
|
124
|
+
size_t insert_pos = buffer_.find('>', html_pos);
|
|
125
|
+
if (insert_pos != std::string::npos) {
|
|
126
|
+
std::string head_with_script = "<head>" + script_tag + "</head>";
|
|
127
|
+
buffer_.insert(insert_pos + 1, head_with_script);
|
|
128
|
+
injected_ = true;
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Strategy 4: Last resort - inject at the very beginning
|
|
134
|
+
buffer_.insert(0, script_tag);
|
|
135
|
+
injected_ = true;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
std::string BuildScriptTag() const {
|
|
140
|
+
if (electrobun_script_.empty() && custom_script_.empty()) {
|
|
141
|
+
return "";
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
std::string result = "<script>\n";
|
|
145
|
+
|
|
146
|
+
if (!electrobun_script_.empty()) {
|
|
147
|
+
result += electrobun_script_.code;
|
|
148
|
+
result += "\n";
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!custom_script_.empty()) {
|
|
152
|
+
result += custom_script_.code;
|
|
153
|
+
result += "\n";
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
result += "</script>\n";
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Case-insensitive tag search
|
|
161
|
+
size_t FindTagCaseInsensitive(const std::string& tag) const {
|
|
162
|
+
std::string lower_buffer = buffer_;
|
|
163
|
+
std::string lower_tag = tag;
|
|
164
|
+
|
|
165
|
+
std::transform(lower_buffer.begin(), lower_buffer.end(), lower_buffer.begin(),
|
|
166
|
+
[](unsigned char c) { return std::tolower(c); });
|
|
167
|
+
std::transform(lower_tag.begin(), lower_tag.end(), lower_tag.begin(),
|
|
168
|
+
[](unsigned char c) { return std::tolower(c); });
|
|
169
|
+
|
|
170
|
+
return lower_buffer.find(lower_tag);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
FilterStatus OutputBufferedData(void* data_out, size_t data_out_size, size_t& data_out_written) {
|
|
174
|
+
size_t copy_size = std::min(buffer_.size(), data_out_size);
|
|
175
|
+
if (copy_size > 0) {
|
|
176
|
+
std::memcpy(data_out, buffer_.c_str(), copy_size);
|
|
177
|
+
buffer_.erase(0, copy_size);
|
|
178
|
+
}
|
|
179
|
+
data_out_written = copy_size;
|
|
180
|
+
|
|
181
|
+
return buffer_.empty() ? RESPONSE_FILTER_DONE : RESPONSE_FILTER_NEED_MORE_DATA;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
IMPLEMENT_REFCOUNTING(ElectrobunResponseFilter);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
} // namespace electrobun
|
|
188
|
+
|
|
189
|
+
#endif // ELECTROBUN_CEF_RESPONSE_FILTER_H
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// chromium_flags.h - Cross-platform Chromium CLI flag passthrough
|
|
2
|
+
// Reads user-defined Chromium flags from build.json and applies them
|
|
3
|
+
// to CEF's command line during initialization.
|
|
4
|
+
// Used across Windows, macOS, and Linux.
|
|
5
|
+
//
|
|
6
|
+
// This is a header-only implementation to avoid build complexity.
|
|
7
|
+
|
|
8
|
+
#ifndef ELECTROBUN_CHROMIUM_FLAGS_H
|
|
9
|
+
#define ELECTROBUN_CHROMIUM_FLAGS_H
|
|
10
|
+
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <vector>
|
|
13
|
+
#include <set>
|
|
14
|
+
#include <fstream>
|
|
15
|
+
#include <sstream>
|
|
16
|
+
|
|
17
|
+
// Forward-declare CEF types so this header can be included without
|
|
18
|
+
// pulling in the full CEF headers (the call sites already include them).
|
|
19
|
+
#include "include/cef_command_line.h"
|
|
20
|
+
|
|
21
|
+
namespace electrobun {
|
|
22
|
+
|
|
23
|
+
struct ChromiumFlag {
|
|
24
|
+
std::string name;
|
|
25
|
+
std::string value;
|
|
26
|
+
bool hasValue;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
struct ChromiumFlagConfig {
|
|
30
|
+
std::vector<ChromiumFlag> flags; // flags to add (true / "value")
|
|
31
|
+
std::set<std::string> skip; // default flags to skip (any user-specified flag overrides its default)
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Read an entire file into a string. Returns empty string on failure.
|
|
35
|
+
inline std::string readFileToString(const std::string& path) {
|
|
36
|
+
std::ifstream file(path);
|
|
37
|
+
if (!file.is_open()) {
|
|
38
|
+
return "";
|
|
39
|
+
}
|
|
40
|
+
std::stringstream buf;
|
|
41
|
+
buf << file.rdbuf();
|
|
42
|
+
return buf.str();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Parse the "chromiumFlags" object from build.json content.
|
|
46
|
+
// Handles three value types:
|
|
47
|
+
// "flag-name": true -> add switch (hasValue = false)
|
|
48
|
+
// "flag-name": "value" -> add switch with value (hasValue = true)
|
|
49
|
+
// "flag-name": false -> skip a default flag set by Electrobun
|
|
50
|
+
inline ChromiumFlagConfig parseChromiumFlags(const std::string& json) {
|
|
51
|
+
ChromiumFlagConfig config;
|
|
52
|
+
|
|
53
|
+
// Find the "chromiumFlags" key
|
|
54
|
+
std::string key = "\"chromiumFlags\"";
|
|
55
|
+
size_t keyPos = json.find(key);
|
|
56
|
+
if (keyPos == std::string::npos) {
|
|
57
|
+
return config;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Find the opening brace of the object
|
|
61
|
+
size_t objStart = json.find('{', keyPos + key.length());
|
|
62
|
+
if (objStart == std::string::npos) {
|
|
63
|
+
return config;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Find the matching closing brace (handles nested depth = 0 since
|
|
67
|
+
// chromiumFlags values are only primitives, not nested objects)
|
|
68
|
+
int depth = 1;
|
|
69
|
+
size_t objEnd = objStart + 1;
|
|
70
|
+
while (objEnd < json.size() && depth > 0) {
|
|
71
|
+
if (json[objEnd] == '{') depth++;
|
|
72
|
+
else if (json[objEnd] == '}') depth--;
|
|
73
|
+
objEnd++;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
std::string objContent = json.substr(objStart + 1, objEnd - objStart - 2);
|
|
77
|
+
|
|
78
|
+
// Iterate over key-value pairs inside the object
|
|
79
|
+
size_t pos = 0;
|
|
80
|
+
while (pos < objContent.size()) {
|
|
81
|
+
// Find next quoted key
|
|
82
|
+
size_t nameStart = objContent.find('"', pos);
|
|
83
|
+
if (nameStart == std::string::npos) break;
|
|
84
|
+
nameStart++;
|
|
85
|
+
size_t nameEnd = objContent.find('"', nameStart);
|
|
86
|
+
if (nameEnd == std::string::npos) break;
|
|
87
|
+
|
|
88
|
+
std::string flagName = objContent.substr(nameStart, nameEnd - nameStart);
|
|
89
|
+
|
|
90
|
+
// Skip past the colon
|
|
91
|
+
size_t colon = objContent.find(':', nameEnd + 1);
|
|
92
|
+
if (colon == std::string::npos) break;
|
|
93
|
+
|
|
94
|
+
// Skip whitespace after colon
|
|
95
|
+
size_t valStart = colon + 1;
|
|
96
|
+
while (valStart < objContent.size() &&
|
|
97
|
+
(objContent[valStart] == ' ' || objContent[valStart] == '\t' ||
|
|
98
|
+
objContent[valStart] == '\n' || objContent[valStart] == '\r')) {
|
|
99
|
+
valStart++;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (valStart >= objContent.size()) break;
|
|
103
|
+
|
|
104
|
+
// Any user-specified flag overrides the corresponding default
|
|
105
|
+
config.skip.insert(flagName);
|
|
106
|
+
|
|
107
|
+
if (objContent[valStart] == '"') {
|
|
108
|
+
// String value — add flag with value
|
|
109
|
+
valStart++;
|
|
110
|
+
size_t valEnd = objContent.find('"', valStart);
|
|
111
|
+
if (valEnd == std::string::npos) break;
|
|
112
|
+
ChromiumFlag flag;
|
|
113
|
+
flag.name = flagName;
|
|
114
|
+
flag.value = objContent.substr(valStart, valEnd - valStart);
|
|
115
|
+
flag.hasValue = true;
|
|
116
|
+
config.flags.push_back(flag);
|
|
117
|
+
pos = valEnd + 1;
|
|
118
|
+
} else {
|
|
119
|
+
// Boolean token — "false" means skip only, "true" means add
|
|
120
|
+
size_t tokenEnd = valStart;
|
|
121
|
+
while (tokenEnd < objContent.size() &&
|
|
122
|
+
objContent[tokenEnd] != ',' && objContent[tokenEnd] != '}' &&
|
|
123
|
+
objContent[tokenEnd] != '\n') {
|
|
124
|
+
tokenEnd++;
|
|
125
|
+
}
|
|
126
|
+
std::string token = objContent.substr(valStart, tokenEnd - valStart);
|
|
127
|
+
// Trim whitespace from token
|
|
128
|
+
while (!token.empty() && (token.back() == ' ' || token.back() == '\t' || token.back() == '\r')) {
|
|
129
|
+
token.pop_back();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (token != "false") {
|
|
133
|
+
// true or any other value — add as switch-only
|
|
134
|
+
ChromiumFlag flag;
|
|
135
|
+
flag.name = flagName;
|
|
136
|
+
flag.hasValue = false;
|
|
137
|
+
config.flags.push_back(flag);
|
|
138
|
+
}
|
|
139
|
+
pos = tokenEnd;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return config;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// A default flag: either a switch-only or a switch with a value.
|
|
147
|
+
struct DefaultFlag {
|
|
148
|
+
std::string name;
|
|
149
|
+
std::string value; // empty = switch-only
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// Apply a list of default flags, skipping any that the user overrode.
|
|
153
|
+
inline void applyDefaultFlags(const std::vector<DefaultFlag>& defaults,
|
|
154
|
+
const std::set<std::string>& skip,
|
|
155
|
+
CefRefPtr<CefCommandLine> command_line) {
|
|
156
|
+
for (const auto& def : defaults) {
|
|
157
|
+
if (skip.count(def.name) > 0) continue;
|
|
158
|
+
if (def.value.empty()) {
|
|
159
|
+
command_line->AppendSwitch(def.name);
|
|
160
|
+
} else {
|
|
161
|
+
command_line->AppendSwitchWithValue(def.name, def.value);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Apply user-defined flags to a CefCommandLine. Call this from
|
|
167
|
+
// OnBeforeCommandLineProcessing after default flags.
|
|
168
|
+
inline void applyChromiumFlags(const ChromiumFlagConfig& config,
|
|
169
|
+
CefRefPtr<CefCommandLine> command_line) {
|
|
170
|
+
for (const auto& flag : config.flags) {
|
|
171
|
+
if (flag.hasValue) {
|
|
172
|
+
command_line->AppendSwitchWithValue(flag.name, flag.value);
|
|
173
|
+
} else {
|
|
174
|
+
command_line->AppendSwitch(flag.name);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
} // namespace electrobun
|
|
180
|
+
|
|
181
|
+
#endif // ELECTROBUN_CHROMIUM_FLAGS_H
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// config.h - Cross-platform global configuration
|
|
2
|
+
// Used for CEF cache path isolation and app identification
|
|
3
|
+
// across Windows, macOS, and Linux
|
|
4
|
+
//
|
|
5
|
+
// This is a header-only implementation to avoid build complexity.
|
|
6
|
+
|
|
7
|
+
#ifndef ELECTROBUN_CONFIG_H
|
|
8
|
+
#define ELECTROBUN_CONFIG_H
|
|
9
|
+
|
|
10
|
+
#include <string>
|
|
11
|
+
#include <mutex>
|
|
12
|
+
|
|
13
|
+
namespace electrobun {
|
|
14
|
+
|
|
15
|
+
// Thread-safe configuration singleton
|
|
16
|
+
class Config {
|
|
17
|
+
public:
|
|
18
|
+
static Config& getInstance() {
|
|
19
|
+
static Config instance;
|
|
20
|
+
return instance;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
void setChannel(const std::string& channel) {
|
|
24
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
25
|
+
channel_ = channel;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
std::string getChannel() const {
|
|
29
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
30
|
+
return channel_;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
void setIdentifier(const std::string& identifier) {
|
|
34
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
35
|
+
identifier_ = identifier;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
std::string getIdentifier() const {
|
|
39
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
40
|
+
return identifier_;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
void setName(const std::string& name) {
|
|
44
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
45
|
+
name_ = name;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
std::string getName() const {
|
|
49
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
50
|
+
return name_;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private:
|
|
54
|
+
Config() = default;
|
|
55
|
+
Config(const Config&) = delete;
|
|
56
|
+
Config& operator=(const Config&) = delete;
|
|
57
|
+
|
|
58
|
+
mutable std::mutex mutex_;
|
|
59
|
+
std::string channel_;
|
|
60
|
+
std::string identifier_;
|
|
61
|
+
std::string name_;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
} // namespace electrobun
|
|
65
|
+
|
|
66
|
+
#endif // ELECTROBUN_CONFIG_H
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// download_event.h - Cross-platform download event structures
|
|
2
|
+
// Common data structures for download events
|
|
3
|
+
// Used across Windows, macOS, and Linux
|
|
4
|
+
//
|
|
5
|
+
// This is a header-only implementation to avoid build complexity.
|
|
6
|
+
|
|
7
|
+
#ifndef ELECTROBUN_DOWNLOAD_EVENT_H
|
|
8
|
+
#define ELECTROBUN_DOWNLOAD_EVENT_H
|
|
9
|
+
|
|
10
|
+
#include <string>
|
|
11
|
+
#include <cstdint>
|
|
12
|
+
#include <sstream>
|
|
13
|
+
|
|
14
|
+
namespace electrobun {
|
|
15
|
+
|
|
16
|
+
// Download event types
|
|
17
|
+
enum class DownloadEventType {
|
|
18
|
+
STARTED,
|
|
19
|
+
PROGRESS,
|
|
20
|
+
COMPLETED,
|
|
21
|
+
CANCELLED,
|
|
22
|
+
FAILED
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Convert event type to string
|
|
26
|
+
inline const char* downloadEventTypeToString(DownloadEventType type) {
|
|
27
|
+
switch (type) {
|
|
28
|
+
case DownloadEventType::STARTED: return "download-started";
|
|
29
|
+
case DownloadEventType::PROGRESS: return "download-progress";
|
|
30
|
+
case DownloadEventType::COMPLETED: return "download-completed";
|
|
31
|
+
case DownloadEventType::CANCELLED: return "download-cancelled";
|
|
32
|
+
case DownloadEventType::FAILED: return "download-failed";
|
|
33
|
+
default: return "download-unknown";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Download event data structure
|
|
38
|
+
struct DownloadEvent {
|
|
39
|
+
uint32_t downloadId = 0;
|
|
40
|
+
std::string url;
|
|
41
|
+
std::string filename;
|
|
42
|
+
std::string mimeType;
|
|
43
|
+
std::string destinationPath;
|
|
44
|
+
int64_t totalBytes = -1; // -1 if unknown
|
|
45
|
+
int64_t receivedBytes = 0;
|
|
46
|
+
int percentComplete = 0;
|
|
47
|
+
bool canResume = false;
|
|
48
|
+
std::string errorMessage;
|
|
49
|
+
|
|
50
|
+
// Serialize to JSON string for FFI callbacks
|
|
51
|
+
std::string toJson() const {
|
|
52
|
+
std::ostringstream ss;
|
|
53
|
+
ss << "{";
|
|
54
|
+
ss << "\"downloadId\":" << downloadId;
|
|
55
|
+
|
|
56
|
+
if (!url.empty()) {
|
|
57
|
+
ss << ",\"url\":\"" << escapeJson(url) << "\"";
|
|
58
|
+
}
|
|
59
|
+
if (!filename.empty()) {
|
|
60
|
+
ss << ",\"filename\":\"" << escapeJson(filename) << "\"";
|
|
61
|
+
}
|
|
62
|
+
if (!mimeType.empty()) {
|
|
63
|
+
ss << ",\"mimeType\":\"" << escapeJson(mimeType) << "\"";
|
|
64
|
+
}
|
|
65
|
+
if (!destinationPath.empty()) {
|
|
66
|
+
ss << ",\"destinationPath\":\"" << escapeJson(destinationPath) << "\"";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
ss << ",\"totalBytes\":" << totalBytes;
|
|
70
|
+
ss << ",\"receivedBytes\":" << receivedBytes;
|
|
71
|
+
ss << ",\"percentComplete\":" << percentComplete;
|
|
72
|
+
ss << ",\"canResume\":" << (canResume ? "true" : "false");
|
|
73
|
+
|
|
74
|
+
if (!errorMessage.empty()) {
|
|
75
|
+
ss << ",\"errorMessage\":\"" << escapeJson(errorMessage) << "\"";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
ss << "}";
|
|
79
|
+
return ss.str();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Serialize to simple key=value format (legacy format)
|
|
83
|
+
std::string toKeyValue() const {
|
|
84
|
+
std::ostringstream ss;
|
|
85
|
+
ss << "downloadId=" << downloadId;
|
|
86
|
+
|
|
87
|
+
if (!url.empty()) {
|
|
88
|
+
ss << "&url=" << url;
|
|
89
|
+
}
|
|
90
|
+
if (!filename.empty()) {
|
|
91
|
+
ss << "&filename=" << filename;
|
|
92
|
+
}
|
|
93
|
+
if (!mimeType.empty()) {
|
|
94
|
+
ss << "&mimeType=" << mimeType;
|
|
95
|
+
}
|
|
96
|
+
if (!destinationPath.empty()) {
|
|
97
|
+
ss << "&destinationPath=" << destinationPath;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
ss << "&totalBytes=" << totalBytes;
|
|
101
|
+
ss << "&receivedBytes=" << receivedBytes;
|
|
102
|
+
ss << "&percentComplete=" << percentComplete;
|
|
103
|
+
|
|
104
|
+
return ss.str();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private:
|
|
108
|
+
// Simple JSON string escaping
|
|
109
|
+
static std::string escapeJson(const std::string& str) {
|
|
110
|
+
std::string result;
|
|
111
|
+
result.reserve(str.length() * 2);
|
|
112
|
+
|
|
113
|
+
for (char c : str) {
|
|
114
|
+
switch (c) {
|
|
115
|
+
case '"': result += "\\\""; break;
|
|
116
|
+
case '\\': result += "\\\\"; break;
|
|
117
|
+
case '\b': result += "\\b"; break;
|
|
118
|
+
case '\f': result += "\\f"; break;
|
|
119
|
+
case '\n': result += "\\n"; break;
|
|
120
|
+
case '\r': result += "\\r"; break;
|
|
121
|
+
case '\t': result += "\\t"; break;
|
|
122
|
+
default: result += c; break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// Builder pattern for download events
|
|
131
|
+
class DownloadEventBuilder {
|
|
132
|
+
public:
|
|
133
|
+
DownloadEventBuilder& setDownloadId(uint32_t id) {
|
|
134
|
+
event_.downloadId = id;
|
|
135
|
+
return *this;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
DownloadEventBuilder& setUrl(const std::string& url) {
|
|
139
|
+
event_.url = url;
|
|
140
|
+
return *this;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
DownloadEventBuilder& setFilename(const std::string& filename) {
|
|
144
|
+
event_.filename = filename;
|
|
145
|
+
return *this;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
DownloadEventBuilder& setMimeType(const std::string& mimeType) {
|
|
149
|
+
event_.mimeType = mimeType;
|
|
150
|
+
return *this;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
DownloadEventBuilder& setDestinationPath(const std::string& path) {
|
|
154
|
+
event_.destinationPath = path;
|
|
155
|
+
return *this;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
DownloadEventBuilder& setTotalBytes(int64_t bytes) {
|
|
159
|
+
event_.totalBytes = bytes;
|
|
160
|
+
return *this;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
DownloadEventBuilder& setReceivedBytes(int64_t bytes) {
|
|
164
|
+
event_.receivedBytes = bytes;
|
|
165
|
+
return *this;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
DownloadEventBuilder& setPercentComplete(int percent) {
|
|
169
|
+
event_.percentComplete = percent;
|
|
170
|
+
return *this;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
DownloadEventBuilder& setCanResume(bool canResume) {
|
|
174
|
+
event_.canResume = canResume;
|
|
175
|
+
return *this;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
DownloadEventBuilder& setErrorMessage(const std::string& msg) {
|
|
179
|
+
event_.errorMessage = msg;
|
|
180
|
+
return *this;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
DownloadEvent build() const {
|
|
184
|
+
return event_;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
std::string toJson() const {
|
|
188
|
+
return event_.toJson();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private:
|
|
192
|
+
DownloadEvent event_;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
} // namespace electrobun
|
|
196
|
+
|
|
197
|
+
#endif // ELECTROBUN_DOWNLOAD_EVENT_H
|