Skip to content

Commit dfa25bc

Browse files
author
MatthewColvin
committed
Tweak curl http client so it works with roku
1 parent 92e1f7e commit dfa25bc

6 files changed

Lines changed: 157 additions & 289 deletions

File tree

Platformio/lib/Device/Custom/RokuHttp.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,17 @@ void RokuHttp::sendKeyPress(const std::string &keyName) {
108108
}
109109

110110
std::string url = buildRokuUrl("/keypress/" + keyName);
111-
mHttpClient->postAsync(url, "")->onError([](const HttpResponse &err) {
112-
// TODO: Handle Error Somehow
113-
// Handle error silently for now
114-
});
111+
112+
HttpRequest request(HttpRequest::Method::POST, url);
113+
// TODO Try and add the other headers from postman here
114+
// request.headers["Content-Type"] = "application/x-www-form-urlencoded";
115+
request.headers["Expect"] = "";
116+
request.headers["Content-Type"] = "application/x-www-form-urlencoded";
117+
request.headers["Accept"] = "*/*";
118+
request.timeout_ms = 2000;
119+
120+
mHttpClient->executeAsync(request)
121+
->onReturnCode(200, [](const HttpResponse &sSuccess) {});
115122
}
116123

117124
void RokuHttp::launchApp(const std::string &appId) {
@@ -121,7 +128,5 @@ void RokuHttp::launchApp(const std::string &appId) {
121128

122129
std::string url = buildRokuUrl("/launch/app");
123130
std::string body = appId;
124-
mHttpClient->postAsync(url, body)->onError([](const HttpResponse &err) {
125-
// Handle error silently for now
126-
});
131+
mHttpClient->postAsync(url, body)->onReturnCode(200, [](const HttpResponse &sSuccess) {});
127132
}

Platformio/lib/HAL/Hardware/wifi/http/HttpTypes.cpp

Lines changed: 15 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,10 @@ HttpRequest::HttpRequest(Method aMethod, const std::string &aUrl, const std::str
2121
// HttpFuture implementation
2222
HttpFuture::HttpFuture(std::future<HttpResponse> aFuture)
2323
: mFuture(std::move(aFuture)),
24-
mResponseCallback(nullptr),
25-
mErrorCallback(nullptr),
26-
mIsBlocking(false),
2724
mReturnCodeDefaultCallback(nullptr) {}
2825

2926
std::shared_ptr<HttpFuture> HttpFuture::onReturnCode(int aCode, ResponseCallback aCallback) {
3027
mReturnCodeCallbacks[aCode] = aCallback;
31-
checkAndInvoke();
3228
return shared_from_this();
3329
}
3430

@@ -37,88 +33,14 @@ std::shared_ptr<HttpFuture> HttpFuture::onReturnCode(const std::vector<int> &aCo
3733
for (int aCode : aCodes) {
3834
mReturnCodeCallbacks[aCode] = aCallback;
3935
}
40-
checkAndInvoke();
4136
return shared_from_this();
4237
}
4338

4439
std::shared_ptr<HttpFuture> HttpFuture::onOtherReturnCode(ResponseCallback aCallback) {
4540
mReturnCodeDefaultCallback = aCallback;
46-
checkAndInvoke();
4741
return shared_from_this();
4842
}
4943

50-
std::shared_ptr<HttpFuture> HttpFuture::onResponse(ResponseCallback aCallback) {
51-
mResponseCallback = aCallback;
52-
checkAndInvoke();
53-
return shared_from_this();
54-
}
55-
56-
std::shared_ptr<HttpFuture> HttpFuture::onError(ErrorCallback aCallback) {
57-
mErrorCallback = aCallback;
58-
checkAndInvoke();
59-
return shared_from_this();
60-
}
61-
62-
std::shared_ptr<HttpFuture> HttpFuture::then(ResponseCallback aOnResponse, ErrorCallback aOnError) {
63-
mResponseCallback = aOnResponse;
64-
mErrorCallback = aOnError;
65-
checkAndInvoke();
66-
return shared_from_this();
67-
}
68-
69-
std::shared_ptr<HttpFuture> HttpFuture::flatMap(TransformCallback aTransform) {
70-
// If future is ready, transform immediately
71-
if (mFuture.valid() &&
72-
mFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
73-
// Note: exceptions are not used here. If the transform callable throws
74-
// and exceptions are disabled, the program will terminate. Callers
75-
// should avoid throwing from transform when building without
76-
// exceptions (ESP builds).
77-
HttpResponse aResp = mFuture.get();
78-
return aTransform(aResp);
79-
}
80-
81-
// Otherwise, chain the transformation
82-
std::shared_ptr<HttpFuture> aSelf = shared_from_this();
83-
onResponse([aSelf, aTransform](const HttpResponse &aResp) {
84-
auto aNextFuture = aTransform(aResp);
85-
if (aNextFuture) {
86-
// Propagate callbacks to next future if needed
87-
// (callbacks are already set on the returned future)
88-
}
89-
});
90-
91-
return shared_from_this();
92-
}
93-
94-
std::shared_ptr<HttpFuture> HttpFuture::map(
95-
std::function<HttpResponse(const HttpResponse &)> aTransform) {
96-
if (mFuture.valid() &&
97-
mFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
98-
// Note: do not throw in transform when building without exceptions.
99-
HttpResponse aResp = mFuture.get();
100-
HttpResponse aTransformed = aTransform(aResp);
101-
auto aNewFuture = std::make_shared<HttpFuture>(
102-
std::async(std::launch::deferred, [aTransformed]() { return aTransformed; }));
103-
return aNewFuture;
104-
}
105-
106-
std::shared_ptr<HttpFuture> aSelf = shared_from_this();
107-
auto aMappedPromise = std::make_shared<std::promise<HttpResponse>>();
108-
109-
onResponse([aSelf, aTransform, aMappedPromise](const HttpResponse &aResp) {
110-
// If transform throws and exceptions are disabled the program will
111-
// terminate. Prefer not to throw in callbacks when building for ESP.
112-
HttpResponse aTransformed = aTransform(aResp);
113-
aMappedPromise->set_value(aTransformed);
114-
});
115-
116-
onError([aMappedPromise](const HttpResponse &aErr) { aMappedPromise->set_value(aErr); });
117-
118-
auto aNewFuture = std::make_shared<HttpFuture>(aMappedPromise->get_future());
119-
return aNewFuture;
120-
}
121-
12244
HttpResponse HttpFuture::get() {
12345
if (mFuture.valid()) {
12446
return mFuture.get();
@@ -130,72 +52,31 @@ HttpResponse HttpFuture::get() {
13052
return aError;
13153
}
13254

133-
bool HttpFuture::ready() const {
55+
bool HttpFuture::IsReady() const {
13456
if (!mFuture.valid())
13557
return false;
13658
return mFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
13759
}
13860

139-
std::shared_ptr<HttpFuture> HttpFuture::always(std::function<void(const HttpResponse &)> aCallback) {
140-
auto aCb = [aCallback](const HttpResponse &aResp) { aCallback(aResp); };
141-
142-
// Register for both success and error
143-
if (!mResponseCallback) {
144-
mResponseCallback = aCb;
145-
} else {
146-
auto aExisting = mResponseCallback;
147-
mResponseCallback = [aExisting, aCb](const HttpResponse &aResp) {
148-
aExisting(aResp);
149-
aCb(aResp);
150-
};
61+
void HttpFuture::checkAndInvoke() {
62+
if (!IsReady()) {
63+
return;
15164
}
15265

153-
if (!mErrorCallback) {
154-
mErrorCallback = aCb;
155-
} else {
156-
auto aExisting = mErrorCallback;
157-
mErrorCallback = [aExisting, aCb](const HttpResponse &aResp) {
158-
aExisting(aResp);
159-
aCb(aResp);
160-
};
161-
}
66+
HttpResponse aResponse = mFuture.get();
16267

163-
checkAndInvoke();
164-
return shared_from_this();
165-
}
68+
std::lock_guard<std::mutex> aLock(mCallbackMutex);
16669

167-
void HttpFuture::checkAndInvoke() {
168-
if (!mFuture.valid())
70+
// Check for specific return code handler
71+
auto aIt = mReturnCodeCallbacks.find(aResponse.status_code);
72+
if (aIt != mReturnCodeCallbacks.end()) {
73+
aIt->second(aResponse);
16974
return;
75+
}
17076

171-
if (mFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
172-
// Note: avoid throwing inside futures/callbacks when building without
173-
// exceptions. mFuture.get() should return a valid HttpResponse value
174-
// (implementations should set an error HttpResponse instead of
175-
// throwing). If an exception does escape and exceptions are disabled,
176-
// the program will terminate.
177-
HttpResponse aResponse = mFuture.get();
178-
179-
std::lock_guard<std::mutex> aLock(mCallbackMutex);
180-
181-
// Check for specific return code handler
182-
auto aIt = mReturnCodeCallbacks.find(aResponse.status_code);
183-
if (aIt != mReturnCodeCallbacks.end()) {
184-
aIt->second(aResponse);
185-
return;
186-
}
187-
188-
// Check for default return code handler
189-
if (mReturnCodeDefaultCallback) {
190-
mReturnCodeDefaultCallback(aResponse);
191-
return;
192-
}
193-
194-
// Fall back to success/error handlers
195-
if (aResponse.success && mResponseCallback) {
196-
mResponseCallback(aResponse);
197-
} else if (!aResponse.success && mErrorCallback) {
198-
mErrorCallback(aResponse);
199-
}
77+
// Check for default return code handler
78+
if (mReturnCodeDefaultCallback) {
79+
mReturnCodeDefaultCallback(aResponse);
80+
return;
20081
}
20182
}

Platformio/lib/HAL/Hardware/wifi/http/HttpTypes.hpp

Lines changed: 3 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ struct HttpRequest {
5151
class HttpFuture : public std::enable_shared_from_this<HttpFuture> {
5252
public:
5353
using ResponseCallback = std::function<void(const HttpResponse &)>;
54-
using ErrorCallback = std::function<void(const HttpResponse &)>;
55-
using TransformCallback = std::function<std::shared_ptr<HttpFuture>(const HttpResponse &)>;
5654

5755
explicit HttpFuture(std::future<HttpResponse> aFuture);
5856

@@ -109,55 +107,6 @@ class HttpFuture : public std::enable_shared_from_this<HttpFuture> {
109107
*/
110108
std::shared_ptr<HttpFuture> onOtherReturnCode(ResponseCallback aCallback);
111109

112-
/**
113-
* @brief Register a callback to be invoked on successful response (status 200-299)
114-
*
115-
* @param aCallback Function to call with the response
116-
* @return Shared pointer to this HttpFuture for chaining
117-
*/
118-
std::shared_ptr<HttpFuture> onResponse(ResponseCallback aCallback);
119-
120-
/**
121-
* @brief Register a callback to be invoked on error (non-2xx status or network error)
122-
*
123-
* @param aCallback Function to call with the error response
124-
* @return Shared pointer to this HttpFuture for chaining
125-
*/
126-
std::shared_ptr<HttpFuture> onError(ErrorCallback aCallback);
127-
128-
/**
129-
* @brief Register callbacks for both success and error cases
130-
*
131-
* @param aOnResponse Callback for successful responses
132-
* @param aOnError Callback for errors
133-
* @return Shared pointer to this HttpFuture for chaining
134-
*/
135-
std::shared_ptr<HttpFuture> then(ResponseCallback aOnResponse, ErrorCallback aOnError);
136-
137-
/**
138-
* @brief Transform the response into another HttpFuture (monadic bind)
139-
*
140-
* Allows chaining HTTP requests: first request result feeds into second request
141-
* @example
142-
* httpclient->getAsync("https://api.example.com/user/1")
143-
* ->flatMap([httpclient](const HttpResponse& resp) {
144-
* // Parse resp and make another request
145-
* return httpclient->getAsync("https://api.example.com/user/1/posts");
146-
* })
147-
* ->onResponse([](const HttpResponse& resp) {
148-
* std::cout << resp.body << std::endl;
149-
* });
150-
*/
151-
std::shared_ptr<HttpFuture> flatMap(TransformCallback aTransform);
152-
153-
/**
154-
* @brief Map/transform the response into a new value
155-
*
156-
* @param aTransform Function to transform the response
157-
* @return Shared pointer to a new HttpFuture containing the transformed result
158-
*/
159-
std::shared_ptr<HttpFuture> map(std::function<HttpResponse(const HttpResponse &)> aTransform);
160-
161110
/**
162111
* @brief Block and get the response (synchronous)
163112
*
@@ -183,7 +132,7 @@ class HttpFuture : public std::enable_shared_from_this<HttpFuture> {
183132
*
184133
* @return true if response is ready
185134
*/
186-
bool ready() const;
135+
bool IsReady() const;
187136

188137
/**
189138
* @brief Register a callback to invoke when response is ready (regardless of success/error)
@@ -195,9 +144,7 @@ class HttpFuture : public std::enable_shared_from_this<HttpFuture> {
195144

196145
private:
197146
std::future<HttpResponse> mFuture;
198-
ResponseCallback mResponseCallback;
199-
ErrorCallback mErrorCallback;
200-
bool mIsBlocking;
147+
201148
mutable std::mutex mCallbackMutex;
202149
std::map<int, ResponseCallback> mReturnCodeCallbacks;
203150
ResponseCallback mReturnCodeDefaultCallback;
@@ -206,7 +153,4 @@ class HttpFuture : public std::enable_shared_from_this<HttpFuture> {
206153
* @brief Check if future is ready and invoke appropriate callback
207154
*/
208155
void checkAndInvoke();
209-
};
210-
211-
// Convenience type aliases
212-
using HttpFuturePtr = std::shared_ptr<HttpFuture>;
156+
};

Platformio/lib/JsonConfigUI/screen/JsonHomeScreen.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ JsonHomeScreen::JsonHomeScreen(DeviceFactory &aFactory)
102102
auto jsonDevices = mFactory.getJsonDevices();
103103
return std::make_unique<UI::Page::AddDevice>(mFactory.getActiveDevices(), jsonDevices);
104104
}});
105+
mStatusBar->AddDebugSettingItem({"Add Compile Time Device", LV_SYMBOL_EDIT, [this] {
106+
auto compiledDevices = mFactory.getCompileTimeDevices();
107+
return std::make_unique<UI::Page::AddDevice>(mFactory.getActiveDevices(), compiledDevices);
108+
}});
105109
}
106110

107111
bool JsonHomeScreen::checkSceneForEntryExit(const std::string &aFileName) {

0 commit comments

Comments
 (0)