Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ USER ${REMOTE_USER}
# Install Rustup and set default toolchains
RUN rustup default nightly

# Install the wasm32-wasi target for nightly
RUN rustup target add wasm32-wasip1 --toolchain nightly

# Install binstall
RUN curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash

Expand Down
41 changes: 27 additions & 14 deletions .github/docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
#!/bin/sh

# Check if the environment variable PTERODACTYL is set to true
if [ "$PTERODACTYL" = "true" ]; then
# Define the URL and the destination folder
WASM_URL="https://github.com/HttpRafa/atomic-cloud/releases/latest/download/pterodactyl-driver.wasm"
DEST_FOLDER="drivers/wasm"
WASM_FILE="$DEST_FOLDER/pterodactyl.wasm"
# Define the destination folder
DEST_FOLDER="drivers/wasm"

# Create the destination folder if it does not exist
if [ ! -d "$DEST_FOLDER" ]; then
echo "Creating directory $DEST_FOLDER..."
mkdir -p "$DEST_FOLDER"
fi
# Create the destination folder if it does not exist
if [ ! -d "$DEST_FOLDER" ]; then
echo "Creating directory $DEST_FOLDER..."
mkdir -p "$DEST_FOLDER"
fi

# Function to download the .wasm file
download_wasm() {
local WASM_URL=$1
local WASM_FILE=$2

# Check if the .wasm file already exists
if [ -f "$WASM_FILE" ]; then
Expand All @@ -25,9 +26,21 @@ if [ "$PTERODACTYL" = "true" ]; then

echo "Download complete."
fi
else
echo "PTERODACTYL is not set to true. Skipping download."
}

# Check if the environment variable PTERODACTYL is set to true
if [ "$PTERODACTYL" = "true" ]; then
WASM_URL="https://github.com/HttpRafa/atomic-cloud/releases/latest/download/pterodactyl-driver.wasm"
WASM_FILE="$DEST_FOLDER/pterodactyl.wasm"
download_wasm $WASM_URL $WASM_FILE
fi

# Check if the environment variable LOCAL is set to true
if [ "$LOCAL" = "true" ]; then
WASM_URL="https://github.com/HttpRafa/atomic-cloud/releases/latest/download/local-driver.wasm"
WASM_FILE="$DEST_FOLDER/local.wasm"
download_wasm $WASM_URL $WASM_FILE
fi

# Run the main command
./controller "$@"
exec ./controller "$@"
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
CURRENT_BUILD: ${{ github.run_number }}

- name: Run Tests
run: cargo test --workspace --exclude pterodactyl --all-features --verbose
run: cargo test --workspace --exclude pterodactyl --exclude local --all-features --verbose

- name: Build & Test JVM Client
working-directory: clients/jvm
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,12 @@ jobs:
git push -u origin $BRANCH
sed -i 's/client_version=0\.0\.0-nightly/client_version=\${REF:11}/g' clients/jvm/gradle.properties
sed -i 's/version = "0\.0\.0-nightly"/version = "\${REF:11}"/g' drivers/pterodactyl/Cargo.toml
sed -i 's/version = "0\.0\.0-nightly"/version = "\${REF:11}"/g' drivers/local/Cargo.toml
sed -i 's/version = "0\.0\.0-nightly"/version = "\${REF:11}"/g' clients/wrapper/Cargo.toml
sed -i 's/version = "0\.0\.0-nightly"/version = "\${REF:11}"/g' controller/Cargo.toml
sed -i 's/version = "0\.0\.0-nightly"/version = "\${REF:11}"/g' common/Cargo.toml
sed -i 's/version = "0\.0\.0-nightly"/version = "\${REF:11}"/g' cli/Cargo.toml
git add clients/jvm/gradle.properties drivers/pterodactyl/Cargo.toml clients/wrapper/Cargo.toml controller/Cargo.toml common/Cargo.toml cli/Cargo.toml
git add clients/jvm/gradle.properties drivers/pterodactyl/Cargo.toml drivers/local/Cargo.toml clients/wrapper/Cargo.toml controller/Cargo.toml common/Cargo.toml cli/Cargo.toml
git commit -m "ci(release): bump version"
git push

Expand Down Expand Up @@ -112,6 +113,7 @@ jobs:
cp ./target/x86_64-pc-windows-gnu/release/wrapper.exe wrapper-windows-x86_64.exe

cp ./target/wasm32-wasip2/release/pterodactyl.wasm pterodactyl-driver.wasm
cp ./target/wasm32-wasip2/release/local.wasm local-driver.wasm

cp $(find ./clients/jvm/paper/build -name "*-all.jar") paper-client.jar

Expand All @@ -131,4 +133,5 @@ jobs:
wrapper-linux-x86_64
wrapper-windows-x86_64.exe
pterodactyl-driver.wasm
local-driver.wasm
paper-client.jar
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ members = [

# Drivers
"drivers/pterodactyl",
"drivers/local",

# Clients
"cli",
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
# Configuration
WASM_RUSTFLAGS = -Z wasi-exec-model=reactor
WASM_TARGET = wasm32-wasip2
WASM_COMPONENT = target/wasm32-wasip2/release/pterodactyl.wasm

# Directories
RUN_DIR = run
Expand Down Expand Up @@ -72,6 +71,7 @@ build-wrapper:
build-drivers:
$(SETENV) RUSTFLAGS="$(WASM_RUSTFLAGS)"
cargo build -p pterodactyl --target $(WASM_TARGET) --release
cargo build -p local --target $(WASM_TARGET) --release

# Create driver directory if it doesn't exist
$(DRIVER_DIR):
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

Atomic Cloud is a cloud that was primarily developed for the game Minecraft, but it is possible to integrate other games with Atomic Cloud.

## Disclaimer

This project is a work in progress and a way for me to learn Rust. Since it’s one of my first Rust apps, the code might not be perfect. You might notice things like too many locks or overusing Mutex, and I’m still figuring out some of Rust’s trickier features like lifetimes.

If you like the project, I’d love to hear your suggestions or corrections! Just keep it friendly and helpful. Instead of saying, "everything is bad" let me know what can be improved and how. Over time, the code will get better.

## Documentation

For detailed information, please visit the [Atomic Cloud Documentation](https://httprafa.github.io/atomic-cloud/).
2 changes: 1 addition & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ simplelog = { version = "0.12.2", features = ["paris"] }
loading = "0.4.0"

# File management
dirs = "5.0.1"
dirs = "6.0.0"

# Input parsing
inquire = "0.7.5"
Expand Down
4 changes: 2 additions & 2 deletions cli/src/application/profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl Profiles {
profiles.add_profile(profile);
}

progress.success(format!("Loaded {} profiles(s)", profiles.profiles.len()));
progress.success(format!("Loaded {} profile(s)", profiles.profiles.len()));
progress.end();
profiles
}
Expand Down Expand Up @@ -177,7 +177,7 @@ impl Profile {
authorization: self.authorization.clone(),
url: self.url.clone(),
};
stored_profile.save_to_file(&Storage::get_profile_file(&self.id))
stored_profile.save_to_file(&Storage::get_profile_file(&self.id), true)
}

pub fn compute_id(name: &str) -> String {
Expand Down
2 changes: 1 addition & 1 deletion clients/wrapper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ anyhow = "1.0.95"
ctrlc = "3.4.5"

# User system
uuid = { version = "1.11.1", features = ["v4"] }
uuid = { version = "1.12.0", features = ["v4"] }

# Command line arguments
clap = { version = "4.5.26", features = ["derive"] }
Expand Down
47 changes: 47 additions & 0 deletions common/src/allocator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use std::{
collections::{BTreeSet, HashSet},
hash::Hash,
ops::{AddAssign, Range},
};

pub struct NumberAllocator<T> {
next: T,
max: T,
available: BTreeSet<T>,
active: HashSet<T>,
}

impl<T> NumberAllocator<T>
where
T: Copy + Ord + Hash + AddAssign + From<u8>,
{
pub fn new(range: Range<T>) -> Self {
Self {
next: range.start,
max: range.end,
available: BTreeSet::new(),
active: HashSet::new(),
}
}

pub fn allocate(&mut self) -> Option<T> {
if let Some(&id) = self.available.iter().next() {
self.available.remove(&id);
self.active.insert(id);
Some(id)
} else if self.next < self.max {
let id = self.next;
self.next += T::from(1);
self.active.insert(id);
Some(id)
} else {
None
}
}

pub fn release(&mut self, value: T) {
if self.active.remove(&value) {
self.available.insert(value);
}
}
}
8 changes: 5 additions & 3 deletions common/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ use anyhow::Result;
use serde::{de::DeserializeOwned, Serialize};

pub trait SaveToTomlFile: Serialize {
fn save_to_file(&self, path: &Path) -> Result<()> {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
fn save_to_file(&self, path: &Path, create_parent: bool) -> Result<()> {
if create_parent {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
}
fs::write(path, toml::to_string(self)?)?;
Ok(())
Expand Down
3 changes: 3 additions & 0 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
pub mod allocator;
pub mod config;
pub mod init;
pub mod name;
pub mod tick;
pub mod version;
45 changes: 45 additions & 0 deletions common/src/name.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use std::time::{SystemTime, UNIX_EPOCH};

#[derive(Clone)]
pub struct TimedName {
raw_name: String,
name: String,
}

impl TimedName {
pub fn new(cloud_identifier: &str, name: &str, permanent: bool) -> Self {
Self {
raw_name: name.to_string(),
name: Self::generate(Some(cloud_identifier.to_string()), name, permanent),
}
}
pub fn new_no_identifier(name: &str, permanent: bool) -> Self {
Self {
raw_name: name.to_string(),
name: Self::generate(None, name, permanent),
}
}

fn generate(cloud_identifier: Option<String>, name: &str, permanent: bool) -> String {
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
match (cloud_identifier, permanent) {
(Some(identifier), true) => format!("{}@{}", name, identifier),
(None, true) => name.to_string(),
(Some(identifier), false) => format!("{}@{}#{}", name, identifier, timestamp),
(None, false) => format!("{}#{}", name, timestamp),
}
}

pub fn get_name(&self) -> &str {
&self.name
}
pub fn get_name_cloned(&self) -> String {
self.name.clone()
}
pub fn get_raw_name(&self) -> &str {
&self.raw_name
}
}
6 changes: 6 additions & 0 deletions common/src/tick.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#[derive(PartialEq)]
pub enum TickResult {
Ok,
Drop,
Stop,
}
6 changes: 3 additions & 3 deletions controller/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ anyhow = "1.0.95"
ctrlc = "3.4.5"

# Unit system
uuid = { version = "1.11.1", features = ["v4"] }
uuid = { version = "1.12.0", features = ["v4"] }

# Command line arguments
clap = { version = "4.5.26", features = ["derive"] }
Expand All @@ -39,8 +39,8 @@ prost = "0.13.4"
tonic = "0.12.3"

# Drivers
wasmtime = { version = "28.0.0", default-features = false, features = ["runtime", "component-model", "cranelift", "parallel-compilation", "cache"], optional = true }
wasmtime-wasi = { version = "28.0.0", optional = true }
wasmtime = { version = "28.0.1", default-features = false, features = ["runtime", "component-model", "cranelift", "parallel-compilation", "cache"], optional = true }
wasmtime-wasi = { version = "28.0.1", optional = true }
minreq = { version = "2.13.0", features = ["https-rustls"], optional = true }

[build-dependencies]
Expand Down
10 changes: 10 additions & 0 deletions controller/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ impl Controller {
info!("<red>Stopping</> all units...");
self.units.stop_all_instant();

// Let the drivers cleanup there messes
info!("Letting the drivers <red>cleanup</>...");
self.drivers.cleanup();

// Stop network stack
info!("<red>Stopping</> network stack...");
network_handle.shutdown();
Expand Down Expand Up @@ -179,6 +183,12 @@ impl Controller {
}

fn tick(&self) {
// Tick all drivers
self.drivers.tick();

// Tick all driver cloudlets
self.lock_cloudlets().tick();

// Check if all deployments have started there units etc..
self.lock_deployments().tick(&self.units);

Expand Down
2 changes: 1 addition & 1 deletion controller/src/application/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ impl Auth {
token: token.to_string(),
};
let user_path = Storage::get_user_file(username);
if stored_user.save_to_file(&user_path).is_err() {
if stored_user.save_to_file(&user_path, true).is_err() {
error!(
"<red>Failed</> to save user to file: <red>{}</>",
&user_path.display()
Expand Down
15 changes: 13 additions & 2 deletions controller/src/application/cloudlet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,17 @@ impl Cloudlets {
cloudlets
}

pub fn tick(&self) {
for cloudlet in self.cloudlets.values() {
if let Err(error) = cloudlet.get_inner().tick() {
error!(
"<red>Failed</> to tick cloudlet <blue>{}</>: <red>{}</>",
cloudlet.name, error
);
}
}
}

pub fn get_amount(&self) -> usize {
self.cloudlets.len()
}
Expand Down Expand Up @@ -215,7 +226,7 @@ impl Cloudlets {

match self.add_cloudlet(cloudlet) {
Ok(_) => {
stored_cloudlet.save_to_file(&Storage::get_cloudlet_file(name))?;
stored_cloudlet.save_to_file(&Storage::get_cloudlet_file(name), true)?;
info!("<green>Created</> cloudlet <blue>{}</>", name);
Ok(CreationResult::Created)
}
Expand Down Expand Up @@ -393,7 +404,7 @@ impl Cloudlet {
status: self.status.read().unwrap().clone(),
controller: self.controller.clone(),
};
stored_cloudlet.save_to_file(&Storage::get_cloudlet_file(&self.name))
stored_cloudlet.save_to_file(&Storage::get_cloudlet_file(&self.name), true)
}
}

Expand Down
Loading