rpkl_jdx/api/
external_reader.rs1use std::io::Write;
2
3use crate::internal::msgapi::{
4 codes::{
5 CLOSE_EXTERNAL_PROCESS, INITIALIZE_MODULE_READER_REQUEST,
6 INITIALIZE_RESOURCE_READER_REQUEST, LIST_MODULES_REQUEST, LIST_RESOURCES_REQUEST,
7 READ_MODULE_REQUEST, READ_RESOURCE_REQUEST,
8 },
9 incoming::PklServerMessage,
10 outgoing::{
11 ClientModuleReader, ClientResourceReader, InitializeModuleReaderResponse,
12 InitializeResourceReaderResponse,
13 },
14 PklMessage,
15};
16
17use crate::{
18 api::{
19 evaluator::recv_msg,
20 reader::{
21 handle_list_modules, handle_list_resources, handle_read_module, handle_read_resource,
22 },
23 },
24 utils::macros::{_info, _warn},
25};
26
27pub struct ExternalReaderRuntime {
28 resource_readers: Vec<Box<dyn PklResourceReader>>,
29 module_readers: Vec<Box<dyn PklModuleReader>>,
30}
31
32impl ExternalReaderRuntime {
33 pub fn new() -> Self {
34 Self {
35 resource_readers: Vec::new(),
36 module_readers: Vec::new(),
37 }
38 }
39
40 pub fn add_resource_readers<T: IntoResourceReaders>(&mut self, readers: T) -> &mut Self {
44 let readers = readers.into_readers();
45 self.resource_readers.extend(readers);
46
47 for (i, reader) in self.resource_readers.iter().enumerate() {
48 for other in &self.resource_readers[i + 1..] {
49 if reader.scheme() == other.scheme() {
50 panic!(
51 "Multiple resource readers sharing the same scheme: {}",
52 reader.scheme()
53 );
54 }
55 }
56 }
57
58 self
59 }
60
61 pub fn add_module_readers<T: IntoModuleReaders>(&mut self, readers: T) -> &mut Self {
62 let readers = readers.into_readers();
63 self.module_readers.extend(readers);
64
65 for (i, reader) in self.module_readers.iter().enumerate() {
66 for other in &self.module_readers[i + 1..] {
67 if reader.scheme() == other.scheme() {
68 panic!(
69 "Multiple resource readers sharing the same scheme: {}",
70 reader.scheme()
71 );
72 }
73 }
74 }
75
76 self
77 }
78
79 fn handle_initalize_resource_reader<W: Write>(
80 &self,
81 pkl_msg: &PklServerMessage,
82 out: &mut W,
83 ) -> Result<(), Box<dyn std::error::Error>> {
84 debug_assert!(pkl_msg.header == INITIALIZE_RESOURCE_READER_REQUEST);
85
86 let map = pkl_msg.response.as_map().unwrap();
87 let request_id = map.get(0).unwrap().1.as_i64().unwrap();
88 let scheme = map.get(1).unwrap().1.as_str().unwrap();
89
90 let Some(reader) = self.resource_readers.iter().find(|r| r.scheme() == scheme) else {
92 _warn!("Incompatible scheme: {:?}", scheme);
93
94 let serialized = InitializeResourceReaderResponse {
95 request_id,
96 spec: None,
97 }
98 .encode_msg()?;
99
100 out.write_all(&serialized)?;
101 out.flush()?;
102
103 return Ok(());
104 };
105
106 let serialized = InitializeResourceReaderResponse {
107 request_id,
108 spec: Some(ClientResourceReader {
109 scheme: scheme.to_owned(),
110 has_hierarchical_uris: reader.has_hierarchical_uris(),
111 is_globbable: reader.is_globbable(),
112 }),
113 }
114 .encode_msg()?;
115
116 out.write_all(&serialized)?;
117 out.flush()?;
118
119 Ok(())
120 }
121
122 fn handle_initalize_module_reader<W: Write>(
123 &self,
124 pkl_msg: &PklServerMessage,
125 out: &mut W,
126 ) -> Result<(), Box<dyn std::error::Error>> {
127 debug_assert!(pkl_msg.header == INITIALIZE_MODULE_READER_REQUEST);
128
129 let map = pkl_msg.response.as_map().unwrap();
130 let request_id = map.get(0).unwrap().1.as_i64().unwrap();
131 let scheme = map.get(1).unwrap().1.as_str().unwrap();
132
133 let Some(reader) = self.module_readers.iter().find(|r| r.scheme() == scheme) else {
135 _warn!("Incompatible scheme: {:?}", scheme);
136
137 let serialized = InitializeModuleReaderResponse {
138 request_id,
139 spec: None,
140 }
141 .encode_msg()?;
142
143 out.write_all(&serialized)?;
144 out.flush()?;
145
146 return Ok(());
147 };
148
149 let serialized = InitializeModuleReaderResponse {
150 request_id,
151 spec: Some(ClientModuleReader {
152 scheme: scheme.to_owned(),
153 has_hierarchical_uris: reader.has_hierarchical_uris(),
154 is_globbable: reader.is_globbable(),
155 is_local: reader.is_local(),
156 }),
157 }
158 .encode_msg()?;
159
160 out.write_all(&serialized)?;
161 out.flush()?;
162
163 Ok(())
164 }
165
166 pub fn run(&self) -> Result<(), Box<dyn std::error::Error>> {
167 let mut stdin = std::io::stdin().lock();
168 let mut stdout = std::io::stdout().lock();
169
170 for _reader in self.resource_readers.iter() {
171 _info!("Registered resource reader: {:?}", _reader.scheme());
172 }
173
174 for _reader in self.module_readers.iter() {
175 _info!("Registered module reader: {:?}", _reader.scheme());
176 }
177
178 loop {
179 let Ok(pkl_msg) = recv_msg(&mut stdin) else {
180 _warn!("Failed to decode message");
181 break;
182 };
183
184 match pkl_msg.header {
185 INITIALIZE_RESOURCE_READER_REQUEST => {
186 self.handle_initalize_resource_reader(&pkl_msg, &mut stdout)?;
187 }
188 INITIALIZE_MODULE_READER_REQUEST => {
189 self.handle_initalize_module_reader(&pkl_msg, &mut stdout)?;
190 }
191 LIST_RESOURCES_REQUEST => {
192 handle_list_resources(&self.resource_readers, &pkl_msg, &mut stdout)?;
193 }
194 LIST_MODULES_REQUEST => {
195 handle_list_modules(&self.module_readers, &pkl_msg, &mut stdout)?;
196 }
197 READ_RESOURCE_REQUEST => {
198 handle_read_resource(&self.resource_readers, &pkl_msg, &mut stdout)?;
199 }
200 READ_MODULE_REQUEST => {
201 handle_read_module(&self.module_readers, &pkl_msg, &mut stdout)?;
202 }
203 CLOSE_EXTERNAL_PROCESS => {
204 _info!("CLOSE_EXTERNAL_PROCESS received");
205 break;
206 }
207 _ => {
208 _warn!("unexpected message type: {:x}", pkl_msg.header);
209 }
210 }
211 }
212
213 Ok(())
214 }
215}
216
217pub use crate::api::reader::{PklModuleReader, PklResourceReader};
218pub use crate::internal::msgapi::outgoing::PathElements;
219
220use super::reader::{IntoModuleReaders, IntoResourceReaders};