@aptre/bldr-saucer 0.3.1 → 0.4.2
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 +18 -13
- package/src/main.cpp +3 -4
- package/src/scheme_forwarder.cpp +52 -33
- package/src/scheme_forwarder.h +2 -1
package/package.json
CHANGED
|
@@ -1,29 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aptre/bldr-saucer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Native webview bridge for Bldr using Saucer",
|
|
5
5
|
"main": "index.js",
|
|
6
|
-
"
|
|
7
|
-
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/aperturerobotics/bldr-saucer.git"
|
|
9
|
-
},
|
|
6
|
+
"license": "MIT",
|
|
10
7
|
"keywords": [
|
|
11
8
|
"webview",
|
|
12
9
|
"saucer",
|
|
13
10
|
"native",
|
|
14
11
|
"bldr"
|
|
15
12
|
],
|
|
16
|
-
"
|
|
17
|
-
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/aperturerobotics/bldr-saucer.git"
|
|
16
|
+
},
|
|
18
17
|
"bugs": {
|
|
19
18
|
"url": "https://github.com/aperturerobotics/bldr-saucer/issues"
|
|
20
19
|
},
|
|
21
20
|
"homepage": "https://github.com/aperturerobotics/bldr-saucer#readme",
|
|
21
|
+
"author": {
|
|
22
|
+
"name": "Aperture Robotics LLC.",
|
|
23
|
+
"email": "support@aperture.us",
|
|
24
|
+
"url": "http://aperture.us"
|
|
25
|
+
},
|
|
22
26
|
"scripts": {
|
|
23
27
|
"postinstall": "node install.js",
|
|
24
28
|
"gen": "bun run go:aptre -- generate",
|
|
25
29
|
"gen:force": "bun run go:aptre -- generate --force",
|
|
26
30
|
"go:aptre": "go run -mod=mod github.com/aperturerobotics/common/cmd/aptre",
|
|
31
|
+
"build": "go mod vendor && cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build --parallel",
|
|
27
32
|
"release": "npm run release:version && npm run release:sync && npm run release:commit",
|
|
28
33
|
"release:minor": "npm run release:version:minor && npm run release:sync && npm run release:commit",
|
|
29
34
|
"release:version": "npm version patch --no-git-tag-version",
|
|
@@ -33,11 +38,11 @@
|
|
|
33
38
|
"release:publish": "git push && git push --tags"
|
|
34
39
|
},
|
|
35
40
|
"optionalDependencies": {
|
|
36
|
-
"@aptre/bldr-saucer-darwin-arm64": "0.
|
|
37
|
-
"@aptre/bldr-saucer-darwin-x64": "0.
|
|
38
|
-
"@aptre/bldr-saucer-linux-x64": "0.
|
|
39
|
-
"@aptre/bldr-saucer-linux-arm64": "0.
|
|
40
|
-
"@aptre/bldr-saucer-win32-x64": "0.
|
|
41
|
+
"@aptre/bldr-saucer-darwin-arm64": "0.4.2",
|
|
42
|
+
"@aptre/bldr-saucer-darwin-x64": "0.4.2",
|
|
43
|
+
"@aptre/bldr-saucer-linux-x64": "0.4.2",
|
|
44
|
+
"@aptre/bldr-saucer-linux-arm64": "0.4.2",
|
|
45
|
+
"@aptre/bldr-saucer-win32-x64": "0.4.2"
|
|
41
46
|
},
|
|
42
47
|
"files": [
|
|
43
48
|
"index.js",
|
|
@@ -46,7 +51,7 @@
|
|
|
46
51
|
"CMakeLists.txt"
|
|
47
52
|
],
|
|
48
53
|
"devDependencies": {
|
|
49
|
-
"@aptre/common": "^0.
|
|
54
|
+
"@aptre/common": "^0.32.0"
|
|
50
55
|
},
|
|
51
56
|
"dependencies": {
|
|
52
57
|
"@aptre/protobuf-es-lite": "^1.0.0"
|
package/src/main.cpp
CHANGED
|
@@ -120,7 +120,6 @@ coco::stray start(saucer::application* app) {
|
|
|
120
120
|
auto window = saucer::window::create(app).value();
|
|
121
121
|
auto webview = saucer::smartview::create({
|
|
122
122
|
.window = window,
|
|
123
|
-
.non_persistent_data_store = true,
|
|
124
123
|
.storage_path = storage,
|
|
125
124
|
});
|
|
126
125
|
|
|
@@ -128,9 +127,9 @@ coco::stray start(saucer::application* app) {
|
|
|
128
127
|
window->set_size({1024, 768});
|
|
129
128
|
|
|
130
129
|
// Handle bldr:// scheme: forward all requests to Go over yamux.
|
|
131
|
-
webview->
|
|
132
|
-
std::thread([forwarder, req = std::move(req),
|
|
133
|
-
forwarder->forward(req,
|
|
130
|
+
webview->handle_scheme("bldr", [forwarder](saucer::scheme::request req, saucer::scheme::executor executor) {
|
|
131
|
+
std::thread([forwarder, req = std::move(req), executor = std::move(executor)]() mutable {
|
|
132
|
+
forwarder->forward(req, executor);
|
|
134
133
|
}).detach();
|
|
135
134
|
});
|
|
136
135
|
|
package/src/scheme_forwarder.cpp
CHANGED
|
@@ -23,25 +23,33 @@ static const std::map<std::string, std::string> corsHeaders = {
|
|
|
23
23
|
{"Access-Control-Allow-Headers", "*"},
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
-
// sendError
|
|
27
|
-
static void sendError(saucer::scheme::
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
// sendError resolves the executor with an error status response.
|
|
27
|
+
static void sendError(saucer::scheme::executor& executor, int status) {
|
|
28
|
+
executor.resolve({
|
|
29
|
+
.data = saucer::stash::empty(),
|
|
30
|
+
.mime = "text/plain",
|
|
31
|
+
.headers = corsHeaders,
|
|
32
|
+
.status = status,
|
|
33
|
+
});
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
void SchemeForwarder::forward(const saucer::scheme::request& req,
|
|
33
|
-
saucer::scheme::
|
|
37
|
+
saucer::scheme::executor& executor) {
|
|
34
38
|
// Handle CORS preflight directly without forwarding to Go.
|
|
35
39
|
if (toLower(req.method()) == "options") {
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
executor.resolve({
|
|
41
|
+
.data = saucer::stash::empty(),
|
|
42
|
+
.mime = "text/plain",
|
|
43
|
+
.headers = corsHeaders,
|
|
44
|
+
.status = 204,
|
|
45
|
+
});
|
|
38
46
|
return;
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
// Open a new yamux stream.
|
|
42
50
|
auto [stream, err] = session_->OpenStream();
|
|
43
51
|
if (err != yamux::Error::OK || !stream) {
|
|
44
|
-
sendError(
|
|
52
|
+
sendError(executor, 502);
|
|
45
53
|
return;
|
|
46
54
|
}
|
|
47
55
|
|
|
@@ -56,58 +64,64 @@ void SchemeForwarder::forward(const saucer::scheme::request& req,
|
|
|
56
64
|
}
|
|
57
65
|
|
|
58
66
|
// Check if request has a body.
|
|
59
|
-
auto content = req.content();
|
|
67
|
+
auto content = req.content().data();
|
|
60
68
|
info.has_body = (content.size() > 0);
|
|
61
69
|
|
|
62
70
|
// Serialize and send FetchRequestInfo frame.
|
|
63
71
|
auto reqInfoMsg = proto::EncodeFetchRequest_Info(info);
|
|
64
72
|
if (!writeFrame(stream.get(), reqInfoMsg)) {
|
|
65
73
|
stream->Close();
|
|
66
|
-
sendError(
|
|
74
|
+
sendError(executor, 502);
|
|
67
75
|
return;
|
|
68
76
|
}
|
|
69
77
|
|
|
70
78
|
// Send body if present.
|
|
71
79
|
if (info.has_body) {
|
|
72
80
|
proto::FetchRequestData bodyData;
|
|
73
|
-
bodyData.data.assign(
|
|
74
|
-
static_cast<const uint8_t*>(content.data()),
|
|
75
|
-
static_cast<const uint8_t*>(content.data()) + content.size()
|
|
76
|
-
);
|
|
81
|
+
bodyData.data.assign(content.data(), content.data() + content.size());
|
|
77
82
|
bodyData.done = true;
|
|
78
83
|
|
|
79
84
|
auto reqDataMsg = proto::EncodeFetchRequest_Data(bodyData);
|
|
80
85
|
if (!writeFrame(stream.get(), reqDataMsg)) {
|
|
81
86
|
stream->Close();
|
|
82
|
-
sendError(
|
|
87
|
+
sendError(executor, 502);
|
|
83
88
|
return;
|
|
84
89
|
}
|
|
85
90
|
}
|
|
86
91
|
|
|
92
|
+
// Create streaming stash for incremental response delivery.
|
|
93
|
+
auto result = saucer::scheme::response::stream();
|
|
94
|
+
if (!result) {
|
|
95
|
+
executor.reject(saucer::scheme::error::failed);
|
|
96
|
+
stream->Close();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
auto [stash, write] = std::move(*result);
|
|
100
|
+
|
|
87
101
|
// Read response frames from Go.
|
|
88
|
-
bool
|
|
102
|
+
bool resolved = false;
|
|
89
103
|
bool done = false;
|
|
90
104
|
|
|
91
105
|
while (!done) {
|
|
92
106
|
std::vector<uint8_t> frame;
|
|
93
107
|
if (!readFrame(stream.get(), frame)) {
|
|
94
|
-
if (!
|
|
95
|
-
|
|
108
|
+
if (!resolved) {
|
|
109
|
+
executor.reject(saucer::scheme::error::failed);
|
|
96
110
|
}
|
|
97
111
|
break;
|
|
98
112
|
}
|
|
99
113
|
|
|
100
114
|
proto::FetchResponse resp;
|
|
101
115
|
if (!proto::DecodeFetchResponse(frame.data(), frame.size(), resp)) {
|
|
102
|
-
if (!
|
|
103
|
-
|
|
116
|
+
if (!resolved) {
|
|
117
|
+
executor.reject(saucer::scheme::error::failed);
|
|
104
118
|
}
|
|
105
119
|
break;
|
|
106
120
|
}
|
|
107
121
|
|
|
108
|
-
// Process ResponseInfo (first frame).
|
|
109
|
-
if (resp.has_info && !
|
|
110
|
-
|
|
122
|
+
// Process ResponseInfo (first frame): resolve executor with headers and streaming stash.
|
|
123
|
+
if (resp.has_info && !resolved) {
|
|
124
|
+
resolved = true;
|
|
111
125
|
|
|
112
126
|
// Extract Content-Type header (case-insensitive) and merge CORS headers.
|
|
113
127
|
std::string mime = "application/octet-stream";
|
|
@@ -120,22 +134,29 @@ void SchemeForwarder::forward(const saucer::scheme::request& req,
|
|
|
120
134
|
}
|
|
121
135
|
}
|
|
122
136
|
|
|
123
|
-
|
|
137
|
+
executor.resolve({
|
|
138
|
+
.data = std::move(stash),
|
|
124
139
|
.mime = mime,
|
|
125
140
|
.headers = hdrs,
|
|
126
141
|
.status = static_cast<int>(resp.info.status),
|
|
127
142
|
});
|
|
128
143
|
}
|
|
129
144
|
|
|
130
|
-
// Process ResponseData.
|
|
145
|
+
// Process ResponseData: push body chunks via streaming write callback.
|
|
131
146
|
if (resp.has_data) {
|
|
132
|
-
if (!
|
|
133
|
-
|
|
134
|
-
|
|
147
|
+
if (!resolved) {
|
|
148
|
+
resolved = true;
|
|
149
|
+
executor.resolve({
|
|
150
|
+
.data = std::move(stash),
|
|
151
|
+
.mime = "application/octet-stream",
|
|
152
|
+
.status = 200,
|
|
153
|
+
});
|
|
135
154
|
}
|
|
136
155
|
|
|
137
|
-
if (!resp.data.data.empty()
|
|
138
|
-
|
|
156
|
+
if (!resp.data.data.empty()) {
|
|
157
|
+
if (!write({resp.data.data.data(), resp.data.data.size()})) {
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
139
160
|
}
|
|
140
161
|
|
|
141
162
|
if (resp.data.done) {
|
|
@@ -144,9 +165,7 @@ void SchemeForwarder::forward(const saucer::scheme::request& req,
|
|
|
144
165
|
}
|
|
145
166
|
}
|
|
146
167
|
|
|
147
|
-
|
|
148
|
-
writer.finish();
|
|
149
|
-
}
|
|
168
|
+
// Destroying write closes the streaming stash.
|
|
150
169
|
stream->Close();
|
|
151
170
|
}
|
|
152
171
|
|
package/src/scheme_forwarder.h
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#include "fetch_proto.h"
|
|
4
4
|
#include "yamux/session.hpp"
|
|
5
5
|
|
|
6
|
+
#include <saucer/scheme.hpp>
|
|
6
7
|
#include <saucer/smartview.hpp>
|
|
7
8
|
|
|
8
9
|
#include <cstdint>
|
|
@@ -21,7 +22,7 @@ public:
|
|
|
21
22
|
explicit SchemeForwarder(yamux::Session* session) : session_(session) {}
|
|
22
23
|
|
|
23
24
|
// forward handles a single scheme request by forwarding it to Go.
|
|
24
|
-
void forward(const saucer::scheme::request& req, saucer::scheme::
|
|
25
|
+
void forward(const saucer::scheme::request& req, saucer::scheme::executor& executor);
|
|
25
26
|
|
|
26
27
|
private:
|
|
27
28
|
// writeFrame writes a length-prefixed frame to a yamux stream.
|