-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdata_source_handle.hpp
More file actions
195 lines (167 loc) · 5.75 KB
/
Copy pathdata_source_handle.hpp
File metadata and controls
195 lines (167 loc) · 5.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/**
* @file data_source_handle.hpp
* @brief RAII wrapper around a single DataSource plugin instance (protocol v4).
*
* Obtained from `DataSourceLibrary::createHandle()`. Owns the plugin context
* and destroys it on scope exit. Move-only; not copyable.
*
* Typical host usage:
* @code
* auto handle = library.createHandle();
* if (auto s = handle.bind(registry.view()); !s) { ... }
* if (auto s = handle.loadConfig(json); !s) { ... }
* if (auto s = handle.start(); !s) { ... }
* while (handle.currentState() == PJ::DataSourceState::kRunning) {
* if (auto s = handle.poll(); !s) { ... }
* }
* handle.stop();
* @endcode
*/
// Copyright 2026 Davide Faconti
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include <cassert>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include "pj_base/data_source_protocol.h"
#include "pj_base/expected.hpp"
#include "pj_base/sdk/data_source_host_views.hpp"
namespace PJ {
/// RAII handle owning a DataSource plugin instance.
class DataSourceHandle {
public:
explicit DataSourceHandle(const PJ_data_source_vtable_t* vt, std::shared_ptr<void> library_owner = {})
: vt_(vt), library_owner_(std::move(library_owner)) {
if (vt_ != nullptr) {
assert(vt_->protocol_version == PJ_DATA_SOURCE_PROTOCOL_VERSION);
ctx_ = vt_->create();
}
}
~DataSourceHandle() {
if (vt_ != nullptr && ctx_ != nullptr) {
vt_->destroy(ctx_);
}
}
DataSourceHandle(DataSourceHandle&& other) noexcept
: vt_(other.vt_), ctx_(other.ctx_), library_owner_(std::move(other.library_owner_)) {
other.vt_ = nullptr;
other.ctx_ = nullptr;
}
DataSourceHandle& operator=(DataSourceHandle&& other) noexcept {
if (this != &other) {
std::swap(vt_, other.vt_);
std::swap(ctx_, other.ctx_);
std::swap(library_owner_, other.library_owner_);
}
return *this;
}
DataSourceHandle(const DataSourceHandle&) = delete;
DataSourceHandle& operator=(const DataSourceHandle&) = delete;
[[nodiscard]] bool valid() const {
return vt_ != nullptr && ctx_ != nullptr;
}
// The shared library token that keeps this plugin's DSO mapped. Capture a copy
// anywhere a callback or payload anchor PRODUCED BY the plugin may outlive this
// handle (e.g. lazy ObjectStore payloads): the .so must not be dlclosed while
// plugin code (a payload anchor's release fn) can still run.
[[nodiscard]] std::shared_ptr<void> libraryOwner() const {
return library_owner_;
}
[[nodiscard]] std::string manifest() const {
return vt_->manifest_json != nullptr ? std::string(vt_->manifest_json) : std::string();
}
[[nodiscard]] uint64_t capabilities() const {
return vt_->capabilities(ctx_);
}
/// Bind host-provided services. Acquired exactly once between create and start.
[[nodiscard]] Status bind(PJ_service_registry_t registry) {
PJ_error_t err{};
if (!vt_->bind(ctx_, registry, &err)) {
return unexpected(errorToString(err));
}
return okStatus();
}
/// Serialize the plugin's config. Writes the JSON into @p out_json on
/// success. The output reference is only touched when the returned
/// Status is ok. Uses an out-parameter rather than `Expected<std::string>`
/// because `PJ::Expected` defaults its error type to `std::string`, which
/// would produce a degenerate `variant<string, string>`.
[[nodiscard]] Status saveConfig(std::string& out_json) {
PJ_string_view_t sv{};
PJ_error_t err{};
if (!vt_->save_config(ctx_, &sv, &err)) {
return unexpected(errorToString(err));
}
out_json.assign(sv.data == nullptr ? "" : sv.data, sv.size);
return okStatus();
}
[[nodiscard]] Status loadConfig(std::string_view config_json) {
PJ_string_view_t sv{config_json.data(), config_json.size()};
PJ_error_t err{};
if (!vt_->load_config(ctx_, sv, &err)) {
return unexpected(errorToString(err));
}
return okStatus();
}
[[nodiscard]] Status start() {
PJ_error_t err{};
if (!vt_->start(ctx_, &err)) {
return unexpected(errorToString(err));
}
return okStatus();
}
void stop() {
vt_->stop(ctx_);
}
[[nodiscard]] Status pause() {
PJ_error_t err{};
if (!vt_->pause(ctx_, &err)) {
return unexpected(errorToString(err));
}
return okStatus();
}
[[nodiscard]] Status resume() {
PJ_error_t err{};
if (!vt_->resume(ctx_, &err)) {
return unexpected(errorToString(err));
}
return okStatus();
}
[[nodiscard]] Status poll() {
PJ_error_t err{};
if (!vt_->poll(ctx_, &err)) {
return unexpected(errorToString(err));
}
return okStatus();
}
[[nodiscard]] DataSourceState currentState() const {
return static_cast<DataSourceState>(vt_->current_state(ctx_));
}
/// Return the typed borrowed-dialog handle. `{nullptr, nullptr}` if no dialog.
[[nodiscard]] PJ_borrowed_dialog_t getDialog() const {
return vt_->get_dialog != nullptr ? vt_->get_dialog(ctx_) : PJ_borrowed_dialog_t{nullptr, nullptr};
}
/// Query a plugin-exposed extension by reverse-DNS id. Tail-slot gated —
/// returns nullptr if the plugin was compiled against an older v4 header that
/// didn't have this slot, or if the plugin doesn't know the id.
[[nodiscard]] const void* getPluginExtension(std::string_view id) const {
if (!PJ_HAS_TAIL_SLOT(PJ_data_source_vtable_t, vt_, get_plugin_extension)) {
return nullptr;
}
PJ_string_view_t sv{id.data(), id.size()};
return vt_->get_plugin_extension(ctx_, sv);
}
[[nodiscard]] const PJ_data_source_vtable_t* vtable() const {
return vt_;
}
[[nodiscard]] void* context() const {
return ctx_;
}
private:
const PJ_data_source_vtable_t* vt_ = nullptr;
void* ctx_ = nullptr;
std::shared_ptr<void> library_owner_;
};
} // namespace PJ