mirror of
https://github.com/aydencharles/onionHEN.git
synced 2026-10-22 03:42:46 -05:00
225 lines
5.4 KiB
C++
225 lines
5.4 KiB
C++
#pragma once
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <span>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <vector>
|
|
|
|
namespace onion::plugin_ui {
|
|
|
|
inline constexpr uint32_t kDocumentMagic = 0x4449554Fu;
|
|
inline constexpr uint16_t kWireVersion = 1;
|
|
inline constexpr size_t kDocumentHeaderSize = 36;
|
|
inline constexpr size_t kNodeHeaderSize = 60;
|
|
inline constexpr size_t kMaxEncodedSize = 256 * 1024;
|
|
inline constexpr size_t kMaxNodes = 256;
|
|
inline constexpr size_t kMaxDepth = 8;
|
|
|
|
enum class NodeKind : uint16_t {
|
|
Page = 1,
|
|
Menu = 2,
|
|
Group = 3,
|
|
Label = 4,
|
|
Action = 5,
|
|
Toggle = 6,
|
|
List = 7,
|
|
ListItem = 8,
|
|
Input = 9,
|
|
};
|
|
|
|
enum class ValueType : uint32_t {
|
|
None = 0,
|
|
Bool = 1,
|
|
Integer = 2,
|
|
String = 3,
|
|
};
|
|
|
|
enum class BindingKind : uint32_t {
|
|
None = 0,
|
|
Config = 1,
|
|
Event = 2,
|
|
};
|
|
|
|
struct Node {
|
|
NodeKind kind = NodeKind::Label;
|
|
uint32_t flags = 0;
|
|
ValueType value_type = ValueType::None;
|
|
BindingKind binding = BindingKind::None;
|
|
int64_t min_value = 0;
|
|
int64_t max_value = 0;
|
|
uint32_t min_length = 0;
|
|
uint32_t max_length = 0;
|
|
std::string id;
|
|
std::string parent_id;
|
|
std::string title;
|
|
std::string description;
|
|
std::string target_id;
|
|
std::string binding_key;
|
|
std::string value;
|
|
};
|
|
|
|
struct Document {
|
|
uint32_t flags = 0;
|
|
int32_t priority = 0;
|
|
std::string plugin_id;
|
|
std::string contribution_id;
|
|
std::string title;
|
|
std::string description;
|
|
std::string root_page_id;
|
|
std::vector<Node> nodes;
|
|
|
|
const Node *find_node(std::string_view id) const;
|
|
Node *find_node(std::string_view id);
|
|
};
|
|
|
|
enum class Status {
|
|
Ok = 0,
|
|
InvalidArgument,
|
|
InvalidEncoding,
|
|
InvalidDocument,
|
|
PermissionDenied,
|
|
NotFound,
|
|
Stale,
|
|
InvalidState,
|
|
NotSupported,
|
|
Busy,
|
|
};
|
|
|
|
Status decode_document(std::span<const uint8_t> encoded, Document &out,
|
|
std::string *error = nullptr);
|
|
Status encode_document(const Document &document, std::vector<uint8_t> &out,
|
|
std::string *error = nullptr);
|
|
Status validate_document(const Document &document, std::string *error = nullptr);
|
|
|
|
using Handle = uint64_t;
|
|
|
|
struct ContributionSnapshot {
|
|
Handle handle = 0;
|
|
std::string owner;
|
|
std::shared_ptr<const Document> document;
|
|
};
|
|
|
|
struct RegistrySnapshot {
|
|
uint64_t generation = 0;
|
|
std::vector<ContributionSnapshot> contributions;
|
|
|
|
const ContributionSnapshot *find(Handle handle) const;
|
|
};
|
|
|
|
struct RegisterResult {
|
|
Status status = Status::InvalidArgument;
|
|
Handle handle = 0;
|
|
uint64_t generation = 0;
|
|
std::string error;
|
|
};
|
|
|
|
class Registry {
|
|
public:
|
|
RegisterResult register_encoded(std::string_view owner,
|
|
std::span<const uint8_t> encoded);
|
|
Status unregister(std::string_view owner, Handle handle);
|
|
size_t remove_owner(std::string_view owner);
|
|
Status set_value(std::string_view owner, Handle handle,
|
|
std::string_view node_id, ValueType value_type,
|
|
std::string_view value);
|
|
RegistrySnapshot snapshot() const;
|
|
|
|
private:
|
|
mutable std::mutex mutex_;
|
|
uint64_t generation_ = 0;
|
|
Handle next_handle_ = 1;
|
|
std::vector<ContributionSnapshot> contributions_;
|
|
};
|
|
|
|
using TransferId = uint32_t;
|
|
|
|
struct BeginResult {
|
|
Status status = Status::InvalidArgument;
|
|
TransferId transfer_id = 0;
|
|
};
|
|
|
|
enum class WireCommand : uint16_t {
|
|
RegisterBegin = 10,
|
|
RegisterChunk = 11,
|
|
RegisterCommit = 12,
|
|
RegisterAbort = 13,
|
|
Unregister = 14,
|
|
SetValue = 15,
|
|
};
|
|
|
|
struct WireResponse {
|
|
Status status = Status::InvalidArgument;
|
|
std::vector<uint8_t> data;
|
|
};
|
|
|
|
struct ActionEvent {
|
|
std::string owner;
|
|
Handle handle = 0;
|
|
uint64_t sequence = 0;
|
|
ValueType value_type = ValueType::None;
|
|
std::string contribution_id;
|
|
std::string page_id;
|
|
std::string node_id;
|
|
std::string value;
|
|
};
|
|
|
|
using SnapshotSink = void (*)(const RegistrySnapshot &snapshot, void *context);
|
|
|
|
class RegistrationBroker {
|
|
public:
|
|
explicit RegistrationBroker(Registry ®istry) : registry_(registry) {}
|
|
|
|
BeginResult begin(std::string_view owner, uint32_t total_size,
|
|
uint32_t checksum);
|
|
Status append(std::string_view owner, TransferId transfer_id,
|
|
uint32_t offset, std::span<const uint8_t> chunk);
|
|
RegisterResult commit(std::string_view owner, TransferId transfer_id);
|
|
Status abort(std::string_view owner, TransferId transfer_id);
|
|
size_t disconnect(std::string_view owner);
|
|
|
|
private:
|
|
struct Transfer {
|
|
TransferId id = 0;
|
|
std::string owner;
|
|
uint32_t checksum = 0;
|
|
std::vector<uint8_t> bytes;
|
|
size_t received = 0;
|
|
};
|
|
|
|
Registry ®istry_;
|
|
std::mutex mutex_;
|
|
TransferId next_transfer_id_ = 1;
|
|
std::vector<Transfer> transfers_;
|
|
};
|
|
|
|
/*
|
|
* Parses SDK UI payloads for an owner already fixed by its connection session.
|
|
*/
|
|
class ProtocolBroker {
|
|
public:
|
|
explicit ProtocolBroker(Registry ®istry);
|
|
|
|
void set_snapshot_sink(SnapshotSink sink, void *context);
|
|
WireResponse dispatch(std::string_view session_owner,
|
|
uint16_t command, std::span<const uint8_t> payload);
|
|
Status dispatch_action(Handle handle, std::string_view node_id,
|
|
std::string_view value, ActionEvent &out);
|
|
size_t disconnect(std::string_view session_owner);
|
|
|
|
private:
|
|
void publish_snapshot();
|
|
|
|
Registry ®istry_;
|
|
RegistrationBroker registrations_;
|
|
std::mutex sink_mutex_;
|
|
SnapshotSink snapshot_sink_ = nullptr;
|
|
void *snapshot_context_ = nullptr;
|
|
uint64_t next_action_sequence_ = 1;
|
|
};
|
|
|
|
} // namespace onion::plugin_ui
|