mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
* rename frontend to web and update contributing guide * rename this time * fix build * restructure rust code * update documentation * update descriptions * Update CONTRIBUTING.md Co-authored-by: J H <2364004+Blu-J@users.noreply.github.com> --------- Co-authored-by: Aiden McClelland <me@drbonez.dev> Co-authored-by: Aiden McClelland <3732071+dr-bonez@users.noreply.github.com> Co-authored-by: J H <2364004+Blu-J@users.noreply.github.com>
146 lines
5.1 KiB
Rust
146 lines
5.1 KiB
Rust
use sha2::{Digest, Sha512};
|
|
use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt, SeekFrom};
|
|
use tracing::instrument;
|
|
use typed_builder::TypedBuilder;
|
|
|
|
use super::header::{FileSection, Header};
|
|
use super::manifest::Manifest;
|
|
use super::SIG_CONTEXT;
|
|
use crate::util::io::to_cbor_async_writer;
|
|
use crate::util::HashWriter;
|
|
use crate::{Error, ResultExt};
|
|
|
|
#[derive(TypedBuilder)]
|
|
pub struct S9pkPacker<
|
|
'a,
|
|
W: AsyncWriteExt + AsyncSeekExt,
|
|
RLicense: AsyncReadExt + Unpin,
|
|
RInstructions: AsyncReadExt + Unpin,
|
|
RIcon: AsyncReadExt + Unpin,
|
|
RDockerImages: AsyncReadExt + Unpin,
|
|
RAssets: AsyncReadExt + Unpin,
|
|
RScripts: AsyncReadExt + Unpin,
|
|
> {
|
|
writer: W,
|
|
manifest: &'a Manifest,
|
|
license: RLicense,
|
|
instructions: RInstructions,
|
|
icon: RIcon,
|
|
docker_images: RDockerImages,
|
|
assets: RAssets,
|
|
scripts: Option<RScripts>,
|
|
}
|
|
impl<
|
|
'a,
|
|
W: AsyncWriteExt + AsyncSeekExt + Unpin,
|
|
RLicense: AsyncReadExt + Unpin,
|
|
RInstructions: AsyncReadExt + Unpin,
|
|
RIcon: AsyncReadExt + Unpin,
|
|
RDockerImages: AsyncReadExt + Unpin,
|
|
RAssets: AsyncReadExt + Unpin,
|
|
RScripts: AsyncReadExt + Unpin,
|
|
> S9pkPacker<'a, W, RLicense, RInstructions, RIcon, RDockerImages, RAssets, RScripts>
|
|
{
|
|
/// BLOCKING
|
|
#[instrument(skip_all)]
|
|
pub async fn pack(mut self, key: &ed25519_dalek::SigningKey) -> Result<(), Error> {
|
|
let header_pos = self.writer.stream_position().await?;
|
|
if header_pos != 0 {
|
|
tracing::warn!("Appending to non-empty file.");
|
|
}
|
|
let mut header = Header::placeholder();
|
|
header.serialize(&mut self.writer).await.with_ctx(|_| {
|
|
(
|
|
crate::ErrorKind::Serialization,
|
|
"Writing Placeholder Header",
|
|
)
|
|
})?;
|
|
let mut position = self.writer.stream_position().await?;
|
|
|
|
let mut writer = HashWriter::new(Sha512::new(), &mut self.writer);
|
|
// manifest
|
|
to_cbor_async_writer(&mut writer, self.manifest).await?;
|
|
let new_pos = writer.inner_mut().stream_position().await?;
|
|
header.table_of_contents.manifest = FileSection {
|
|
position,
|
|
length: new_pos - position,
|
|
};
|
|
position = new_pos;
|
|
// license
|
|
tokio::io::copy(&mut self.license, &mut writer)
|
|
.await
|
|
.with_ctx(|_| (crate::ErrorKind::Filesystem, "Copying License"))?;
|
|
let new_pos = writer.inner_mut().stream_position().await?;
|
|
header.table_of_contents.license = FileSection {
|
|
position,
|
|
length: new_pos - position,
|
|
};
|
|
position = new_pos;
|
|
// instructions
|
|
tokio::io::copy(&mut self.instructions, &mut writer)
|
|
.await
|
|
.with_ctx(|_| (crate::ErrorKind::Filesystem, "Copying Instructions"))?;
|
|
let new_pos = writer.inner_mut().stream_position().await?;
|
|
header.table_of_contents.instructions = FileSection {
|
|
position,
|
|
length: new_pos - position,
|
|
};
|
|
position = new_pos;
|
|
// icon
|
|
tokio::io::copy(&mut self.icon, &mut writer)
|
|
.await
|
|
.with_ctx(|_| (crate::ErrorKind::Filesystem, "Copying Icon"))?;
|
|
let new_pos = writer.inner_mut().stream_position().await?;
|
|
header.table_of_contents.icon = FileSection {
|
|
position,
|
|
length: new_pos - position,
|
|
};
|
|
position = new_pos;
|
|
// docker_images
|
|
tokio::io::copy(&mut self.docker_images, &mut writer)
|
|
.await
|
|
.with_ctx(|_| (crate::ErrorKind::Filesystem, "Copying Docker Images"))?;
|
|
let new_pos = writer.inner_mut().stream_position().await?;
|
|
header.table_of_contents.docker_images = FileSection {
|
|
position,
|
|
length: new_pos - position,
|
|
};
|
|
position = new_pos;
|
|
// assets
|
|
tokio::io::copy(&mut self.assets, &mut writer)
|
|
.await
|
|
.with_ctx(|_| (crate::ErrorKind::Filesystem, "Copying Assets"))?;
|
|
let new_pos = writer.inner_mut().stream_position().await?;
|
|
header.table_of_contents.assets = FileSection {
|
|
position,
|
|
length: new_pos - position,
|
|
};
|
|
position = new_pos;
|
|
// scripts
|
|
if let Some(mut scripts) = self.scripts {
|
|
tokio::io::copy(&mut scripts, &mut writer)
|
|
.await
|
|
.with_ctx(|_| (crate::ErrorKind::Filesystem, "Copying Scripts"))?;
|
|
let new_pos = writer.inner_mut().stream_position().await?;
|
|
header.table_of_contents.scripts = Some(FileSection {
|
|
position,
|
|
length: new_pos - position,
|
|
});
|
|
position = new_pos;
|
|
}
|
|
|
|
// header
|
|
let (hash, _) = writer.finish();
|
|
self.writer.seek(SeekFrom::Start(header_pos)).await?;
|
|
header.pubkey = key.into();
|
|
header.signature = key.sign_prehashed(hash, Some(SIG_CONTEXT))?;
|
|
header
|
|
.serialize(&mut self.writer)
|
|
.await
|
|
.with_ctx(|_| (crate::ErrorKind::Serialization, "Writing Header"))?;
|
|
self.writer.seek(SeekFrom::Start(position)).await?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|