Implement http-module (#637)
Create http-module and implement it in App Hub and App Hub Details apps.
This commit is contained in:
committed by
GitHub
parent
d2442bedb4
commit
bcbf18e363
@@ -0,0 +1,143 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <tactility/concurrent/task_event_group.h>
|
||||
#include <tactility/error.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Identifies how a download finished, as delivered to http_download_poll(). */
|
||||
enum HttpDownloadEventType {
|
||||
HTTP_DOWNLOAD_EVENT_SUCCESS, // no data
|
||||
HTTP_DOWNLOAD_EVENT_ERROR, // struct HttpDownloadErrorEvent
|
||||
HTTP_DOWNLOAD_EVENT_CANCELLED, // no data - see http_download_cancel()
|
||||
};
|
||||
|
||||
#define HTTP_DOWNLOAD_ERROR_MESSAGE_MAX_LEN 64
|
||||
|
||||
/** Data for HTTP_DOWNLOAD_EVENT_ERROR. */
|
||||
struct HttpDownloadErrorEvent {
|
||||
char message[HTTP_DOWNLOAD_ERROR_MESSAGE_MAX_LEN];
|
||||
};
|
||||
|
||||
/** Event delivered through http_download_poll() once a download's task finishes. */
|
||||
struct HttpDownloadEvent {
|
||||
enum HttpDownloadEventType type;
|
||||
/** Microseconds since boot, from get_micros_since_boot(). */
|
||||
uint64_t timestamp;
|
||||
/** The server's HTTP response status code, or 0 if no response was ever received
|
||||
* (e.g. failed to open the connection, or platform doesn't support downloads). */
|
||||
int32_t status_code;
|
||||
/** Valid only when type == HTTP_DOWNLOAD_EVENT_ERROR. */
|
||||
struct HttpDownloadErrorEvent error;
|
||||
};
|
||||
|
||||
/** Internal, refcounted state shared between a subscription and its download task - lets
|
||||
* http_download_unsubscribe() sever the link safely at any time, even mid-download (see its
|
||||
* own doc). Defined only in download.cpp; opaque here like Module::internal (tactility/module.h). */
|
||||
struct HttpDownloadLink;
|
||||
|
||||
/**
|
||||
* Caller-owned subscription node for one download's outcome, registered with
|
||||
* http_download_subscribe() and polled with http_download_poll() - same subscribe/await/poll
|
||||
* shape as TactilityKernel's system_event and app-module's app_event. Unlike those (which
|
||||
* multiplex many emitters/subscribers by type or app instance), one subscription always belongs
|
||||
* to exactly one download and receives exactly one terminal event.
|
||||
* @warning Fields other than `bit` are for internal use only; do not read or write them directly.
|
||||
*/
|
||||
struct HttpDownloadSubscription {
|
||||
/** Set by http_download_subscribe(). Read-only for the caller: OR it into a
|
||||
* task_event_group_wait() mask (alongside other subscriptions sharing the same
|
||||
* `internal.event_group`) to block on this subscription and other event sources with one
|
||||
* call. */
|
||||
uint32_t bit;
|
||||
|
||||
struct {
|
||||
/** Caller-owned, borrowed; set by http_download_subscribe(). */
|
||||
struct TaskEventGroup* event_group;
|
||||
struct HttpDownloadEvent event;
|
||||
bool pending;
|
||||
struct HttpDownloadLink* link;
|
||||
} internal;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a poll subscription for one download's outcome.
|
||||
* @warning Does not work in ISR context.
|
||||
* @warning Must be called before http_download_start(), so the download task can never finish
|
||||
* before a subscriber exists to notify.
|
||||
* @param[in,out] sub subscription to register; caller owns the storage and must keep it alive
|
||||
* (and stationary) until http_download_unsubscribe()
|
||||
* @param[in] event_group caller-owned group to wait on; must outlive @a sub. To block for the
|
||||
* outcome, call task_event_group_wait()/task_event_group_wait_any() on this group (OR sub->bit
|
||||
* into the mask, or use _wait_any() to include every subscription sharing it), then poll with
|
||||
* http_download_poll().
|
||||
* @retval ERROR_NONE on success
|
||||
* @retval ERROR_RESOURCE @a event_group has no free bits left to claim; @a sub was not registered
|
||||
* @retval ERROR_OUT_OF_MEMORY failed to allocate @a sub's internal link; @a sub was not registered
|
||||
*/
|
||||
error_t http_download_subscribe(struct HttpDownloadSubscription* sub, struct TaskEventGroup* event_group);
|
||||
|
||||
/**
|
||||
* Remove a previously registered subscription. Safe to call at any time, including while the
|
||||
* download is still in flight (e.g. right after http_download_cancel()) - the download task
|
||||
* never touches @a sub or its event_group again once this returns, so both may be destructed
|
||||
* immediately afterward without waiting for the download to actually finish.
|
||||
* @warning Does not work in ISR context.
|
||||
* @return ERROR_NONE on success, ERROR_NOT_FOUND if @a sub isn't currently subscribed
|
||||
*/
|
||||
error_t http_download_unsubscribe(struct HttpDownloadSubscription* sub);
|
||||
|
||||
/**
|
||||
* Non-blocking: check whether the download's terminal event has arrived.
|
||||
* @warning Never blocks. To wait, block in task_event_group_wait()/task_event_group_wait_any()
|
||||
* on @a sub's bit first (see http_download_subscribe()), then call this.
|
||||
* @param[in,out] sub subscription to poll, as passed to http_download_subscribe()
|
||||
* @param[out] out_event set to the download's outcome
|
||||
* @retval ERROR_NONE the terminal event arrived - it is copied into @a out_event
|
||||
* @retval ERROR_TIMEOUT the download hasn't finished yet
|
||||
*/
|
||||
error_t http_download_poll(struct HttpDownloadSubscription* sub, struct HttpDownloadEvent* out_event);
|
||||
|
||||
/**
|
||||
* Starts a download on its own dedicated task: issues a GET request for @a url, verifying the
|
||||
* server against the PEM certificate at @a cert_path, and writes the response body to
|
||||
* @a target_path.
|
||||
* @param[in] url the URL to download
|
||||
* @param[in] cert_path path to a PEM certificate file used to verify the server
|
||||
* @param[in] target_path path to write the downloaded file to
|
||||
* @param[in] sub subscription to notify on completion, already registered via
|
||||
* http_download_subscribe(); must stay alive (and stationary) at least until
|
||||
* http_download_unsubscribe() is called
|
||||
* @retval ERROR_NONE the download task was started
|
||||
* @retval ERROR_INVALID_ARGUMENT @a sub is not currently subscribed
|
||||
* @retval ERROR_OUT_OF_MEMORY failed to allocate the download task
|
||||
*/
|
||||
error_t http_download_start(
|
||||
const char* url,
|
||||
const char* cert_path,
|
||||
const char* target_path,
|
||||
struct HttpDownloadSubscription* sub
|
||||
);
|
||||
|
||||
/**
|
||||
* Request cancellation of @a sub's in-flight download. Best-effort and asynchronous: the
|
||||
* download task only checks for this periodically (between I/O steps), so it keeps running for
|
||||
* a short while after this returns. If you still want the outcome, poll as usual - it finishes
|
||||
* with HTTP_DOWNLOAD_EVENT_CANCELLED. If you don't, http_download_unsubscribe() may be called
|
||||
* right away instead of waiting for that - see its own doc.
|
||||
* @param[in,out] sub subscription for the download to cancel, as passed to
|
||||
* http_download_subscribe()
|
||||
* @retval ERROR_NONE the cancellation request was recorded
|
||||
* @retval ERROR_INVALID_STATE @a sub is not currently subscribed
|
||||
*/
|
||||
error_t http_download_cancel(struct HttpDownloadSubscription* sub);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <tactility/module.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern struct Module http_module;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user