Skip to content

Commit

Permalink
feat: run workers in installed language runtimes (#81)
Browse files Browse the repository at this point in the history
* feat: run workers in installed language runtimes

* fix: delete wws binary

* fix: use inline args in println and fix Windows test by adding missing config

* feat: add a python example

* chore: move external runtime initialization logic to a separate method
  • Loading branch information
Angelmmiguel authored Feb 7, 2023
1 parent eb1df99 commit 9752cf2
Show file tree
Hide file tree
Showing 12 changed files with 244 additions and 31 deletions.
2 changes: 2 additions & 0 deletions examples/python-basic/worker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def worker(req):
return Response("Hello from Python!")
3 changes: 3 additions & 0 deletions examples/ruby-basic/worker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
def worker(_req)
Response.new("Hello from Ruby!")
end
27 changes: 17 additions & 10 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,7 @@ impl Config {
anyhow!("Error opening the .wws.toml file. The file format is not correct")
})
} else {
let new_repo = ConfigRepository {
name: DEFAULT_REPO_NAME.to_string(),
url: DEFAULT_REPO_URL.to_string(),
runtimes: Vec::new(),
};

Ok(Self {
version: 1,
repositories: vec![new_repo],
})
Ok(Self::default())
}
}

Expand Down Expand Up @@ -115,6 +106,22 @@ impl Config {
}
}

impl Default for Config {
// Initialize an empty repository by default
fn default() -> Self {
let new_repo = ConfigRepository {
name: DEFAULT_REPO_NAME.to_string(),
url: DEFAULT_REPO_URL.to_string(),
runtimes: Vec::new(),
};

Self {
version: 1,
repositories: vec![new_repo],
}
}
}

#[derive(Deserialize, Serialize)]
pub struct ConfigRepository {
/// Local name to identify the repository. It avoids collisions when installing
Expand Down
15 changes: 14 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ mod runtimes;
mod store;
mod workers;

use crate::config::Config;
use actix_files::{Files, NamedFile};
use actix_web::dev::{fn_service, ServiceRequest, ServiceResponse};
use actix_web::{
Expand Down Expand Up @@ -257,8 +258,20 @@ async fn main() -> std::io::Result<()> {
} else {
// TODO(Angelmmiguel): refactor this into a separate command!
// Initialize the routes

// Loading the local configuration if available.
let config = match Config::load(&args.path) {
Ok(c) => c,
Err(err) => {
println!("⚠️ There was an error reading the .wws.toml file. It will be ignored");
println!("⚠️ Error: {err}");

Config::default()
}
};

println!("⚙️ Loading routes from: {}", &args.path.display());
let routes = Data::new(Routes::new(&args.path, &args.prefix));
let routes = Data::new(Routes::new(&args.path, &args.prefix, &config));

let data = Data::new(RwLock::new(DataConnectors { kv: KV::new() }));

Expand Down
30 changes: 26 additions & 4 deletions src/router/files.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2022 VMware, Inc.
// SPDX-License-Identifier: Apache-2.0

use crate::config::Config;
use crate::store::STORE_FOLDER;
use std::ffi::OsStr;
use std::path::{Component, Path, PathBuf};
Expand All @@ -11,25 +12,43 @@ use wax::{Glob, WalkEntry};
/// provide utilities to work with public folders and
/// other related resources.
pub struct Files {
/// Root path
root: PathBuf,
/// Available extensions based on the config
extensions: Vec<String>,
/// Check if the public folder exists
has_public: bool,
}

impl Files {
/// Initializes a new files instance. It will detect
/// relevant resources for WWS like the public folder.
pub fn new(root: &Path) -> Self {
pub fn new(root: &Path, config: &Config) -> Self {
let mut extensions = vec![String::from("js"), String::from("wasm")];

for repo in &config.repositories {
for runtime in &repo.runtimes {
for ext in &runtime.extensions {
if !extensions.contains(ext) {
extensions.push(ext.clone());
}
}
}
}

Self {
root: root.to_path_buf(),
extensions,
has_public: root.join(Path::new("public")).exists(),
}
}

/// Walk through all the different files associated to this
/// project using a Glob pattern
pub fn walk(&self) -> Vec<WalkEntry> {
let glob_pattern = format!("**/*.{{{}}}", self.extensions.join(","));
let glob =
Glob::new("**/*.{wasm,js}").expect("Failed to read the files in the current directory");
Glob::new(&glob_pattern).expect("Failed to read the files in the current directory");

glob.walk(&self.root)
.filter_map(|el| match el {
Expand Down Expand Up @@ -85,8 +104,9 @@ mod tests {
];

for t in tests {
let config = Config::default();
assert_eq!(
Files::new(Path::new("./tests/data")).is_in_public_folder(Path::new(t.0)),
Files::new(Path::new("./tests/data"), &config).is_in_public_folder(Path::new(t.0)),
t.1
)
}
Expand All @@ -106,8 +126,10 @@ mod tests {
];

for t in tests {
let config = Config::default();
assert_eq!(
Files::new(Path::new(".\\tests\\data")).is_in_public_folder(Path::new(t.0)),
Files::new(Path::new(".\\tests\\data"), &config)
.is_in_public_folder(Path::new(t.0)),
t.1
)
}
Expand Down
6 changes: 3 additions & 3 deletions src/router/route.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2022 VMware, Inc.
// SPDX-License-Identifier: Apache-2.0

use crate::{workers::config::Config, workers::Worker};
use crate::{config::Config as ProjectConfig, workers::config::Config, workers::Worker};
use lazy_static::lazy_static;
use regex::Regex;
use std::{
Expand Down Expand Up @@ -53,8 +53,8 @@ impl Route {
/// proper URL path based on the filename.
///
/// This method also initializes the Runner and loads the Config if available.
pub fn new(base_path: &Path, filepath: PathBuf, prefix: &str) -> Self {
let worker = Worker::new(base_path, &filepath).unwrap();
pub fn new(base_path: &Path, filepath: PathBuf, prefix: &str, config: &ProjectConfig) -> Self {
let worker = Worker::new(base_path, &filepath, config).unwrap();

// Load configuration
let mut config_path = filepath.clone();
Expand Down
11 changes: 8 additions & 3 deletions src/router/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::path::Path;

use super::files::Files;
use super::route::{Route, RouteAffinity};
use crate::config::Config;

/// Contains all registered routes
pub struct Routes {
Expand All @@ -20,13 +21,13 @@ impl Routes {
/// Initialize the list of routes from the given folder. This method will look for
/// different files and will create the associated routes. This routing approach
/// is pretty popular in web development and static sites.
pub fn new(path: &Path, base_prefix: &str) -> Self {
pub fn new(path: &Path, base_prefix: &str, config: &Config) -> Self {
let mut routes = Vec::new();
let prefix = Self::format_prefix(base_prefix);
let files = Files::new(path);
let files = Files::new(path, config);

for entry in files.walk() {
routes.push(Route::new(path, entry.into_path(), &prefix));
routes.push(Route::new(path, entry.into_path(), &prefix, config));
}

Self { routes, prefix }
Expand Down Expand Up @@ -91,10 +92,12 @@ mod tests {
#[test]
fn route_path_affinity() {
let build_route = |file: &str| -> Route {
let project_config = Config::default();
Route::new(
Path::new("./tests/data/params"),
PathBuf::from(format!("./tests/data/params{file}")),
"",
&project_config,
)
};

Expand Down Expand Up @@ -123,10 +126,12 @@ mod tests {
#[test]
fn best_route_by_affinity() {
let build_route = |file: &str| -> Route {
let project_config = Config::default();
Route::new(
Path::new("./tests/data/params"),
PathBuf::from(format!("./tests/data/params{file}")),
"",
&project_config,
)
};

Expand Down
50 changes: 44 additions & 6 deletions src/runtimes/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

use super::{
metadata::{RemoteFile, Runtime as RuntimeMetadata},
modules::{javascript::JavaScriptRuntime, native::NativeRuntime},
modules::{external::ExternalRuntime, javascript::JavaScriptRuntime, native::NativeRuntime},
runtime::Runtime,
};
use crate::{fetch::fetch_and_validate, store::Store};
use crate::{config::Config, fetch::fetch_and_validate, store::Store};
use anyhow::{anyhow, Result};
use std::path::Path;

Expand All @@ -15,7 +15,11 @@ use std::path::Path;
/// Initializes a runtime based on the file extension. In the future,
/// This will contain a more complete struct that will identify local
/// runtimes.
pub fn init_runtime(project_root: &Path, path: &Path) -> Result<Box<dyn Runtime + Sync + Send>> {
pub fn init_runtime(
project_root: &Path,
path: &Path,
config: &Config,
) -> Result<Box<dyn Runtime + Sync + Send>> {
if let Some(ext) = path.extension() {
let ext_as_str = ext.to_str().unwrap();

Expand All @@ -25,15 +29,49 @@ pub fn init_runtime(project_root: &Path, path: &Path) -> Result<Box<dyn Runtime
path.to_path_buf(),
)?)),
"wasm" => Ok(Box::new(NativeRuntime::new(path.to_path_buf()))),
_ => Err(anyhow!(format!(
"The '{ext_as_str}' extension does not have an associated runtime"
))),
other => init_external_runtime(project_root, config, path, other),
}
} else {
Err(anyhow!("The given file does not have a valid extension"))
}
}

/// Initialize an external runtime. It looks for the right runtime in the configuration
/// metadata. Then, it will init the runtime with it.
fn init_external_runtime(
project_root: &Path,
config: &Config,
path: &Path,
extension: &str,
) -> Result<Box<dyn Runtime + Sync + Send>> {
let mut runtime_config = None;
let mut repo_name = "";
let other_string = extension.to_string();

'outer: for repo in &config.repositories {
for r in &repo.runtimes {
if r.extensions.contains(&other_string) {
runtime_config = Some(r);
repo_name = &repo.name;
break 'outer;
}
}
}

if let Some(runtime_config) = runtime_config {
Ok(Box::new(ExternalRuntime::new(
project_root,
path.to_path_buf(),
repo_name,
runtime_config.clone(),
)?))
} else {
Err(anyhow!(format!(
"The '{extension}' extension does not have an associated runtime"
)))
}
}

// Install a given runtime based on its metadata
pub async fn install_runtime(
project_root: &Path,
Expand Down
Loading

0 comments on commit 9752cf2

Please sign in to comment.