Skip to main content

sofie_http/
module.rs

1use sofie_db::worker::Worker;
2use sofie_db::{Db, File, Migrations};
3
4#[cfg(feature = "engine")]
5use crate::screens::Form;
6use crate::{App, RouteName};
7
8pub type Mount = fn(App, &'static str) -> App;
9
10/// A module crate's `MODULE`: its manifest (`name`, `tier`, `context`, `settings`)
11/// spreading what `sofie gen` writes in its `src/wiring.rs`; a package writes its own.
12#[derive(Clone, Copy)]
13pub struct Module {
14    /// The crate name; also its database schema and its configuration prefix.
15    pub name: &'static str,
16    pub tier: Tier,
17    /// Metadata only, granting no access.
18    pub context: Option<&'static str>,
19    pub settings: &'static [Setting],
20    pub migrations: Option<Migrations>,
21    /// A handler's module path is not known at runtime, so the wiring names each route.
22    pub route_names: &'static [RouteName],
23    /// A key naming another module's screen, `<module>/<area>/<name>`, replaces that screen.
24    pub screens: &'static [(&'static str, File)],
25    #[cfg(feature = "engine")]
26    pub forms: &'static [Form],
27    pub areas: &'static [Mount],
28    pub jobs: fn(Worker) -> Worker,
29}
30
31/// A module depends only on its own tier or lower ones.
32#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub enum Tier {
34    Experience,
35    Core,
36    Platform,
37}
38
39#[derive(Clone, Copy, Debug, PartialEq, Eq)]
40pub struct Setting {
41    pub name: &'static str,
42    pub default: SettingValue,
43}
44
45#[derive(Clone, Copy, Debug, PartialEq, Eq)]
46pub enum SettingValue {
47    Switch(bool),
48    Number(i64),
49    Text(&'static str),
50}
51
52impl Module {
53    /// A package's: the platform tier, no context, settings or registrations.
54    #[must_use]
55    pub const fn new(name: &'static str) -> Self {
56        Self {
57            name,
58            tier: Tier::Platform,
59            context: None,
60            settings: &[],
61            migrations: None,
62            route_names: &[],
63            screens: &[],
64            #[cfg(feature = "engine")]
65            forms: &[],
66            areas: &[],
67            jobs: no_jobs,
68        }
69    }
70}
71
72fn no_jobs(worker: Worker) -> Worker {
73    worker
74}
75
76#[must_use]
77pub fn migrations(modules: &[Module]) -> Vec<Migrations> {
78    modules
79        .iter()
80        .filter_map(|module| module.migrations)
81        .collect()
82}
83
84#[must_use]
85pub fn worker(db: Db, modules: &[Module]) -> Worker {
86    modules
87        .iter()
88        .fold(Worker::new(db), |worker, module| (module.jobs)(worker))
89}
90
91impl App {
92    #[must_use]
93    pub fn modules(mut self, modules: &[Module]) -> Self {
94        for module in modules {
95            self.names.extend_from_slice(module.route_names);
96        }
97        modules.iter().fold(self, |app, module| {
98            module
99                .areas
100                .iter()
101                .fold(app, |app, mount| mount(app, module.name))
102        })
103    }
104}