Skip to content

Commit

Permalink
remove server global loader (#246)
Browse files Browse the repository at this point in the history
* remove server global loader

* clean up

---------

Co-authored-by: Pistonight <[email protected]>
  • Loading branch information
Pistonight and Pistonight authored May 13, 2024
1 parent 58c0fba commit b3d2385
Show file tree
Hide file tree
Showing 20 changed files with 388 additions and 231 deletions.
8 changes: 4 additions & 4 deletions compiler-base/src/env/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::cell::RefCell;

use crate::macros::late_global;
use crate::res::Loader;
use crate::res::LoaderFactory;

#[cfg(feature = "wasm")]
pub mod env_wasm;
Expand Down Expand Up @@ -44,10 +44,10 @@ pub mod site {
}
}

/// Global loader instance that can be used to load resources
/// Factory for getting resource loader instance that can be used to load resources
/// outside of the usual compilation cycle. For example, in plugins
#[late_global(dyn Loader)]
pub mod global_loader {}
#[late_global(dyn LoaderFactory)]
pub mod global_loader_factory {}

thread_local! {
/// Current number of ticks ran without yielding in cooperative multitasking
Expand Down
14 changes: 12 additions & 2 deletions compiler-base/src/res/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ pub enum ResError {

#[error("Cannot load url `{0}`: {1}")]
FailToLoadUrl(String, String),

#[error("Failed to create resource: {0}")]
Create(String),
}

impl PartialEq for ResError {
Expand All @@ -69,6 +72,13 @@ pub trait Loader {
async fn load_raw(&self, path: &ResPath) -> ResResult<RefCounted<[u8]>>;
}

/// Factory for creating new loaders
pub trait LoaderFactory: Send + Sync {
/// Get a loader instance. Note that the loader instance is ref-counted
/// and could be shared among multiple resources. (Doesn't have to be a new one)
fn create_loader(&self) -> ResResult<RefCounted<dyn Loader>>;
}

/// A Resource is an absolute reference to a resource that can be loaded.
/// It can be a local file or a remote URL. It also has an associated ref-counted
/// [`Loader`] that can be used to load the resource.
Expand All @@ -77,8 +87,8 @@ pub struct Resource<'a, L>
where
L: Loader,
{
path: ResPath<'a>,
loader: RefCounted<L>,
pub path: ResPath<'a>,
pub loader: RefCounted<L>,
}

impl<'a, L> Resource<'a, L>
Expand Down
2 changes: 1 addition & 1 deletion compiler-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ pub use comp::CompDoc;
pub use exec::{ExecContext, ExecDoc};
pub use expo::{ExpoContext, ExpoDoc, ExportRequest};
pub use pack::{CompileContext, Compiler};
pub use prep::{ContextBuilder, PreparedContext};
pub use prep::{ContextBuilder, PrepCtx, PrepDoc};

pub use celerb::*;
4 changes: 2 additions & 2 deletions compiler-core/src/pack/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use instant::Instant;
use crate::env::yield_budget;
use crate::json::RouteBlob;
use crate::plugin;
use crate::prep::{self, CompilerMetadata, PrepDoc, PreparedContext, RouteConfig, Setting};
use crate::prep::{self, CompilerMetadata, PrepCtx, PrepDoc, RouteConfig, Setting};
use crate::res::Loader;

mod error;
Expand Down Expand Up @@ -146,7 +146,7 @@ impl<'p> CompileContext<'p> {
}
}

impl<L> PreparedContext<L>
impl<L> PrepCtx<L>
where
L: Loader,
{
Expand Down
7 changes: 5 additions & 2 deletions compiler-core/src/plugin/native/export_livesplit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,13 +222,16 @@ async fn load_icon(
icon_url: String,
webp_compat: WebpCompat,
) -> Result<(String, RefCounted<[u8]>), String> {
let loader = match env::global_loader::get() {
let loader = match env::global_loader_factory::get() {
None => {
return Err(
"No global loader available to load the icons for split export!".to_string(),
)
}
Some(loader) => loader,
Some(factory) => match factory.create_loader() {
Ok(loader) => loader,
Err(e) => return Err(format!("Failed to create loader: {e}")),
},
};

let path = ResPath::new_remote_unchecked("", &icon_url);
Expand Down
66 changes: 54 additions & 12 deletions compiler-core/src/prep/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,19 @@
//! the compiler with additional (and optional) plugins.
use std::collections::BTreeMap;
use std::ops::Deref;

use derivative::Derivative;
use instant::Instant;
use serde_json::{Map, Value};

use crate::env::join_futures;
use crate::env::{join_futures, RefCounted};
use crate::json::{Cast, Coerce, RouteBlob};
use crate::lang::Preset;
use crate::macros::derive_wasm;
use crate::plugin;
use crate::prop;
use crate::res::{Loader, Resource, Use, ValidUse};
use crate::res::{Loader, ResPath, Resource, Use, ValidUse};
use crate::util::StringMap;

mod error;
Expand All @@ -44,11 +45,49 @@ pub use route::*;

/// Output of the prep phase
#[derive(Debug, Clone)]
pub struct PreparedContext<L>
pub struct PrepCtx<L>
where
L: Loader,
{
pub project_res: Resource<'static, L>,
data: RefCounted<PrepCtxData>,
}

impl<L> Deref for PrepCtx<L>
where
L: Loader,
{
type Target = PrepCtxData;

fn deref(&self) -> &Self::Target {
&self.data
}
}

impl<L> PrepCtx<L>
where
L: Loader,
{
/// Hydrate a context from its data with a loader
pub fn from_data(data: RefCounted<PrepCtxData>, loader: RefCounted<L>) -> Self {
Self {
project_res: Resource::new(data.res_path.clone(), loader),
data,
}
}

/// Get the ref-counted inner data
#[inline]
pub fn get_data(&self) -> &RefCounted<PrepCtxData> {
&self.data
}
}

/// The loader-independent data of prep context that
/// is safe to be cached
#[derive(Debug, Clone)]
pub struct PrepCtxData {
pub res_path: ResPath<'static>,
pub entry_path: Option<String>,
pub config: RouteConfig,
pub meta: CompilerMetadata,
Expand Down Expand Up @@ -160,7 +199,7 @@ where
}

/// Load the project and parse config and (optionally) route
pub async fn build_context(mut self) -> PrepResult<PreparedContext<L>> {
pub async fn build_context(mut self) -> PrepResult<PrepCtx<L>> {
let start_time = Instant::now();
let mut project = self.resolve_entry_point().await?;
let metadata = self.load_metadata(&mut project)?;
Expand Down Expand Up @@ -219,15 +258,18 @@ where
let (config_and_meta, prep_doc) = join_futures!(config_future, route_future);
let (config, meta, plugins) = config_and_meta?;

Ok(PreparedContext {
Ok(PrepCtx {
data: RefCounted::new(PrepCtxData {
res_path: self.project_res.path().clone(),
entry_path: self.entry_point,
config,
meta,
prep_doc,
start_time,
setting: self.setting,
plugins,
}),
project_res: self.project_res,
entry_path: self.entry_point,
config,
meta,
prep_doc,
start_time,
setting: self.setting,
plugins,
})
}

Expand Down
12 changes: 6 additions & 6 deletions compiler-wasm/src/compiler/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ use std::cell::RefCell;

use log::info;

use celerc::PreparedContext;
use celerc::PrepCtx;

use crate::loader::{self, LoadFileOutput, LoaderInWasm};

thread_local! {
static CACHED_COMPILER_CONTEXT: RefCell<Option<PreparedContext<LoaderInWasm>>> = const { RefCell::new(None) };
static CACHED_COMPILER_CONTEXT: RefCell<Option<PrepCtx<LoaderInWasm>>> = const { RefCell::new(None) };
}

/// Guard for acquiring the cached context and takes care of releasing it
pub struct CachedContextGuard(Option<PreparedContext<LoaderInWasm>>);
pub struct CachedContextGuard(Option<PrepCtx<LoaderInWasm>>);
impl CachedContextGuard {
/// Acquire the cached context if it's valid
pub async fn acquire(entry_path: Option<&String>) -> Option<Self> {
Expand Down Expand Up @@ -46,7 +46,7 @@ impl CachedContextGuard {
}

/// Put a new context into the cache upon drop
pub fn new(prep_ctx: PreparedContext<LoaderInWasm>) -> Self {
pub fn new(prep_ctx: PrepCtx<LoaderInWasm>) -> Self {
CachedContextGuard(Some(prep_ctx))
}
}
Expand All @@ -55,8 +55,8 @@ impl Drop for CachedContextGuard {
CACHED_COMPILER_CONTEXT.with_borrow_mut(|x| *x = self.0.take());
}
}
impl AsRef<PreparedContext<LoaderInWasm>> for CachedContextGuard {
fn as_ref(&self) -> &PreparedContext<LoaderInWasm> {
impl AsRef<PrepCtx<LoaderInWasm>> for CachedContextGuard {
fn as_ref(&self) -> &PrepCtx<LoaderInWasm> {
self.0.as_ref().unwrap()
}
}
4 changes: 2 additions & 2 deletions compiler-wasm/src/compiler/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use log::{error, info};

use celerc::pack::PackError;
use celerc::plugin;
use celerc::{Compiler, ExpoDoc, ExportRequest, PreparedContext};
use celerc::{Compiler, ExpoDoc, ExportRequest, PrepCtx};

use crate::loader::LoaderInWasm;

Expand Down Expand Up @@ -46,7 +46,7 @@ pub async fn export_document(
}

async fn export_in_context(
prep_ctx: &PreparedContext<LoaderInWasm>,
prep_ctx: &PrepCtx<LoaderInWasm>,
start_time: Option<Instant>,
plugin_options: Option<plugin::Options>,
req: ExportRequest,
Expand Down
6 changes: 3 additions & 3 deletions compiler-wasm/src/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use wasm_bindgen::prelude::*;

use celerc::pack::PackError;
use celerc::plugin;
use celerc::{CompDoc, CompileContext, Compiler, ContextBuilder, ExecContext, PreparedContext};
use celerc::{CompDoc, CompileContext, Compiler, ContextBuilder, ExecContext, PrepCtx};

use crate::interop::OpaqueExpoContext;
use crate::loader::LoaderInWasm;
Expand Down Expand Up @@ -57,7 +57,7 @@ pub async fn compile_document(
compile_in_context(guard.as_ref(), None, plugin_options).await
}

pub async fn new_context(entry_path: Option<String>) -> PrepResult<PreparedContext<LoaderInWasm>> {
pub async fn new_context(entry_path: Option<String>) -> PrepResult<PrepCtx<LoaderInWasm>> {
let mut context_builder = new_context_builder();
if entry_path.is_some() {
context_builder = context_builder.entry_point(entry_path);
Expand All @@ -66,7 +66,7 @@ pub async fn new_context(entry_path: Option<String>) -> PrepResult<PreparedConte
}

async fn compile_in_context(
prep_ctx: &PreparedContext<LoaderInWasm>,
prep_ctx: &PrepCtx<LoaderInWasm>,
start_time: Option<Instant>,
plugin_options: Option<plugin::Options>,
) -> Result<OpaqueExpoContext, JsValue> {
Expand Down
5 changes: 2 additions & 3 deletions compiler-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use wasm_bindgen::prelude::*;
use celerc::env::RefCounted;
use celerc::plugin::OptionsRaw as PluginOptionsRaw;
use celerc::prep::EntryPointsSorted;
use celerc::res::{Loader, ResPath, Resource};
use celerc::res::{ResPath, Resource};
use celerc::{ExpoDoc, ExportRequest};

mod interop;
Expand All @@ -30,8 +30,7 @@ pub fn init(
info!("initializing compiler...");
loader::bind(load_file, load_url);
celerc::env::site::set_origin(&site_origin);
let loader: Box<dyn Loader> = Box::new(LoaderInWasm);
let _ = celerc::env::global_loader::set(RefCounted::from(loader));
let _ = celerc::env::global_loader_factory::set(RefCounted::new(LoaderInWasm));

info!("compiler initialized");
}
Expand Down
8 changes: 7 additions & 1 deletion compiler-wasm/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use wasm_bindgen::prelude::*;

use celerc::env::{yield_budget, RefCounted};
use celerc::macros::async_trait;
use celerc::res::{Loader, ResError, ResPath, ResResult};
use celerc::res::{Loader, LoaderFactory, ResError, ResPath, ResResult};

use crate::interop::{self, JsIntoFuture};
use crate::logger;
Expand Down Expand Up @@ -44,6 +44,12 @@ pub fn bind(load_file: Function, load_url: Function) {

pub struct LoaderInWasm;

impl LoaderFactory for LoaderInWasm {
fn create_loader(&self) -> ResResult<RefCounted<dyn Loader>> {
Ok(RefCounted::from(Self))
}
}

#[async_trait(?Send)]
impl Loader for LoaderInWasm {
async fn load_raw(&self, path: &ResPath) -> ResResult<RefCounted<[u8]>> {
Expand Down
19 changes: 9 additions & 10 deletions server/Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@ tasks:
dev:
desc: Start server in watch mode
aliases: [d]
env:
CELERSERVER_LOG: INFO
CELERSERVER_ANSI: "true"
CELERSERVER_PORT: 8173
CELERSERVER_DOCS_DIR: ../docs/src/.vitepress/dist
CELERSERVER_APP_DIR: ../web-client/dist
CELERSERVER_HTTPS_CERT: ../cert/cert.pem
CELERSERVER_HTTPS_KEY: ../cert/cert-key.pem
CELERSERVER_SITE_ORIGIN: https://pistonite.local:8173
CELERSERVER_GZIP: "true"
dotenv:
- dev.env
cmds:
- cargo watch -B 1 -s "cargo run --bin celery {{.CLI_ARGS}}"

run:
desc: Start server
dotenv:
- dev.env
cmds:
- cargo run --bin celery {{.CLI_ARGS}}

watch:
desc: Run server tests in watch mode
cmds:
Expand Down
9 changes: 9 additions & 0 deletions server/dev.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CELERSERVER_LOG=INFO
CELERSERVER_ANSI=true
CELERSERVER_PORT=8173
CELERSERVER_DOCS_DIR=../docs/src/.vitepress/dist
CELERSERVER_APP_DIR=../web-client/dist
CELERSERVER_HTTPS_CERT=../cert/cert.pem
CELERSERVER_HTTPS_KEY=../cert/cert-key.pem
CELERSERVER_SITE_ORIGIN=https://pistonite.local:8173
CELERSERVER_GZIP=true
8 changes: 7 additions & 1 deletion server/src/api/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,13 @@ async fn view_internal(
reference: &str,
path: &str,
) -> Result<String, StatusCode> {
let mut builder = compiler::new_context_builder(owner, repo, Some(reference));
let mut builder = match compiler::new_context_builder(owner, repo, Some(reference)) {
Ok(builder) => builder,
Err(e) => {
error!("Error creating context builder for project {owner}/{repo}/{reference}: {e}");
return view_fallback();
}
};
if !path.is_empty() {
builder = builder.entry_point(Some(path.to_string()));
}
Expand Down
Loading

0 comments on commit b3d2385

Please sign in to comment.