spin_factor_outbound_mysql/
lib.rs1pub mod client;
2mod host;
3pub mod runtime_config;
4
5use std::sync::Arc;
6
7use client::Client;
8use mysql_async::Conn as MysqlClient;
9use runtime_config::RuntimeConfig;
10use spin_factor_otel::OtelFactorState;
11use spin_factor_outbound_networking::{
12 ConnectionPermit, ConnectionSemaphore, OutboundNetworkingFactor, build_connection_semaphore,
13 config::allowed_hosts::OutboundAllowedHosts,
14};
15use spin_factors::{Factor, FactorData, InitContext, RuntimeFactors, SelfInstanceBuilder};
16use spin_world::spin::mysql::mysql as v3;
17use spin_world::v1::mysql as v1;
18use spin_world::v2::mysql as v2;
19use tokio::sync::Mutex;
20
21pub struct OutboundMysqlFactor<C = MysqlClient> {
22 _phantom: std::marker::PhantomData<C>,
23}
24
25pub struct AppState {
26 pub semaphore: ConnectionSemaphore,
28}
29
30impl<C: Send + Sync + Client + 'static> Factor for OutboundMysqlFactor<C> {
31 type RuntimeConfig = RuntimeConfig;
32 type AppState = AppState;
33 type InstanceBuilder = InstanceState<C>;
34
35 fn init<T: InitContext<Self>>(&mut self, ctx: &mut T) -> anyhow::Result<()> {
36 ctx.link_bindings(v1::add_to_linker::<_, FactorData<Self>>)?;
37 ctx.link_bindings(v2::add_to_linker::<_, FactorData<Self>>)?;
38 ctx.link_bindings(v3::add_to_linker::<_, MysqlFactorData<C>>)?;
39 Ok(())
40 }
41
42 fn configure_app<T: RuntimeFactors>(
43 &self,
44 mut ctx: spin_factors::ConfigureAppContext<T, Self>,
45 ) -> anyhow::Result<Self::AppState> {
46 let config = ctx.take_runtime_config().unwrap_or_default();
47 let networking = ctx.app_state::<OutboundNetworkingFactor>().ok();
48
49 Ok(AppState {
50 semaphore: build_connection_semaphore(
51 networking,
52 "mysql",
53 config.max_connections,
54 config.wait_timeout,
55 ),
56 })
57 }
58
59 fn prepare<T: spin_factors::RuntimeFactors>(
60 &self,
61 mut ctx: spin_factors::PrepareContext<T, Self>,
62 ) -> anyhow::Result<Self::InstanceBuilder> {
63 let allowed_hosts = ctx
64 .instance_builder::<OutboundNetworkingFactor>()?
65 .allowed_hosts();
66 let otel = OtelFactorState::from_prepare_context(&mut ctx)?;
67
68 Ok(InstanceState {
69 inner: Arc::new(Mutex::new(InstanceStateInner {
70 allowed_hosts,
71 connections: Default::default(),
72 otel,
73 })),
74 semaphore: ctx.app_state().semaphore.clone(),
75 })
76 }
77}
78
79impl<C> Default for OutboundMysqlFactor<C> {
80 fn default() -> Self {
81 Self {
82 _phantom: Default::default(),
83 }
84 }
85}
86
87impl<C> OutboundMysqlFactor<C> {
88 pub fn new() -> Self {
89 Self::default()
90 }
91}
92
93pub struct InstanceStateInner<C> {
94 allowed_hosts: OutboundAllowedHosts,
95 connections: spin_resource_table::Table<(Arc<Mutex<C>>, ConnectionPermit)>,
96 otel: OtelFactorState,
97}
98
99pub struct InstanceState<C> {
100 pub(crate) inner: Arc<Mutex<InstanceStateInner<C>>>,
101 pub semaphore: ConnectionSemaphore,
102}
103
104impl<C: Send + 'static> SelfInstanceBuilder for InstanceState<C> {}
105
106pub struct MysqlFactorData<C: Client>(OutboundMysqlFactor<C>);
107
108impl<C: Client> spin_core::wasmtime::component::HasData for MysqlFactorData<C> {
109 type Data<'a> = &'a mut InstanceState<C>;
110}
111
112impl<C: Client> spin_core::wasmtime::component::HasData for InstanceState<C> {
113 type Data<'a> = &'a mut InstanceState<C>;
114}