Skip to main content

phoxal_bundle/
reader.rs

1//! The one bundle reader, used by the supervisor and by every participant.
2
3use std::path::Path;
4
5use phoxal_model::identity::RobotId;
6use phoxal_model::manifest::ManifestDocument;
7use phoxal_model::{AssetId, Robot};
8
9use crate::{BundleError, BundleRoot, ParticipantAssets, read_manifest_document};
10
11/// An opened bundle: its manifest, and access to its assets.
12///
13/// Opening one parses `manifest.json` and does nothing else. A participant not
14/// named in the manifest opens the bundle exactly as one that is - the manifest
15/// is the robot model plus, for those that have one, their own configuration -
16/// so there is no selection step and no way for a launched process to be refused
17/// by the bundle it was pointed at.
18#[derive(Clone, Debug)]
19pub struct RuntimeBundle {
20    root: BundleRoot,
21    manifest: ManifestDocument,
22    assets: ParticipantAssets,
23}
24
25impl RuntimeBundle {
26    /// Open one installed bundle.
27    ///
28    /// # Errors
29    ///
30    /// Returns [`BundleError::Root`] or [`BundleError::NotDirectory`] when
31    /// `root` is not a directory, [`BundleError::ReadManifest`] when
32    /// `manifest.json` cannot be read, and [`BundleError::ManifestJson`] when it
33    /// is not a document this train understands.
34    pub fn open(root: impl AsRef<Path>) -> Result<Self, BundleError> {
35        let root = BundleRoot::open(root.as_ref())?;
36        let manifest = read_manifest_document(&root)?;
37        Ok(Self {
38            assets: ParticipantAssets::new(root.clone()),
39            root,
40            manifest,
41        })
42    }
43
44    /// The bundle root path, retained for diagnostics and for launching.
45    #[must_use]
46    pub fn root(&self) -> &Path {
47        self.root.path()
48    }
49
50    /// The persisted document, tag included.
51    #[must_use]
52    pub const fn manifest(&self) -> &ManifestDocument {
53        &self.manifest
54    }
55
56    /// The compiled robot the manifest carries.
57    #[must_use]
58    pub const fn robot(&self) -> &Robot {
59        self.manifest.robot()
60    }
61
62    /// The sole persisted robot identity.
63    #[must_use]
64    pub const fn robot_id(&self) -> &RobotId {
65        self.robot().id()
66    }
67
68    /// Read one asset out of `<bundle>/assets`.
69    ///
70    /// # Errors
71    ///
72    /// Returns the same failures as [`ParticipantAssets::read`].
73    pub fn asset(&self, id: &AssetId) -> Result<Vec<u8>, BundleError> {
74        self.assets.read(id)
75    }
76
77    /// The asset reader, for a consumer that keeps it beyond this value.
78    #[must_use]
79    pub const fn assets(&self) -> &ParticipantAssets {
80        &self.assets
81    }
82
83    pub(crate) fn relocated(mut self, path: std::path::PathBuf) -> Self {
84        self.root.relocate(path.clone());
85        self.assets.relocate(path);
86        self
87    }
88}