1use std::collections::HashMap;
2use std::sync::Arc;
3
4use sofie_core::Result;
5use sofie_db::Db;
6use tokio::net::TcpListener;
7
8#[cfg(feature = "engine")]
9use crate::Screens;
10use crate::admission::AreaPolicy;
11use crate::routes::Route;
12use crate::throttle::{Limiter, Rate};
13use crate::{Area, AreaMembers, RouteName, Routes, Serving, server};
14
15pub struct App {
16 pub(crate) db: Db,
17 #[cfg(feature = "engine")]
18 pub(crate) screens: Screens,
19 pub(crate) routes: Vec<Route>,
20 #[cfg(feature = "islands")]
21 pub(crate) islands: Vec<crate::islands::IslandScreen>,
22 pub(crate) names: Vec<RouteName>,
23 pub(crate) areas: HashMap<&'static str, AreaPolicy>,
24 pub(crate) members: Option<Arc<dyn AreaMembers>>,
25 #[cfg(feature = "gates")]
26 pub(crate) gates: crate::Gates,
27 #[cfg(feature = "steps")]
28 pub(crate) steps: Vec<Box<dyn crate::PipelineStep>>,
29 #[cfg(feature = "cors")]
30 pub(crate) cors: HashMap<&'static str, crate::Cors>,
31 pub(crate) serving: Serving,
32}
33
34impl App {
35 #[must_use]
36 pub fn new(db: Db) -> Self {
37 Self {
38 db,
39 #[cfg(feature = "engine")]
40 screens: Screens::default(),
41 routes: Vec::new(),
42 #[cfg(feature = "islands")]
43 islands: Vec::new(),
44 names: Vec::new(),
45 areas: HashMap::new(),
46 members: None,
47 #[cfg(feature = "gates")]
48 gates: crate::Gates::default(),
49 #[cfg(feature = "steps")]
50 steps: Vec::new(),
51 #[cfg(feature = "cors")]
52 cors: HashMap::new(),
53 serving: Serving::default(),
54 }
55 }
56
57 #[cfg(feature = "steps")]
58 #[must_use]
59 pub fn step<A: Area>(mut self, step: impl crate::PipelineStep) -> Self {
60 self.areas
61 .entry(A::NAME)
62 .or_default()
63 .steps
64 .push(Box::new(step));
65 self
66 }
67
68 #[cfg(feature = "steps")]
70 #[must_use]
71 pub fn step_all(mut self, step: impl crate::PipelineStep) -> Self {
72 self.steps.push(Box::new(step));
73 self
74 }
75
76 #[cfg(feature = "cors")]
78 #[must_use]
79 pub fn cors<A: Area>(mut self, cors: crate::Cors) -> Self {
80 self.cors.insert(A::NAME, cors);
81 self
82 }
83
84 #[cfg(feature = "gates")]
86 #[must_use]
87 pub fn gates(mut self, gates: crate::Gates) -> Self {
88 #[cfg(feature = "menu")]
89 let menus = std::mem::take(&mut self.gates.menus);
90 self.gates = gates;
91 #[cfg(feature = "menu")]
92 {
93 self.gates.menus = menus;
94 }
95 self
96 }
97
98 #[must_use]
100 pub fn throttle<A: Area>(mut self, rate: Rate) -> Self {
101 self.areas.entry(A::NAME).or_default().throttle = Some(Limiter::new(rate));
102 self
103 }
104
105 #[must_use]
107 pub fn membership(mut self, members: impl AreaMembers) -> Self {
108 self.members = Some(Arc::new(members));
109 self
110 }
111
112 #[must_use]
114 pub fn serving(mut self, configure: impl FnOnce(Serving) -> Serving) -> Self {
115 self.serving = configure(std::mem::take(&mut self.serving));
116 self
117 }
118
119 #[cfg(feature = "engine")]
120 #[must_use]
121 pub fn screens(mut self, screens: Screens) -> Self {
122 self.screens = screens;
123 self
124 }
125
126 #[must_use]
127 pub fn area<A: Area>(
128 mut self,
129 module: &'static str,
130 define: impl FnOnce(&mut Routes<A>),
131 ) -> Self {
132 let mut routes = Routes::new(module);
133 define(&mut routes);
134 self.routes.extend(routes.added);
135 #[cfg(feature = "islands")]
136 self.islands.extend(routes.islands);
137 self
138 }
139
140 pub async fn serve(
142 self,
143 listener: TcpListener,
144 shutdown: impl Future<Output = ()>,
145 ) -> Result<()> {
146 server::serve(self, listener, shutdown).await
147 }
148}