1use std::collections::HashMap;
4use std::fmt::{Display, Formatter};
5use std::sync::Arc;
6use std::sync::atomic::{AtomicUsize, Ordering};
7
8use anyhow::anyhow;
9use async_trait::async_trait;
10use prost::Message;
11use serde::{Deserialize, Serialize};
12use serde_json::Value;
13use tonic::codegen::InterceptedService;
14use tonic::metadata::{Ascii, MetadataValue};
15use tonic::service::Interceptor;
16use tonic::transport::Channel;
17use tonic::{Request, Status};
18use tracing::{debug, trace};
19
20use crate::child_process::ChildPluginProcess;
21use crate::proto::pact_plugin_client::PactPluginClient as PactPluginClientV1;
22use crate::proto::*;
23use crate::proto_v2::{self, pact_plugin_client::PactPluginClient as PactPluginClientV2};
24
25#[derive(Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Debug, Hash)]
27pub enum PluginDependencyType {
28 OSPackage,
30 Plugin,
32 Library,
34 Executable,
36}
37
38impl Default for PluginDependencyType {
39 fn default() -> Self {
40 PluginDependencyType::Plugin
41 }
42}
43
44#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug, Hash)]
46#[serde(rename_all = "camelCase")]
47pub struct PluginDependency {
48 pub name: String,
50 pub version: Option<String>,
52 #[serde(default)]
54 pub dependency_type: PluginDependencyType,
55}
56
57impl Display for PluginDependency {
58 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
59 if let Some(version) = &self.version {
60 write!(f, "{}:{}", self.name, version)
61 } else {
62 write!(f, "{}:*", self.name)
63 }
64 }
65}
66
67#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
69#[serde(rename_all = "camelCase")]
70pub struct PactPluginManifest {
71 #[serde(skip)]
73 pub plugin_dir: String,
74
75 pub plugin_interface_version: u8,
77
78 pub name: String,
80
81 pub version: String,
83
84 pub executable_type: String,
86
87 pub minimum_required_version: Option<String>,
89
90 pub entry_point: String,
92
93 #[serde(default)]
95 pub entry_points: HashMap<String, String>,
96
97 pub args: Option<Vec<String>>,
99
100 pub dependencies: Option<Vec<PluginDependency>>,
102
103 #[serde(default)]
105 pub plugin_config: HashMap<String, Value>,
106}
107
108impl PactPluginManifest {
109 pub fn as_dependency(&self) -> PluginDependency {
110 PluginDependency {
111 name: self.name.clone(),
112 version: Some(self.version.clone()),
113 dependency_type: PluginDependencyType::Plugin,
114 }
115 }
116}
117
118impl Default for PactPluginManifest {
119 fn default() -> Self {
120 PactPluginManifest {
121 plugin_dir: "".to_string(),
122 plugin_interface_version: 1,
123 name: "".to_string(),
124 version: "".to_string(),
125 executable_type: "".to_string(),
126 minimum_required_version: None,
127 entry_point: "".to_string(),
128 entry_points: Default::default(),
129 args: None,
130 dependencies: None,
131 plugin_config: Default::default(),
132 }
133 }
134}
135
136#[derive(Clone, Copy, Debug, PartialEq, Eq)]
137pub enum PluginInterfaceVersion {
138 V1,
139 V2,
140}
141
142#[derive(Clone, Debug, PartialEq, Eq)]
143pub struct PluginInitRequest {
144 pub implementation: String,
145 pub version: String,
146 pub host_capabilities: Vec<String>,
147}
148
149#[derive(Clone, Debug, PartialEq)]
150pub struct PluginInitResponse {
151 pub catalogue: Vec<CatalogueEntry>,
152 pub plugin_capabilities: Vec<String>,
153}
154
155impl TryFrom<u8> for PluginInterfaceVersion {
156 type Error = anyhow::Error;
157
158 fn try_from(value: u8) -> Result<Self, Self::Error> {
159 match value {
160 1 => Ok(PluginInterfaceVersion::V1),
161 2 => Ok(PluginInterfaceVersion::V2),
162 _ => Err(anyhow!("Unsupported plugin interface version {}", value)),
163 }
164 }
165}
166
167enum PluginClient {
168 V1(PactPluginClientV1<InterceptedService<Channel, PactPluginInterceptor>>),
169 V2(PactPluginClientV2<InterceptedService<Channel, PactPluginInterceptor>>),
170}
171
172impl PluginClient {
173 fn convert_message<T, U>(message: T) -> Result<U, Status>
174 where
175 T: Message,
176 U: Message + Default,
177 {
178 U::decode(message.encode_to_vec().as_slice()).map_err(|err| {
179 Status::internal(format!(
180 "Failed to convert between plugin interface message versions: {}",
181 err
182 ))
183 })
184 }
185
186 async fn init_plugin(
187 &mut self,
188 request: PluginInitRequest,
189 ) -> Result<PluginInitResponse, Status> {
190 match self {
191 PluginClient::V1(client) => client
192 .init_plugin(Request::new(InitPluginRequest {
193 implementation: request.implementation,
194 version: request.version,
195 }))
196 .await
197 .map(|response| PluginInitResponse {
198 catalogue: response.into_inner().catalogue,
199 plugin_capabilities: vec![],
200 }),
201 PluginClient::V2(client) => client
202 .init_plugin(Request::new(proto_v2::InitPluginRequest {
203 implementation: request.implementation,
204 version: request.version,
205 host_capabilities: request.host_capabilities,
206 }))
207 .await
208 .and_then(|response| match response.into_inner().response {
209 Some(proto_v2::init_plugin_response::Response::Success(success)) => {
210 Ok(PluginInitResponse {
211 catalogue: success
212 .catalogue
213 .into_iter()
214 .map(Self::convert_message)
215 .collect::<Result<Vec<CatalogueEntry>, Status>>()?,
216 plugin_capabilities: success.plugin_capabilities,
217 })
218 }
219 Some(proto_v2::init_plugin_response::Response::Failure(failure)) => {
220 let mut error = failure.error;
221 if !failure.missing_host_capabilities.is_empty() {
222 error.push_str(" (missing host capabilities: ");
223 error.push_str(failure.missing_host_capabilities.join(", ").as_str());
224 error.push(')');
225 }
226 Err(Status::failed_precondition(error))
227 }
228 None => Err(Status::internal(
229 "Plugin returned an invalid V2 InitPlugin response",
230 )),
231 }),
232 }
233 }
234
235 async fn compare_contents(
236 &mut self,
237 request: CompareContentsRequest,
238 ) -> Result<CompareContentsResponse, Status> {
239 match self {
240 PluginClient::V1(client) => client
241 .compare_contents(Request::new(request))
242 .await
243 .map(|response| response.into_inner()),
244 PluginClient::V2(client) => client
245 .compare_contents(Request::new(Self::convert_message::<
246 _,
247 proto_v2::CompareContentsRequest,
248 >(request)?))
249 .await
250 .and_then(|response| Self::convert_message(response.into_inner())),
251 }
252 }
253
254 async fn configure_interaction(
255 &mut self,
256 request: ConfigureInteractionRequest,
257 ) -> Result<ConfigureInteractionResponse, Status> {
258 match self {
259 PluginClient::V1(client) => client
260 .configure_interaction(Request::new(request))
261 .await
262 .map(|response| response.into_inner()),
263 PluginClient::V2(client) => client
264 .configure_interaction(Request::new(Self::convert_message::<
265 _,
266 proto_v2::ConfigureInteractionRequest,
267 >(request)?))
268 .await
269 .and_then(|response| Self::convert_message(response.into_inner())),
270 }
271 }
272
273 async fn generate_content(
274 &mut self,
275 request: GenerateContentRequest,
276 ) -> Result<GenerateContentResponse, Status> {
277 match self {
278 PluginClient::V1(client) => client
279 .generate_content(Request::new(request))
280 .await
281 .map(|response| response.into_inner()),
282 PluginClient::V2(client) => client
283 .generate_content(Request::new(Self::convert_message::<
284 _,
285 proto_v2::GenerateContentRequest,
286 >(request)?))
287 .await
288 .and_then(|response| Self::convert_message(response.into_inner())),
289 }
290 }
291
292 async fn start_mock_server(
293 &mut self,
294 request: StartMockServerRequest,
295 ) -> Result<StartMockServerResponse, Status> {
296 match self {
297 PluginClient::V1(client) => client
298 .start_mock_server(Request::new(request))
299 .await
300 .map(|response| response.into_inner()),
301 PluginClient::V2(client) => client
302 .start_mock_server(Request::new(Self::convert_message::<
303 _,
304 proto_v2::StartMockServerRequest,
305 >(request)?))
306 .await
307 .and_then(|response| Self::convert_message(response.into_inner())),
308 }
309 }
310
311 async fn shutdown_mock_server(
312 &mut self,
313 request: ShutdownMockServerRequest,
314 ) -> Result<ShutdownMockServerResponse, Status> {
315 match self {
316 PluginClient::V1(client) => client
317 .shutdown_mock_server(Request::new(request))
318 .await
319 .map(|response| response.into_inner()),
320 PluginClient::V2(client) => client
321 .shutdown_mock_server(Request::new(Self::convert_message::<
322 _,
323 proto_v2::ShutdownMockServerRequest,
324 >(request)?))
325 .await
326 .and_then(|response| Self::convert_message(response.into_inner())),
327 }
328 }
329
330 async fn get_mock_server_results(
331 &mut self,
332 request: MockServerRequest,
333 ) -> Result<MockServerResults, Status> {
334 match self {
335 PluginClient::V1(client) => client
336 .get_mock_server_results(Request::new(request))
337 .await
338 .map(|response| response.into_inner()),
339 PluginClient::V2(client) => client
340 .get_mock_server_results(Request::new(Self::convert_message::<
341 _,
342 proto_v2::MockServerRequest,
343 >(request)?))
344 .await
345 .and_then(|response| Self::convert_message(response.into_inner())),
346 }
347 }
348
349 async fn prepare_interaction_for_verification(
350 &mut self,
351 request: VerificationPreparationRequest,
352 ) -> Result<VerificationPreparationResponse, Status> {
353 match self {
354 PluginClient::V1(client) => client
355 .prepare_interaction_for_verification(Request::new(request))
356 .await
357 .map(|response| response.into_inner()),
358 PluginClient::V2(client) => client
359 .prepare_interaction_for_verification(Request::new(Self::convert_message::<
360 _,
361 proto_v2::VerificationPreparationRequest,
362 >(request)?))
363 .await
364 .and_then(|response| Self::convert_message(response.into_inner())),
365 }
366 }
367
368 async fn verify_interaction(
369 &mut self,
370 request: VerifyInteractionRequest,
371 ) -> Result<VerifyInteractionResponse, Status> {
372 match self {
373 PluginClient::V1(client) => client
374 .verify_interaction(Request::new(request))
375 .await
376 .map(|response| response.into_inner()),
377 PluginClient::V2(client) => client
378 .verify_interaction(Request::new(Self::convert_message::<
379 _,
380 proto_v2::VerifyInteractionRequest,
381 >(request)?))
382 .await
383 .and_then(|response| Self::convert_message(response.into_inner())),
384 }
385 }
386
387 async fn update_catalogue(&mut self, request: Catalogue) -> Result<(), Status> {
388 match self {
389 PluginClient::V1(client) => client
390 .update_catalogue(Request::new(request))
391 .await
392 .map(|_| ()),
393 PluginClient::V2(client) => client
394 .update_catalogue(Request::new(
395 Self::convert_message::<_, proto_v2::Catalogue>(request)?,
396 ))
397 .await
398 .map(|_| ()),
399 }
400 }
401}
402
403#[async_trait]
405pub trait PactPluginRpc {
406 async fn init_plugin(&mut self, request: PluginInitRequest)
408 -> anyhow::Result<PluginInitResponse>;
409
410 async fn compare_contents(
412 &self,
413 request: CompareContentsRequest,
414 ) -> anyhow::Result<CompareContentsResponse>;
415
416 async fn configure_interaction(
418 &self,
419 request: ConfigureInteractionRequest,
420 ) -> anyhow::Result<ConfigureInteractionResponse>;
421
422 async fn generate_content(
424 &self,
425 request: GenerateContentRequest,
426 ) -> anyhow::Result<GenerateContentResponse>;
427
428 async fn start_mock_server(
430 &self,
431 request: StartMockServerRequest,
432 ) -> anyhow::Result<StartMockServerResponse>;
433
434 async fn shutdown_mock_server(
436 &self,
437 request: ShutdownMockServerRequest,
438 ) -> anyhow::Result<ShutdownMockServerResponse>;
439
440 async fn get_mock_server_results(
442 &self,
443 request: MockServerRequest,
444 ) -> anyhow::Result<MockServerResults>;
445
446 async fn prepare_interaction_for_verification(
449 &self,
450 request: VerificationPreparationRequest,
451 ) -> anyhow::Result<VerificationPreparationResponse>;
452
453 async fn verify_interaction(
455 &self,
456 request: VerifyInteractionRequest,
457 ) -> anyhow::Result<VerifyInteractionResponse>;
458
459 async fn update_catalogue(&self, request: Catalogue) -> anyhow::Result<()>;
461}
462
463#[derive(Debug, Clone)]
465pub struct PactPlugin {
466 pub manifest: PactPluginManifest,
468
469 pub interface_version: PluginInterfaceVersion,
471
472 pub child: Arc<ChildPluginProcess>,
474
475 pub plugin_capabilities: Vec<String>,
477
478 access_count: Arc<AtomicUsize>,
480}
481
482#[async_trait]
483impl PactPluginRpc for PactPlugin {
484 async fn init_plugin(
486 &mut self,
487 request: PluginInitRequest,
488 ) -> anyhow::Result<PluginInitResponse> {
489 let mut client = self.get_plugin_client().await?;
490 client
491 .init_plugin(request)
492 .await
493 .map_err(anyhow::Error::from)
494 }
495
496 async fn compare_contents(
498 &self,
499 request: CompareContentsRequest,
500 ) -> anyhow::Result<CompareContentsResponse> {
501 let mut client = self.get_plugin_client().await?;
502 client
503 .compare_contents(request)
504 .await
505 .map_err(anyhow::Error::from)
506 }
507
508 async fn configure_interaction(
510 &self,
511 request: ConfigureInteractionRequest,
512 ) -> anyhow::Result<ConfigureInteractionResponse> {
513 let mut client = self.get_plugin_client().await?;
514 client
515 .configure_interaction(request)
516 .await
517 .map_err(anyhow::Error::from)
518 }
519
520 async fn generate_content(
522 &self,
523 request: GenerateContentRequest,
524 ) -> anyhow::Result<GenerateContentResponse> {
525 let mut client = self.get_plugin_client().await?;
526 client
527 .generate_content(request)
528 .await
529 .map_err(anyhow::Error::from)
530 }
531
532 async fn start_mock_server(
533 &self,
534 request: StartMockServerRequest,
535 ) -> anyhow::Result<StartMockServerResponse> {
536 let mut client = self.get_plugin_client().await?;
537 client
538 .start_mock_server(request)
539 .await
540 .map_err(anyhow::Error::from)
541 }
542
543 async fn shutdown_mock_server(
544 &self,
545 request: ShutdownMockServerRequest,
546 ) -> anyhow::Result<ShutdownMockServerResponse> {
547 let mut client = self.get_plugin_client().await?;
548 client
549 .shutdown_mock_server(request)
550 .await
551 .map_err(anyhow::Error::from)
552 }
553
554 async fn get_mock_server_results(
555 &self,
556 request: MockServerRequest,
557 ) -> anyhow::Result<MockServerResults> {
558 let mut client = self.get_plugin_client().await?;
559 client
560 .get_mock_server_results(request)
561 .await
562 .map_err(anyhow::Error::from)
563 }
564
565 async fn prepare_interaction_for_verification(
566 &self,
567 request: VerificationPreparationRequest,
568 ) -> anyhow::Result<VerificationPreparationResponse> {
569 let mut client = self.get_plugin_client().await?;
570 client
571 .prepare_interaction_for_verification(request)
572 .await
573 .map_err(anyhow::Error::from)
574 }
575
576 async fn verify_interaction(
577 &self,
578 request: VerifyInteractionRequest,
579 ) -> anyhow::Result<VerifyInteractionResponse> {
580 let mut client = self.get_plugin_client().await?;
581 client
582 .verify_interaction(request)
583 .await
584 .map_err(anyhow::Error::from)
585 }
586
587 async fn update_catalogue(&self, request: Catalogue) -> anyhow::Result<()> {
588 let mut client = self.get_plugin_client().await?;
589 client
590 .update_catalogue(request)
591 .await
592 .map_err(anyhow::Error::from)
593 }
594}
595
596impl PactPlugin {
597 pub fn new(manifest: &PactPluginManifest, child: ChildPluginProcess) -> anyhow::Result<Self> {
599 Ok(PactPlugin {
600 manifest: manifest.clone(),
601 interface_version: PluginInterfaceVersion::try_from(manifest.plugin_interface_version)?,
602 child: Arc::new(child),
603 plugin_capabilities: vec![],
604 access_count: Arc::new(AtomicUsize::new(1)),
605 })
606 }
607
608 pub fn has_plugin_capability(&self, capability: &str) -> bool {
609 self.plugin_capabilities.iter().any(|value| value == capability)
610 }
611
612 pub fn port(&self) -> u16 {
614 self.child.port()
615 }
616
617 pub fn kill(&self) {
619 self.child.kill();
620 }
621
622 pub fn update_access(&mut self) {
624 let count = self.access_count.fetch_add(1, Ordering::SeqCst);
625 trace!(
626 "update_access: Plugin {}/{} access is now {}",
627 self.manifest.name,
628 self.manifest.version,
629 count + 1
630 );
631 }
632
633 pub fn drop_access(&mut self) -> usize {
635 let check = self
636 .access_count
637 .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |count| {
638 if count > 0 { Some(count - 1) } else { None }
639 });
640 let count = if let Ok(v) = check {
641 if v > 0 { v - 1 } else { v }
642 } else {
643 0
644 };
645 trace!(
646 "drop_access: Plugin {}/{} access is now {}",
647 self.manifest.name, self.manifest.version, count
648 );
649 count
650 }
651
652 async fn connect_channel(&self) -> anyhow::Result<Channel> {
653 let port = self.child.port();
654 match Channel::from_shared(format!("http://[::1]:{}", port))?
655 .connect()
656 .await
657 {
658 Ok(channel) => Ok(channel),
659 Err(err) => {
660 debug!("IP6 connection failed, will try IP4 address - {err}");
661 Channel::from_shared(format!("http://127.0.0.1:{}", port))?
662 .connect()
663 .await
664 .map_err(|err| anyhow!(err))
665 }
666 }
667 }
668
669 async fn get_plugin_client(&self) -> anyhow::Result<PluginClient> {
670 let channel = self.connect_channel().await?;
671 let interceptor = PactPluginInterceptor::new(self.child.plugin_info.server_key.as_str())?;
672 match self.interface_version {
673 PluginInterfaceVersion::V1 => Ok(PluginClient::V1(PactPluginClientV1::with_interceptor(
674 channel,
675 interceptor,
676 ))),
677 PluginInterfaceVersion::V2 => Ok(PluginClient::V2(PactPluginClientV2::with_interceptor(
678 channel,
679 interceptor,
680 ))),
681 }
682 }
683}
684
685#[derive(Clone, Debug)]
687struct PactPluginInterceptor {
688 server_key: MetadataValue<Ascii>,
690}
691
692impl PactPluginInterceptor {
693 fn new(server_key: &str) -> anyhow::Result<Self> {
694 let token = MetadataValue::try_from(server_key)?;
695 Ok(PactPluginInterceptor { server_key: token })
696 }
697}
698
699impl Interceptor for PactPluginInterceptor {
700 fn call(&mut self, mut request: Request<()>) -> Result<Request<()>, Status> {
701 request
702 .metadata_mut()
703 .insert("authorization", self.server_key.clone());
704 Ok(request)
705 }
706}
707
708#[derive(Clone, Debug, PartialEq)]
710pub struct PluginInteractionConfig {
711 pub pact_configuration: HashMap<String, Value>,
713 pub interaction_configuration: HashMap<String, Value>,
715}
716
717#[cfg(test)]
718pub(crate) mod tests {
719 use std::collections::HashMap;
720 use std::sync::RwLock;
721
722 use async_trait::async_trait;
723 use tonic::Status;
724
725 use crate::plugin_models::{
726 PactPluginRpc, PluginClient, PluginInitRequest, PluginInitResponse,
727 };
728 use crate::proto::verification_preparation_response::Response;
729 use crate::proto::*;
730 use crate::proto_v2;
731
732 pub(crate) struct MockPlugin {
733 pub prepare_request: RwLock<VerificationPreparationRequest>,
734 pub verify_request: RwLock<VerifyInteractionRequest>,
735 }
736
737 impl Default for MockPlugin {
738 fn default() -> Self {
739 MockPlugin {
740 prepare_request: RwLock::new(VerificationPreparationRequest::default()),
741 verify_request: RwLock::new(VerifyInteractionRequest::default()),
742 }
743 }
744 }
745
746 #[test]
747 fn converts_between_v1_and_v2_messages() {
748 let request = PluginInitRequest {
749 implementation: "plugin-driver-rust".to_string(),
750 version: "1.0.0-beta.1".to_string(),
751 host_capabilities: vec!["interaction/request-response".to_string()],
752 };
753
754 let converted_request = proto_v2::InitPluginRequest {
755 implementation: request.implementation,
756 version: request.version,
757 host_capabilities: request.host_capabilities,
758 };
759 assert_eq!(converted_request.implementation, "plugin-driver-rust");
760 assert_eq!(converted_request.version, "1.0.0-beta.1");
761 assert_eq!(
762 converted_request.host_capabilities,
763 vec!["interaction/request-response"]
764 );
765
766 let response = proto_v2::InitPluginResponse {
767 response: Some(proto_v2::init_plugin_response::Response::Success(
768 proto_v2::InitPluginSuccess {
769 catalogue: vec![proto_v2::CatalogueEntry {
770 r#type: proto_v2::catalogue_entry::EntryType::ContentMatcher as i32,
771 key: "test".to_string(),
772 values: HashMap::new(),
773 }],
774 plugin_capabilities: vec!["plugin/verification".to_string()],
775 },
776 )),
777 };
778
779 let converted_response = match response.response.unwrap() {
780 proto_v2::init_plugin_response::Response::Success(success) => PluginInitResponse {
781 catalogue: success
782 .catalogue
783 .into_iter()
784 .map(PluginClient::convert_message)
785 .collect::<Result<Vec<CatalogueEntry>, Status>>()
786 .unwrap(),
787 plugin_capabilities: success.plugin_capabilities,
788 },
789 _ => unreachable!(),
790 };
791 assert_eq!(converted_response.catalogue.len(), 1);
792 assert_eq!(converted_response.catalogue[0].key, "test");
793 assert_eq!(
794 converted_response.catalogue[0].r#type,
795 catalogue_entry::EntryType::ContentMatcher as i32
796 );
797 assert_eq!(converted_response.plugin_capabilities, vec!["plugin/verification"]);
798 }
799
800 #[async_trait]
801 impl PactPluginRpc for MockPlugin {
802 async fn init_plugin(
803 &mut self,
804 _request: PluginInitRequest,
805 ) -> anyhow::Result<PluginInitResponse> {
806 unimplemented!()
807 }
808
809 async fn compare_contents(
810 &self,
811 _request: CompareContentsRequest,
812 ) -> anyhow::Result<CompareContentsResponse> {
813 unimplemented!()
814 }
815
816 async fn configure_interaction(
817 &self,
818 _request: ConfigureInteractionRequest,
819 ) -> anyhow::Result<ConfigureInteractionResponse> {
820 unimplemented!()
821 }
822
823 async fn generate_content(
824 &self,
825 _request: GenerateContentRequest,
826 ) -> anyhow::Result<GenerateContentResponse> {
827 unimplemented!()
828 }
829
830 async fn start_mock_server(
831 &self,
832 _request: StartMockServerRequest,
833 ) -> anyhow::Result<StartMockServerResponse> {
834 unimplemented!()
835 }
836
837 async fn shutdown_mock_server(
838 &self,
839 _request: ShutdownMockServerRequest,
840 ) -> anyhow::Result<ShutdownMockServerResponse> {
841 unimplemented!()
842 }
843
844 async fn get_mock_server_results(
845 &self,
846 _request: MockServerRequest,
847 ) -> anyhow::Result<MockServerResults> {
848 unimplemented!()
849 }
850
851 async fn prepare_interaction_for_verification(
852 &self,
853 request: VerificationPreparationRequest,
854 ) -> anyhow::Result<VerificationPreparationResponse> {
855 let mut w = self.prepare_request.write().unwrap();
856 *w = request;
857 let data = InteractionData {
858 body: None,
859 metadata: Default::default(),
860 };
861 Ok(VerificationPreparationResponse {
862 response: Some(Response::InteractionData(data)),
863 })
864 }
865
866 async fn verify_interaction(
867 &self,
868 request: VerifyInteractionRequest,
869 ) -> anyhow::Result<VerifyInteractionResponse> {
870 let mut w = self.verify_request.write().unwrap();
871 *w = request;
872 let result = VerificationResult {
873 success: false,
874 response_data: None,
875 mismatches: vec![],
876 output: vec![],
877 };
878 Ok(VerifyInteractionResponse {
879 response: Some(verify_interaction_response::Response::Result(result)),
880 })
881 }
882
883 async fn update_catalogue(&self, _request: Catalogue) -> anyhow::Result<()> {
884 unimplemented!()
885 }
886 }
887}