载入中...
搜索中...
未找到
EditingExtension.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <atomic>
5#include <mutex>
6#include <unordered_map>
7#include <utility>
8
9namespace eve::editing {
10namespace {} // namespace
11
13 struct Entry {
16 std::shared_ptr<IEditingExtensionProvider> provider;
17 };
18 mutable std::mutex mutex;
19 std::unordered_map<std::string, Entry> entries;
20 std::unordered_map<std::string, std::uint64_t> generations;
21};
22
24
26 std::vector<std::shared_ptr<IEditingExtensionProvider>> providers;
27 {
28 std::scoped_lock lock(impl_->mutex);
29 for (auto& [id, entry] : impl_->entries) providers.push_back(entry.provider);
30 impl_->entries.clear();
31 }
32 for (auto& provider : providers) {
33 provider->beginUnload().ignore("editing extension registry teardown");
34 provider->deactivate();
35 }
36}
37
39 ExtensionDescriptor descriptor, std::shared_ptr<IEditingExtensionProvider> provider) {
40 if (descriptor.id.empty() || descriptor.schemaVersion == 0 || !provider)
41 return eve::editing::failed<ProviderHandle>(
42 Status::Rejected, RuleId("editing.extension.invalid-provider"),
43 "Extension provider requires id, schema version and implementation");
44 {
45 std::scoped_lock lock(impl_->mutex);
46 if (impl_->entries.contains(descriptor.id))
47 return eve::editing::failed<ProviderHandle>(Status::Conflict,
48 RuleId("editing.extension.duplicate-provider"),
49 "Extension provider id is already published");
50 }
51 auto activated = provider->activate();
52 if (!activated.ok())
53 return eve::editing::failed<ProviderHandle>(Status::Failed, RuleId("editing.extension.activation-failed"),
54 "Extension provider activation failed");
56 bool duplicate = false;
57 {
58 std::scoped_lock lock(impl_->mutex);
59 if (impl_->entries.contains(descriptor.id)) {
60 duplicate = true;
61 } else {
62 const std::string providerId = descriptor.id;
63 handle = {providerId, ++impl_->generations[providerId]};
64 impl_->entries.emplace(providerId, Impl::Entry{std::move(descriptor), handle, provider});
65 }
66 }
67 if (duplicate) {
68 provider->deactivate();
69 return eve::editing::failed<ProviderHandle>(Status::Conflict, RuleId("editing.extension.duplicate-provider"),
70 "Extension provider id was concurrently published");
71 }
72 return eve::editing::applied<ProviderHandle>(handle);
73}
74
76 std::scoped_lock lock(impl_->mutex);
77 const auto found = impl_->entries.find(handle.id);
78 if (found == impl_->entries.end()) {
79 const auto generation = impl_->generations.find(handle.id);
80 return eve::editing::failed<ProviderLease>(
81 generation == impl_->generations.end() ? Status::Unsupported : Status::Conflict,
82 RuleId(generation == impl_->generations.end() ? "editing.extension.provider-absent"
83 : "editing.extension.stale-handle"),
84 generation == impl_->generations.end() ? "Editing extension provider is not available"
85 : "Editing extension handle is stale");
86 }
87 if (found->second.handle != handle)
88 return eve::editing::failed<ProviderLease>(Status::Conflict, RuleId("editing.extension.stale-handle"),
89 "Editing extension handle is stale");
90 return eve::editing::applied<ProviderLease>(ProviderLease(handle, found->second.provider));
91}
92
94 std::scoped_lock lock(impl_->mutex);
95 const auto found = impl_->entries.find(id);
96 if (found == impl_->entries.end())
97 return eve::editing::failed<ProviderLease>(Status::Unsupported, RuleId("editing.extension.provider-absent"),
98 "Editing extension provider is not available");
99 return eve::editing::applied<ProviderLease>(ProviderLease(found->second.handle, found->second.provider));
100}
101
103 std::shared_ptr<IEditingExtensionProvider> provider;
104 {
105 std::scoped_lock lock(impl_->mutex);
106 const auto found = impl_->entries.find(handle.id);
107 if (found == impl_->entries.end() || found->second.handle != handle)
108 return eve::editing::failed<void>(Status::Conflict, RuleId("editing.extension.stale-handle"),
109 "Editing extension handle is stale");
110 provider = found->second.provider;
111 }
112 auto stopping = provider->beginUnload();
113 if (!stopping.ok())
114 return eve::editing::failed<void>(Status::Failed, RuleId("editing.extension.unload-rejected"),
115 "Editing extension refused to stop accepting work");
116 {
117 std::scoped_lock lock(impl_->mutex);
118 const auto found = impl_->entries.find(handle.id);
119 if (found == impl_->entries.end() || found->second.handle != handle)
120 return eve::editing::failed<void>(Status::Conflict, RuleId("editing.extension.stale-handle"),
121 "Editing extension handle is stale");
122 impl_->entries.erase(found);
123 }
124 provider->deactivate();
125 return eve::editing::applied<void>();
126}
127
128std::vector<ExtensionDescriptor> ExtensionProviderRegistry::descriptors() const {
129 std::vector<ExtensionDescriptor> result;
130 std::scoped_lock lock(impl_->mutex);
131 for (const auto& [id, entry] : impl_->entries) result.push_back(entry.descriptor);
132 std::sort(result.begin(), result.end(), [](const auto& a, const auto& b) { return a.id < b.id; });
133 return result;
134}
135
136namespace {
137class StaticProvider final : public IEditingExtensionProvider {
138public:
139 StaticProvider(CapabilityId capability, std::shared_ptr<void> implementation)
140 : capability_(std::move(capability)), implementation_(std::move(implementation)) {}
141
142 Result<void> activate() override {
143 accepting_.store(true, std::memory_order_release);
144 return eve::editing::applied<void>();
145 }
146 Result<void> beginUnload() override {
147 accepting_.store(false, std::memory_order_release);
148 return eve::editing::applied<void>();
149 }
150 void deactivate() noexcept override { accepting_.store(false, std::memory_order_release); }
151 void* query(const CapabilityId& capability) noexcept override {
152 return accepting_.load(std::memory_order_acquire) && capability == capability_
153 ? implementation_.get()
154 : nullptr;
155 }
156
157private:
158 CapabilityId capability_;
159 std::shared_ptr<void> implementation_;
160 std::atomic_bool accepting_{false};
161};
162} // namespace
163
166 CapabilityId capability,
167 std::shared_ptr<void> implementation) {
168 if (!implementation)
169 return eve::editing::failed<ProviderHandle>(Status::Rejected, RuleId("editing.extension.null-capability"),
170 "Static editing provider requires an owned capability");
171 if (std::find(descriptor.capabilities.begin(), descriptor.capabilities.end(), capability) ==
172 descriptor.capabilities.end())
173 descriptor.capabilities.push_back(capability);
174 return registry.registerProvider(
175 std::move(descriptor),
176 std::make_shared<StaticProvider>(std::move(capability), std::move(implementation)));
177}
178} // namespace eve::editing
std::string descriptor
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
std::uint32_t generation
PrimitiveHandle handle
bool found
Move-only operation result carrying either a value or Status.
Definition Result.h:155
UUID-backed identifier adapter for legacy textual boundaries.
Definition Identity.h:314
Thread-safe generation-qualified registry for editing extension providers.
Result< ProviderHandle > registerProvider(ExtensionDescriptor descriptor, std::shared_ptr< IEditingExtensionProvider > provider)
Publish and activate a provider atomically from the caller's perspective.
~ExtensionProviderRegistry()
Extension provider registry.
Result< ProviderLease > acquire(const ProviderHandle &handle) const
Acquire an owning lease or return Unsupported/StaleHandle diagnostics.
Result< void > unload(const ProviderHandle &handle)
Stop, unpublish and deactivate the exact provider generation.
std::vector< ExtensionDescriptor > descriptors() const
Return owning copies of current descriptors.
ExtensionProviderRegistry()
Extension provider registry.
IEditingExtensionProvider public API.
ProviderLease public API.
I * query()
Queries .
Definition Capability.h:88
StrongId< RuleIdTag > RuleId
Definition EditingIds.h:60
StrongId< CapabilityIdTag > CapabilityId
Definition EditingIds.h:61
Result< ProviderHandle > registerStaticProvider(ExtensionProviderRegistry &registry, ExtensionDescriptor descriptor, CapabilityId capability, std::shared_ptr< void > implementation)
Register one owned capability behind the standard provider lifecycle.
ExtensionDescriptor public API.
std::shared_ptr< IEditingExtensionProvider > provider
std::unordered_map< std::string, std::uint64_t > generations
std::unordered_map< std::string, Entry > entries
ProviderHandle public API.