Skip to content

Commit d54021e

Browse files
committed
working lws http client
1 parent 8dc3884 commit d54021e

File tree

10 files changed

+333
-77
lines changed

10 files changed

+333
-77
lines changed

examples/libpeer/CMakeLists.txt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ find_package(peer REQUIRED)
2222

2323
set(src
2424
src/main.cpp
25-
src/websocket_wrapper.cpp
2625
src/webrtc_connection.cpp
26+
src/lws_http_client.cpp
27+
src/lws_websocket.cpp
2728
src/lws_context_manager.cpp
2829
)
2930

@@ -36,9 +37,6 @@ target_link_libraries(libpeer_device
3637
NabtoWebrtcSignaling::util_uuid
3738
NabtoWebrtcSignaling::util_message_transport
3839
NabtoWebrtcSignaling::util_token_generator
39-
40-
NabtoWebrtcSignaling::util_curl_client
41-
4240
websockets
4341
peer
4442
)

examples/libpeer/CMakePresets.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,27 @@
2525
"CMAKE_BUILD_TYPE": "Debug",
2626
"BUILD_SHARED_LIBS": "OFF"
2727
}
28+
},
29+
{
30+
"name": "release",
31+
"inherits": [
32+
"base",
33+
"unix_base",
34+
"vcpkg_base"
35+
],
36+
"cacheVariables": {
37+
"CMAKE_BUILD_TYPE": "Release"
38+
}
2839
}
2940
],
3041
"buildPresets": [
42+
{
43+
"name": "release",
44+
"configurePreset": "release",
45+
"targets": [
46+
"install"
47+
]
48+
},
3149
{
3250
"name": "debug",
3351
"configurePreset": "debug",
@@ -37,6 +55,19 @@
3755
}
3856
],
3957
"workflowPresets": [
58+
{
59+
"name": "release",
60+
"steps": [
61+
{
62+
"type": "configure",
63+
"name": "release"
64+
},
65+
{
66+
"type": "build",
67+
"name": "release"
68+
}
69+
]
70+
},
4071
{
4172
"name": "debug",
4273
"steps": [

examples/libpeer/src/lws_context_manager.cpp

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <nabto/webrtc/util/logging.hpp>
22
#include "lws_context_manager.hpp"
3-
#include "websocket_wrapper.hpp"
3+
#include "lws_websocket.hpp"
4+
#include "lws_http_client.hpp"
45

56
#include <plog/Log.h>
67

@@ -11,14 +12,19 @@ namespace nabto::example {
1112
struct lws_protocols lwsProtocols[] = {
1213
{
1314
"lws-websocket-protocol",
14-
LwsWebsocket::websocketCallback,
15+
LwsWebsocket::lwsCallback,
16+
0,
17+
0
18+
},
19+
{
20+
"lws-http-protocol",
21+
LwsHttpClient::lwsCallback,
1522
0,
1623
0
1724
},
1825
{ nullptr, nullptr, 0, 0 }
1926
};
2027

21-
2228
std::weak_ptr<LwsContextManager> LwsContextManager::instance_;
2329
std::mutex LwsContextManager::instanceMutex_;
2430

@@ -62,16 +68,6 @@ void LwsContextManager::serviceLoop() {
6268
}
6369
}
6470

65-
void LwsContextManager::registerWebsocket(struct lws* wsi) {
66-
std::lock_guard<std::mutex> lock(mutex_);
67-
activeConnections_ += 1;
68-
}
69-
70-
void LwsContextManager::unregisterWebsocket(struct lws* wsi) {
71-
std::lock_guard<std::mutex> lock(mutex_);
72-
activeConnections_ -= 1;
73-
}
74-
7571
void LwsContextManager::cleanup() {
7672
running_ = false;
7773

examples/libpeer/src/lws_context_manager.hpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ class LwsContextManager {
1515
~LwsContextManager();
1616

1717
struct lws_context* getContext() { return context_; }
18-
19-
void registerWebsocket(struct lws* wsi);
20-
void unregisterWebsocket(struct lws* wsi);
2118
private:
2219
LwsContextManager();
2320
void serviceLoop();
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
#include <iostream>
2+
#include <nabto/webrtc/util/logging.hpp>
3+
#include "lws_http_client.hpp"
4+
#include "util.hpp"
5+
6+
namespace nabto::example {
7+
8+
std::unordered_map<uint64_t, LwsHttpClient::Request> LwsHttpClient::requests_;
9+
10+
LwsHttpClient::LwsHttpClient() {
11+
}
12+
13+
LwsHttpClient::~LwsHttpClient() {
14+
cleanup();
15+
}
16+
17+
void LwsHttpClient::cleanup() {
18+
}
19+
20+
bool LwsHttpClient::sendRequest(const nabto::webrtc::SignalingHttpRequest& request,
21+
nabto::webrtc::HttpResponseCallback cb) {
22+
std::lock_guard<std::mutex> lock(sendMutex_);
23+
24+
auto parsed = parseUrl(request.url);
25+
auto protocol = std::get<0>(parsed);
26+
auto host = std::get<1>(parsed);
27+
auto path = std::get<2>(parsed);
28+
29+
struct lws_client_connect_info ccinfo = {};
30+
ccinfo.context = contextManager_->getContext();
31+
32+
ccinfo.ssl_connection = LCCSCF_USE_SSL;
33+
ccinfo.port = 443;
34+
ccinfo.address = host.c_str();
35+
ccinfo.path = path.c_str();
36+
ccinfo.host = ccinfo.address;
37+
ccinfo.origin = ccinfo.address;
38+
ccinfo.method = request.method.c_str();
39+
ccinfo.alpn = "http/1.1";
40+
41+
NPLOGI << request.method << " " << request.body;
42+
43+
uint64_t handle = requestIndex_++;
44+
requests_[handle] = { this, cb, request, "", 0, 0 };
45+
requests_[handle].req.headers.push_back({ "Content-Length", std::to_string(request.body.length()) });
46+
47+
ccinfo.protocol = "lws-http-protocol";
48+
ccinfo.userdata = reinterpret_cast<void*>(handle);
49+
ccinfo.userdata = (void*)handle;
50+
ccinfo.pwsi = &requests_[handle].wsi;
51+
52+
if (!lws_client_connect_via_info(&ccinfo)) {
53+
NPLOGE << "Client creation failed!";
54+
return false;
55+
}
56+
57+
return true;
58+
}
59+
60+
int LwsHttpClient::lwsCallback(struct lws* wsi, enum lws_callback_reasons reason,
61+
void* user, void* in, size_t len) {
62+
uint64_t handle = (uint64_t)user;
63+
Request& r = requests_[handle];
64+
65+
char buf[LWS_PRE + 1024];
66+
char* start = &buf[LWS_PRE];
67+
char* end = &buf[sizeof(buf) - 1];
68+
char* p = start;
69+
int n;
70+
71+
switch (reason) {
72+
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: {
73+
NPLOGI << "CLIENT_CONNECTION_ERROR";
74+
break;
75+
}
76+
77+
case LWS_CALLBACK_CLOSED_CLIENT_HTTP: {
78+
NPLOGI << "CLOSED_CLIENT_HTTP";
79+
requests_.erase(handle);
80+
break;
81+
}
82+
83+
// Receiving callbacks
84+
85+
case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: {
86+
int status = lws_http_client_http_response(wsi);
87+
NPLOGI << "ESTABLISHED_CLIENT_HTTP : " << status;
88+
r.statusCode = status;
89+
break;
90+
}
91+
92+
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: {
93+
NPLOGI << "RECEIVE_CLIENT_HTTP_READ : read " << len;
94+
std::string chunk(static_cast<const char*>(in), len);
95+
r.body += chunk;
96+
break;
97+
}
98+
99+
case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: {
100+
n = sizeof(buf) - LWS_PRE;
101+
if (lws_http_client_read(wsi, &p, &n) < 0) {
102+
return -1;
103+
}
104+
return 0;
105+
}
106+
107+
case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: {
108+
NPLOGI << "COMPLETED_CLIENT_HTTP : status " << r.statusCode << " : " << r.body;
109+
auto response = std::make_unique<nabto::webrtc::SignalingHttpResponse>();
110+
response->statusCode = r.statusCode;
111+
response->body = r.body;
112+
r.cb(std::move(response));
113+
break;
114+
}
115+
116+
// Callbacks for generating POST data
117+
118+
case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: {
119+
if (!lws_http_is_redirected_to_get(wsi)) {
120+
NPLOGI << "APPEND_HANDSHAKE_HEADER : doing POST flow";
121+
122+
unsigned char **headerPtr = (unsigned char**)in;
123+
unsigned char *headerEnd = (*headerPtr) + len;
124+
125+
for (auto& element : r.req.headers) {
126+
lws_add_http_header_by_name(
127+
wsi,
128+
(unsigned char*)element.first.c_str(),
129+
(unsigned char*)element.second.c_str(),
130+
element.second.length(),
131+
headerPtr,
132+
headerEnd
133+
);
134+
}
135+
136+
lws_client_http_body_pending(wsi, 1);
137+
lws_callback_on_writable(wsi);
138+
} else {
139+
NPLOGI << "APPEND_HANDSHAKE_HEADER : doing GET flow";
140+
}
141+
142+
return 0;
143+
}
144+
145+
case LWS_CALLBACK_CLIENT_HTTP_WRITEABLE: {
146+
NPLOGI << "CLIENT_HTTP_WRITEABLE";
147+
148+
if (lws_http_is_redirected_to_get(wsi)) {
149+
break;
150+
}
151+
152+
enum lws_write_protocol prot = LWS_WRITE_HTTP;
153+
size_t remaining = r.req.body.length() - r.writtenBytes;
154+
size_t chunkSize = std::min(remaining, (size_t)1024);
155+
156+
memcpy(start, r.req.body.c_str() + r.writtenBytes, chunkSize);
157+
r.writtenBytes += chunkSize;
158+
159+
if (r.writtenBytes >= r.req.body.length()) {
160+
prot = LWS_WRITE_HTTP_FINAL;
161+
}
162+
163+
int written = lws_write(wsi, (uint8_t*)start, chunkSize, prot);
164+
165+
if (written != chunkSize) {
166+
return 1;
167+
}
168+
169+
if (prot != LWS_WRITE_HTTP_FINAL) {
170+
lws_callback_on_writable(wsi);
171+
} else {
172+
lws_client_http_body_pending(wsi, 0);
173+
}
174+
175+
return 0;
176+
}
177+
178+
default: {
179+
break;
180+
}
181+
}
182+
183+
return lws_callback_http_dummy(wsi, reason, user, in, len);
184+
}
185+
186+
} // nabto::webrtc
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#pragma once
2+
3+
#include <mutex>
4+
#include <unordered_map>
5+
6+
#include <nabto/webrtc/device.hpp>
7+
#include "lws_context_manager.hpp"
8+
9+
namespace nabto::example {
10+
11+
class LwsHttpClient : public nabto::webrtc::SignalingHttpClient {
12+
public:
13+
static nabto::webrtc::SignalingHttpClientPtr create() {
14+
return std::make_shared<LwsHttpClient>();
15+
}
16+
17+
static int lwsCallback(struct lws* wsi, enum lws_callback_reasons reason,
18+
void* user, void* in, size_t len);
19+
20+
LwsHttpClient();
21+
~LwsHttpClient() override;
22+
LwsHttpClient(const LwsHttpClient&) = delete;
23+
LwsHttpClient& operator=(const LwsHttpClient&) = delete;
24+
LwsHttpClient(LwsHttpClient&&) = delete;
25+
LwsHttpClient& operator=(LwsHttpClient&&) = delete;
26+
27+
bool sendRequest(const nabto::webrtc::SignalingHttpRequest& request,
28+
nabto::webrtc::HttpResponseCallback cb) override;
29+
30+
private:
31+
struct Request {
32+
LwsHttpClient* client;
33+
nabto::webrtc::HttpResponseCallback cb;
34+
nabto::webrtc::SignalingHttpRequest req;
35+
std::string body;
36+
int statusCode;
37+
size_t writtenBytes;
38+
39+
uint64_t handle;
40+
struct lws* wsi;
41+
};
42+
uint64_t requestIndex_ = 0;
43+
static std::unordered_map<uint64_t, Request> requests_;
44+
45+
void cleanup();
46+
47+
std::shared_ptr<LwsContextManager> contextManager_ = LwsContextManager::getInstance();
48+
std::atomic<bool> connected_{false};
49+
50+
51+
std::mutex sendMutex_;
52+
};
53+
54+
} // nabto::example

0 commit comments

Comments
 (0)