execution_engine_core/
service_registry.rs1use std::collections::HashMap;
5use std::ffi::{c_char, c_void, CStr};
6use std::sync::{Arc, RwLock};
7
8use serde::{Deserialize, Serialize};
9use skylet_abi::{PluginContext, PluginResult};
10
11#[derive(Debug, Deserialize, Serialize)]
13pub struct UserContext {
14 pub roles: Vec<String>,
15 pub permissions: Vec<String>,
16}
17
18impl UserContext {
19 pub fn is_admin(&self) -> bool {
20 self.roles
21 .iter()
22 .any(|r| r == "admin" || r == "Administrator")
23 }
24
25 pub fn has_permission(&self, perm: &str) -> bool {
26 self.permissions.iter().any(|p| p == perm)
27 }
28}
29
30pub struct ServiceRegistry {
32 inner: RwLock<HashMap<String, (*mut c_void, String)>>,
33}
34
35unsafe impl Send for ServiceRegistry {}
39unsafe impl Sync for ServiceRegistry {}
40
41impl Default for ServiceRegistry {
42 fn default() -> Self {
43 Self::new()
44 }
45}
46
47impl ServiceRegistry {
48 pub fn new() -> Self {
49 Self {
50 inner: RwLock::new(HashMap::new()),
51 }
52 }
53
54 pub fn register(&self, name: &str, service: *mut c_void, service_type: &str) -> PluginResult {
55 let mut map = self.inner.write().unwrap();
56 if map.contains_key(name) {
57 return PluginResult::Error;
58 }
59 map.insert(name.to_string(), (service, service_type.to_string()));
60 PluginResult::Success
61 }
62
63 pub fn get(&self, name: &str, service_type: Option<&str>) -> *mut c_void {
64 let map = self.inner.read().unwrap();
65 if let Some((ptr, stored_type)) = map.get(name) {
66 if let Some(req_type) = service_type {
67 if req_type != stored_type.as_str() {
68 return std::ptr::null_mut();
69 }
70 }
71 *ptr
72 } else {
73 std::ptr::null_mut()
74 }
75 }
76
77 pub fn unregister(&self, name: &str) -> PluginResult {
78 let mut map = self.inner.write().unwrap();
79 if map.remove(name).is_some() {
80 PluginResult::Success
81 } else {
82 PluginResult::Error
83 }
84 }
85}
86
87pub struct ServiceRegistryHandle {
90 pub registry: Arc<ServiceRegistry>,
91}
92
93impl ServiceRegistryHandle {
94 pub fn new(registry: Arc<ServiceRegistry>) -> Self {
95 Self { registry }
96 }
97}
98
99#[no_mangle]
105#[allow(clippy::not_unsafe_ptr_arg_deref)]
106pub extern "C" fn core_service_register(
107 context: *const PluginContext,
108 name: *const c_char,
109 service: *mut c_void,
110 service_type: *const c_char,
111) -> PluginResult {
112 if context.is_null() || name.is_null() {
113 return PluginResult::InvalidRequest;
114 }
115
116 unsafe {
117 let user = (*context).user_data as *mut ServiceRegistryHandle;
118 if user.is_null() {
119 return PluginResult::ServiceUnavailable;
120 }
121
122 let handle = &*user;
123
124 let name = match CStr::from_ptr(name).to_str() {
125 Ok(s) => s,
126 Err(_) => return PluginResult::InvalidRequest,
127 };
128
129 let s_type = if service_type.is_null() {
130 ""
131 } else {
132 match CStr::from_ptr(service_type).to_str() {
133 Ok(s) => s,
134 Err(_) => return PluginResult::InvalidRequest,
135 }
136 };
137
138 handle.registry.register(name, service, s_type)
139 }
140}
141
142#[no_mangle]
143#[allow(clippy::not_unsafe_ptr_arg_deref)]
144pub extern "C" fn core_service_get(
145 context: *const PluginContext,
146 name: *const c_char,
147 service_type: *const c_char,
148) -> *mut c_void {
149 if context.is_null() || name.is_null() {
150 return std::ptr::null_mut();
151 }
152
153 unsafe {
154 let user = (*context).user_data as *mut ServiceRegistryHandle;
155 if user.is_null() {
156 return std::ptr::null_mut();
157 }
158 let handle = &*user;
159
160 let name = match CStr::from_ptr(name).to_str() {
161 Ok(s) => s,
162 Err(_) => return std::ptr::null_mut(),
163 };
164
165 let s_type = if service_type.is_null() {
166 None
167 } else {
168 match CStr::from_ptr(service_type).to_str() {
169 Ok(s) => Some(s),
170 Err(_) => return std::ptr::null_mut(),
171 }
172 };
173
174 if !(*context).user_context_json.is_null() {
178 let cstr = CStr::from_ptr((*context).user_context_json);
179 if let Ok(json) = cstr.to_str() {
180 if let Ok(uc) = serde_json::from_str::<UserContext>(json) {
181 if !uc.is_admin() && !uc.has_permission("service_discovery") {
182 return std::ptr::null_mut();
183 }
184 }
185 }
186 }
187
188 handle.registry.get(name, s_type)
189 }
190}
191
192#[no_mangle]
193#[allow(clippy::not_unsafe_ptr_arg_deref)]
194pub extern "C" fn core_service_unregister(
195 context: *const PluginContext,
196 name: *const c_char,
197) -> PluginResult {
198 if context.is_null() || name.is_null() {
199 return PluginResult::InvalidRequest;
200 }
201
202 unsafe {
203 let user = (*context).user_data as *mut ServiceRegistryHandle;
204 if user.is_null() {
205 return PluginResult::ServiceUnavailable;
206 }
207 let handle = &*user;
208
209 let name = match CStr::from_ptr(name).to_str() {
210 Ok(s) => s,
211 Err(_) => return PluginResult::InvalidRequest,
212 };
213
214 if !(*context).user_context_json.is_null() {
216 let cstr = CStr::from_ptr((*context).user_context_json);
217 if let Ok(json) = cstr.to_str() {
218 if let Ok(uc) = serde_json::from_str::<UserContext>(json) {
219 if !uc.is_admin() && !uc.has_permission("service_unregister") {
220 return PluginResult::PermissionDenied;
221 }
222 }
223 }
224 }
225
226 handle.registry.unregister(name)
227 }
228}