retrom_grpc_service/
lib.rs1use axum::Router;
2use diesel_async::pooled_connection::AsyncDieselConnectionManager;
3use emulators::EmulatorServiceHandlers;
4use file_explorer::FileExplorerServiceHandlers;
5use games::GameServiceHandlers;
6use http::HeaderName;
7use jobs::{job_manager::JobManager, JobServiceHandlers};
8use library::LibraryServiceHandlers;
9use metadata::MetadataServiceHandlers;
10use platforms::PlatformServiceHandlers;
11use retrom_codegen::retrom::{
12 client_service_server::ClientServiceServer, emulator_service_server::EmulatorServiceServer,
13 file_explorer_service_server::FileExplorerServiceServer,
14 game_service_server::GameServiceServer, job_service_server::JobServiceServer,
15 library_service_server::LibraryServiceServer, metadata_service_server::MetadataServiceServer,
16 platform_service_server::PlatformServiceServer, saves_service_server::SavesServiceServer,
17 server_service_server::ServerServiceServer, FILE_DESCRIPTOR_SET,
18};
19use retrom_service_common::{
20 config::ServerConfigManager,
21 media_cache::MediaCache,
22 metadata_providers::{igdb::provider::IGDBProvider, steam::provider::SteamWebApiProvider},
23 retrom_dirs::RetromDirs,
24};
25use retrom_telemetry::grpc::{GrpcOnRequestSpan, GrpcOnResponseSpanHandler};
26use saves::SavesServiceHandlers;
27use std::{sync::Arc, time::Duration};
28use tower_http::cors::{AllowOrigin, CorsLayer};
29
30pub mod clients;
31pub mod emulators;
32pub mod file_explorer;
33pub mod games;
34pub mod jobs;
35pub mod library;
36pub mod metadata;
37pub mod platforms;
38mod saves;
39pub mod server;
40
41const DEFAULT_MAX_AGE: Duration = Duration::from_secs(24 * 60 * 60);
42const DEFAULT_EXPOSED_HEADERS: [HeaderName; 3] = [
43 HeaderName::from_static("grpc-status"),
44 HeaderName::from_static("grpc-message"),
45 HeaderName::from_static("grpc-status-details-bin"),
46];
47
48const DEFAULT_ALLOW_HEADERS: [HeaderName; 7] = [
49 HeaderName::from_static("x-grpc-web"),
50 http::header::CONTENT_TYPE,
51 HeaderName::from_static("x-user-agent"),
52 HeaderName::from_static("grpc-timeout"),
53 HeaderName::from_static("x-client-id"),
54 HeaderName::from_static("traceparent"),
55 HeaderName::from_static("tracestate"),
56];
57
58pub fn grpc_service(db_url: &str, config_manager: Arc<ServerConfigManager>) -> Router {
59 use std::num::NonZeroUsize;
60 let shared_pool_config =
61 AsyncDieselConnectionManager::<diesel_async::AsyncPgConnection>::new(db_url);
62
63 let library_pool_config =
64 AsyncDieselConnectionManager::<diesel_async::AsyncPgConnection>::new(db_url);
65
66 let num_cpus: usize = std::thread::available_parallelism()
67 .unwrap_or(NonZeroUsize::new(2_usize).unwrap())
68 .into();
69
70 let shared_pool = Arc::new(
72 deadpool::managed::Pool::builder(shared_pool_config)
73 .max_size(num_cpus * 3)
74 .build()
75 .expect("Could not create pool"),
76 );
77
78 let library_pool = Arc::new(
81 deadpool::managed::Pool::builder(library_pool_config)
82 .max_size(num_cpus)
83 .build()
84 .expect("Could not create pool"),
85 );
86
87 let igdb_client = Arc::new(IGDBProvider::new(config_manager.clone()));
88 let steam_web_api_client = Arc::new(SteamWebApiProvider::new(config_manager.clone()));
89
90 let _retrom_dirs = RetromDirs::new();
91 let media_cache = Arc::new(MediaCache::new(config_manager.clone()));
92
93 let job_manager = Arc::new(JobManager::new());
94
95 let reflection_service = tonic_reflection::server::Builder::configure()
96 .register_encoded_file_descriptor_set(FILE_DESCRIPTOR_SET)
97 .build_v1()
98 .unwrap();
99
100 let library_service = LibraryServiceServer::new(LibraryServiceHandlers::new(
101 library_pool.clone(),
102 igdb_client.clone(),
103 steam_web_api_client.clone(),
104 job_manager.clone(),
105 config_manager.clone(),
106 ));
107
108 let metadata_service = MetadataServiceServer::new(MetadataServiceHandlers::new(
109 shared_pool.clone(),
110 igdb_client.clone(),
111 steam_web_api_client.clone(),
112 media_cache.clone(),
113 job_manager.clone(),
114 config_manager.clone(),
115 ));
116
117 let game_service = GameServiceServer::new(GameServiceHandlers::new(shared_pool.clone()));
118 let platform_service =
119 PlatformServiceServer::new(PlatformServiceHandlers::new(shared_pool.clone()));
120
121 let client_service =
122 ClientServiceServer::new(clients::ClientServiceHandlers::new(shared_pool.clone()));
123
124 let server_service = ServerServiceServer::new(server::ServerServiceHandlers {
125 config: config_manager.clone(),
126 });
127
128 let emulator_service =
129 EmulatorServiceServer::new(EmulatorServiceHandlers::new(shared_pool.clone()));
130
131 let job_service = JobServiceServer::new(JobServiceHandlers::new(job_manager.clone()));
132 let file_explorer_service = FileExplorerServiceServer::new(FileExplorerServiceHandlers::new());
133
134 let saves_service = SavesServiceServer::new(SavesServiceHandlers::new(
135 shared_pool.clone(),
136 config_manager.clone(),
137 ));
138
139 let mut routes_builder = tonic::service::Routes::builder();
140
141 routes_builder
142 .add_service(reflection_service)
143 .add_service(library_service)
144 .add_service(game_service)
145 .add_service(platform_service)
146 .add_service(metadata_service)
147 .add_service(client_service)
148 .add_service(server_service)
149 .add_service(emulator_service)
150 .add_service(job_service)
151 .add_service(file_explorer_service)
152 .add_service(saves_service);
153
154 routes_builder
155 .routes()
156 .into_axum_router()
157 .layer(tonic_web::GrpcWebLayer::new())
158 .layer(
159 tower_http::trace::TraceLayer::new_for_grpc()
160 .make_span_with(GrpcOnRequestSpan::default())
161 .on_response(GrpcOnResponseSpanHandler::default()),
162 )
163 .layer(
164 CorsLayer::new()
165 .allow_origin(AllowOrigin::mirror_request())
166 .allow_credentials(true)
167 .expose_headers(DEFAULT_EXPOSED_HEADERS)
168 .allow_headers(DEFAULT_ALLOW_HEADERS)
169 .max_age(DEFAULT_MAX_AGE),
170 )
171}