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(&mut self, ctx: &mut impl InitContext<Self>) -> 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
48 Ok(AppState {
49 semaphore: build_connection_semaphore(
50 ctx.app_state::<OutboundNetworkingFactor>().ok(),
51 "mysql",
52 config.max_connections,
53 config.wait_timeout,
54 ),
55 })
56 }
57
58 fn prepare<T: spin_factors::RuntimeFactors>(
59 &self,
60 mut ctx: spin_factors::PrepareContext<T, Self>,
61 ) -> anyhow::Result<Self::InstanceBuilder> {
62 let allowed_hosts = ctx
63 .instance_builder::<OutboundNetworkingFactor>()?
64 .allowed_hosts();
65 let otel = OtelFactorState::from_prepare_context(&mut ctx)?;
66
67 Ok(InstanceState {
68 inner: Arc::new(Mutex::new(InstanceStateInner {
69 allowed_hosts,
70 connections: Default::default(),
71 otel,
72 })),
73 semaphore: ctx.app_state().semaphore.clone(),
74 })
75 }
76}
77
78impl<C> Default for OutboundMysqlFactor<C> {
79 fn default() -> Self {
80 Self {
81 _phantom: Default::default(),
82 }
83 }
84}
85
86impl<C> OutboundMysqlFactor<C> {
87 pub fn new() -> Self {
88 Self::default()
89 }
90}
91
92pub struct InstanceStateInner<C> {
93 allowed_hosts: OutboundAllowedHosts,
94 connections: spin_resource_table::Table<(Arc<Mutex<C>>, ConnectionPermit)>,
95 otel: OtelFactorState,
96}
97
98pub struct InstanceState<C> {
99 pub(crate) inner: Arc<Mutex<InstanceStateInner<C>>>,
100 pub semaphore: ConnectionSemaphore,
101}
102
103impl<C: Send + 'static> SelfInstanceBuilder for InstanceState<C> {}
104
105pub struct MysqlFactorData<C: Client>(OutboundMysqlFactor<C>);
106
107impl<C: Client> spin_core::wasmtime::component::HasData for MysqlFactorData<C> {
108 type Data<'a> = &'a mut InstanceState<C>;
109}
110
111impl<C: Client> spin_core::wasmtime::component::HasData for InstanceState<C> {
112 type Data<'a> = &'a mut InstanceState<C>;
113}