CA certificate HTTP endpoint for gurtca
This commit is contained in:
98
dns/Cargo.lock
generated
98
dns/Cargo.lock
generated
@@ -1027,6 +1027,30 @@ dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "headers"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"headers-core",
|
||||
"http 0.2.12",
|
||||
"httpdate",
|
||||
"mime",
|
||||
"sha1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "headers-core"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
|
||||
dependencies = [
|
||||
"http 0.2.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
@@ -1462,6 +1486,24 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multer"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-util",
|
||||
"http 0.2.12",
|
||||
"httparse",
|
||||
"log",
|
||||
"memchr",
|
||||
"mime",
|
||||
"spin 0.9.8",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
@@ -1658,6 +1700,26 @@ version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.14"
|
||||
@@ -2098,6 +2160,12 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
@@ -3176,6 +3244,35 @@ dependencies = [
|
||||
"try-lock",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "warp"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"headers",
|
||||
"http 0.2.12",
|
||||
"hyper",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"multer",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"scoped-tls",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
"tokio-util",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
@@ -3330,6 +3427,7 @@ dependencies = [
|
||||
"tokio",
|
||||
"toml",
|
||||
"uuid",
|
||||
"warp",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -30,3 +30,4 @@ sha2 = "0.10"
|
||||
base64 = "0.22"
|
||||
uuid = { version = "1.0", features = ["v4"] }
|
||||
openssl = "0.10"
|
||||
warp = "0.3"
|
||||
|
||||
@@ -9,8 +9,13 @@ use colored::Colorize;
|
||||
use macros_rs::fmt::{crashln, string};
|
||||
use std::{sync::Arc, collections::HashMap};
|
||||
use gurt::prelude::*;
|
||||
use warp::Filter;
|
||||
use gurt::{GurtStatusCode, Route};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CertificateError;
|
||||
impl warp::reject::Reject for CertificateError {}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct AppState {
|
||||
config: Config,
|
||||
@@ -245,8 +250,74 @@ pub async fn start(cli: crate::Cli) -> std::io::Result<()> {
|
||||
.route(Route::get("/ca/certificate/*"), AppHandler { app_state: app_state.clone(), rate_limit_state: None, handler_type: HandlerType::GetCertificate })
|
||||
.route(Route::get("/ca/root"), AppHandler { app_state: app_state.clone(), rate_limit_state: None, handler_type: HandlerType::GetCaCertificate });
|
||||
|
||||
let http_port = 8876;
|
||||
let ca_bootstrap_server = start_ca_bootstrap_server(app_state.clone(), http_port, config.server.address.clone());
|
||||
|
||||
log::info!("Starting CA bootstrap HTTP server on {}:{}", config.server.address, http_port);
|
||||
log::info!("GURT server listening on {}", config.get_address());
|
||||
server.listen(&config.get_address()).await.map_err(|e| {
|
||||
std::io::Error::new(std::io::ErrorKind::Other, format!("GURT server error: {}", e))
|
||||
})
|
||||
|
||||
let result = tokio::try_join!(
|
||||
ca_bootstrap_server,
|
||||
async {
|
||||
server.listen(&config.get_address()).await.map_err(|e| {
|
||||
std::io::Error::new(std::io::ErrorKind::Other, format!("GURT server error: {}", e))
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
match result {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
async fn start_ca_bootstrap_server(app_state: AppState, port: u16, address: String) -> std::result::Result<(), std::io::Error> {
|
||||
let ca_root = warp::path("ca")
|
||||
.and(warp::path("root"))
|
||||
.and(warp::path::end())
|
||||
.and_then({
|
||||
let app_state = app_state.clone();
|
||||
move || {
|
||||
let app_state = app_state.clone();
|
||||
async move {
|
||||
match get_ca_certificate_content(&app_state).await {
|
||||
Ok(cert_pem) => {
|
||||
Ok(warp::reply::with_header(
|
||||
cert_pem,
|
||||
"content-type",
|
||||
"application/x-pem-file"
|
||||
))
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Failed to get CA certificate: {}", e);
|
||||
Err(warp::reject::custom(CertificateError))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let routes = ca_root
|
||||
.with(warp::cors().allow_any_origin().allow_methods(vec!["GET"]));
|
||||
|
||||
let addr: std::net::SocketAddr = format!("{}:{}", address, port).parse()
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
|
||||
|
||||
warp::serve(routes).run(addr).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_ca_certificate_content(app_state: &AppState) -> std::result::Result<String, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let query = "SELECT ca_cert_pem FROM ca_certificates WHERE is_active = TRUE ORDER BY created_at DESC LIMIT 1";
|
||||
let row: std::result::Result<(String,), _> = sqlx::query_as(query)
|
||||
.fetch_one(&app_state.db)
|
||||
.await;
|
||||
|
||||
match row {
|
||||
Ok((ca_cert_pem,)) => Ok(ca_cert_pem),
|
||||
Err(e) => {
|
||||
log::error!("Failed to retrieve CA certificate from database: {}", e);
|
||||
Err(format!("No active CA certificate found in database: {}", e).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
390
flumi/CLAUDE.md
Normal file
390
flumi/CLAUDE.md
Normal file
@@ -0,0 +1,390 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
Gurted is a **browser/wayfinder** for the **GURT protocol** built in Godot 4.4. It renders HTML-like content with CSS-like styling using Godot's UI system and supports a custom utility-class-based styling system similar to Tailwind CSS.
|
||||
|
||||
## Notes
|
||||
- Do not prefix functions or variable names with _ (underscore), those are reserved for event functions.
|
||||
- Do not try to "try" your additions via running Godot, leave that up to me.
|
||||
- Read the codebase to implement the requested change in the most optimal, efficient, and with the least amount of code addition.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Core Components
|
||||
|
||||
- **main.gd** - Main entry point that orchestrates HTML parsing and rendering
|
||||
- **HTMLParser.gd** - Parses HTML content into a tree structure of HTMLElement objects
|
||||
- **CSSParser.gd** - Parses utility-class-based CSS and applies styles to elements
|
||||
- **StyleManager.gd** - Applies parsed styles to Godot UI nodes
|
||||
- **TabContainer.gd** - Manages browser tabs with keyboard shortcuts (Ctrl+T, Ctrl+W, Ctrl+Tab)
|
||||
|
||||
### HTML Element System
|
||||
|
||||
HTML elements are mapped to Godot scene files in `Scenes/Tags/`:
|
||||
- `p.tscn`, `div.tscn`, `span.tscn` for text content
|
||||
- `input.tscn`, `button.tscn`, `select.tscn`, `textarea.tscn` for form elements
|
||||
- `ul.tscn`, `ol.tscn`, `li.tscn` for lists
|
||||
- `img.tscn` for images with network loading support
|
||||
- `br.tscn`, `separator.tscn` for layout elements
|
||||
|
||||
Each has a corresponding `.gd` script in `Scripts/Tags/` that handles initialization and behavior.
|
||||
|
||||
### Styling System
|
||||
|
||||
The project uses a Tailwind-like utility class system:
|
||||
- **Font sizes**: `text-xs` (12px) through `text-6xl` (60px)
|
||||
- **Colors**: `text-[#color]`, `bg-[#color]` for arbitrary colors; named colors like `text-red-500`
|
||||
- **Typography**: `font-bold`, `font-italic`, `underline`, `font-mono`
|
||||
- **Flexbox**: Full flexbox support with `flex`, `justify-center`, `items-center`, etc.
|
||||
- **Sizing**: `w-[value]`, `h-[value]`, `max-w-[value]`, `min-h-[value]`
|
||||
- **Spacing**: `p-4`, `px-4`, `py-2`, `gap-4`
|
||||
- **Border radius**: `rounded`, `rounded-lg`, `rounded-full`, `rounded-[12px]`
|
||||
- **Pseudo-classes**: `hover:bg-blue-500`, `active:bg-red-600`
|
||||
|
||||
### Key Utilities
|
||||
|
||||
- **Utils/ColorUtils.gd** - Color parsing and management
|
||||
- **Utils/SizeUtils.gd** - Size/dimension parsing
|
||||
- **Utils/FlexUtils.gd** - Flexbox property handling
|
||||
- **Utils/SizingUtils.gd** - Size constraint application
|
||||
- **Utils/UtilityClassValidator.gd** - Validates utility class syntax
|
||||
|
||||
### Content System
|
||||
|
||||
HTML content is stored in `Constants.gd` as `HTML_CONTENT` (with several examples). The parser processes this content, applies styles, and renders it using Godot's UI system with FlexContainer nodes for layout.
|
||||
|
||||
## Key Features
|
||||
|
||||
- Tabbed browsing with keyboard shortcuts
|
||||
- Network image loading
|
||||
- Form elements (inputs, selects, textareas, buttons)
|
||||
- Flexbox layout system
|
||||
- Utility-class-based styling
|
||||
- Inline and block element handling
|
||||
- Custom HTML elements like `<separator>`
|
||||
|
||||
## Current Limitations
|
||||
|
||||
- No JavaScript support (planned: Lua scripting)
|
||||
- Limited to basic HTML tags
|
||||
- `<br />` elements cause layout spacing issues
|
||||
- No table support yet
|
||||
- External CSS files not supported
|
||||
- GIF support planned but not implemented
|
||||
|
||||
The codebase follows a clean separation between parsing (HTMLParser), styling (CSSParser/StyleManager), and rendering (main.gd + individual tag scripts).
|
||||
|
||||
# Lua Documentation
|
||||
# GDLuaU Technical Specification
|
||||
|
||||
This document provides a complete technical specification for the GDLuaU plugin. It is intended for developers who want to use the plugin for in-game scripting, modding, or other purposes, and for those who may wish to extend or reimplement its functionality.
|
||||
|
||||
## Table of Contents
|
||||
1. [Overview](#1-overview)
|
||||
2. [Setup and Initialization](#2-setup-and-initialization)
|
||||
3. [Core Classes](#3-core-classes)
|
||||
* [3.1. LuauVM](#31-luauvm)
|
||||
* [3.2. LuauFunction](#32-luaufunction)
|
||||
* [3.3. LuauFunctionResult](#33-luaufunctionresult)
|
||||
4. [LuauVM API Reference](#4-luauvm-api-reference)
|
||||
* [4.1. Properties](#41-properties)
|
||||
* [4.2. Signals](#42-signals)
|
||||
* [4.3. Core Methods](#43-core-methods)
|
||||
* [4.4. Data Exchange API (GDLuau Specific)](#44-data-exchange-api-gdluau-specific)
|
||||
* [4.5. Standard Luau API Bindings](#45-standard-luau-api-bindings)
|
||||
* [4.6. Auxiliary Library (`luaL_`) Bindings](#46-auxiliary-library-lual_-bindings)
|
||||
* [4.7. Constants](#47-constants)
|
||||
5. [Data Type Conversions](#5-data-type-conversions)
|
||||
6. [Luau Environment Features](#6-luau-environment-features)
|
||||
* [6.1. Custom `print` Function](#61-custom-print-function)
|
||||
* [6.2. `vector` Library](#62-vector-library)
|
||||
7. [Limitations & Caveats](#7-limitations--caveats)
|
||||
|
||||
---
|
||||
|
||||
## 1. Overview
|
||||
|
||||
GDLuaU is a GDExtension that integrates the Luau scripting language into Godot. It is primarily designed for user-generated content, in-game scripting, and modding, rather than as a replacement for GDScript.
|
||||
|
||||
The plugin's core philosophy is to expose the comprehensive Luau C API directly within GDScript. This provides a low-level, powerful, and flexible interface for interacting with a Luau virtual machine. It includes features for seamless data marshalling between Godot and Luau, such as pushing and pulling Godot Objects, Arrays, Dictionaries, and other core types.
|
||||
|
||||
**Key Features**:
|
||||
* A `LuauVM` node that encapsulates a `lua_State`.
|
||||
* Direct bindings to the majority of the Luau 5.1 C API.
|
||||
* Automatic conversion between Godot's `Variant` types and Luau's native types.
|
||||
* Support for pushing Godot `Object`s (like Nodes and RefCounted) to Luau as userdata.
|
||||
* Support for pushing Godot `Callable`s to Luau as functions.
|
||||
* A custom `print` implementation in Luau that emits a Godot signal.
|
||||
* A configurable interrupt signal to prevent and handle runaway scripts.
|
||||
* A built-in `vector` library in Luau for working with Godot's vector types.
|
||||
|
||||
---
|
||||
|
||||
## 2. Setup and Initialization
|
||||
|
||||
To use GDLuaU, you must first add a `LuauVM` node to your scene. This node represents a single, isolated Luau virtual machine.
|
||||
|
||||
Once the node is in the scene tree, you need to initialize its environment by loading the standard Luau libraries. This is typically done in the `_ready` function of a parent script.
|
||||
|
||||
**Example (GDScript):**
|
||||
```gdscript
|
||||
extends Node
|
||||
|
||||
@onready var vm: LuauVM = $LuauVM
|
||||
|
||||
func _ready():
|
||||
# Load all standard libraries (base, table, string, math, etc.)
|
||||
vm.open_all_libraries()
|
||||
|
||||
# Now the VM is ready to execute code
|
||||
var result = vm.lua_dostring("print('Hello from Luau!')")
|
||||
if result != vm.LUA_OK:
|
||||
# Handle error
|
||||
var error_message = vm.lua_tostring(-1)
|
||||
print("Luau Error: ", error_message)
|
||||
vm.lua_pop(1)
|
||||
```
|
||||
|
||||
**File Structure:**
|
||||
The plugin expects a specific file structure within your Godot project, which is set up by default when installed:
|
||||
```
|
||||
project/
|
||||
└── addons/
|
||||
└── gdluau/
|
||||
├── bin/
|
||||
│ ├── <platform>/
|
||||
│ │ └── <library_files>
|
||||
└── gdluau.gdextension
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Core Classes
|
||||
|
||||
The plugin registers three main classes with Godot's `ClassDB`.
|
||||
|
||||
### 3.1. LuauVM
|
||||
|
||||
This is the central class of the plugin. It inherits from `Node` and represents a single Luau VM instance (`lua_State`). All interactions with Luau, from running code to manipulating the stack, are done through methods on a `LuauVM` object.
|
||||
|
||||
### 3.2. LuauFunction
|
||||
|
||||
This class represents a reference to a Luau function within GDScript. It inherits from `RefCounted`. You can obtain a `LuauFunction` object by calling `LuauVM.lua_tofunction()` on a function value on the stack. Its primary purpose is to allow you to call Luau functions from GDScript in a safe and convenient way.
|
||||
|
||||
**GDScript Example:**
|
||||
```gdscript
|
||||
# Assume a Luau function 'add' has been defined and pushed to the stack
|
||||
vm.lua_getglobal("add")
|
||||
var luau_add_func: LuauFunction = vm.lua_tofunction(-1)
|
||||
vm.lua_pop(1) # Pop the function from the stack
|
||||
|
||||
# Now call it from GDScript
|
||||
var result: LuauFunctionResult = luau_add_func.pcall(5, 7)
|
||||
if not result.is_error():
|
||||
print("Result from Luau: ", result.get_tuple()[0]) # Output: 12
|
||||
```
|
||||
|
||||
### 3.3. LuauFunctionResult
|
||||
|
||||
This `RefCounted` class acts as a container for the results of a protected call (`pcall`) made to a `LuauFunction`. A protected call will not crash the application on an error. Instead, the `LuauFunctionResult` will indicate whether an error occurred.
|
||||
|
||||
* If the call was successful, `is_error()` returns `false`, and `get_tuple()` returns an `Array` containing all the values returned by the Luau function.
|
||||
* If an error occurred, `is_error()` returns `true`, and `get_error()` returns the error message as a `String`.
|
||||
|
||||
---
|
||||
|
||||
## 4. LuauVM API Reference
|
||||
|
||||
This section details the properties, signals, and methods exposed by the `LuauVM` class.
|
||||
|
||||
### 4.1. Properties
|
||||
|
||||
* **`interrupt_cooldown`**: `float` (default: `0.1`)
|
||||
* **Description**: The minimum time in seconds between emissions of the `interrupt` signal. This is used to prevent the signal from firing too frequently in a tight loop, which could cause performance issues.
|
||||
|
||||
### 4.2. Signals
|
||||
|
||||
* **`stdout(message: String)`**
|
||||
* **Description**: Emitted when the `print()` function is called within the Luau environment. The arguments passed to `print()` are concatenated and sent as a single string.
|
||||
* **`interrupt()`**
|
||||
* **Description**: Emitted periodically during Luau script execution. This signal can be used to terminate runaway scripts (e.g., `while true do end`). You can connect a function to this signal to check for conditions (like a timeout) and call `lua_error()` to stop the script.
|
||||
|
||||
**Example: Handling Runaway Scripts**
|
||||
```gdscript
|
||||
const MAX_EXECUTION_TIME = 2.0
|
||||
var start_time = 0.0
|
||||
|
||||
func _ready():
|
||||
vm.interrupt.connect(_on_vm_interrupt)
|
||||
|
||||
func _on_vm_interrupt():
|
||||
if Time.get_ticks_msec() / 1000.0 - start_time > MAX_EXECUTION_TIME:
|
||||
# This will stop the script and trigger an error state
|
||||
vm.luaL_error("Execution timed out")
|
||||
|
||||
func run_script():
|
||||
start_time = Time.get_ticks_msec() / 1000.0
|
||||
# This script would otherwise run forever
|
||||
var result = vm.lua_dostring("while true do end")
|
||||
if result != vm.LUA_OK:
|
||||
print("Script stopped: ", vm.lua_tostring(-1))
|
||||
vm.lua_pop(1)
|
||||
```
|
||||
|
||||
### 4.3. Core Methods
|
||||
|
||||
These methods provide high-level control over the VM.
|
||||
|
||||
* **`open_all_libraries()`**
|
||||
* Loads all standard Luau libraries into the VM state. This includes `base`, `coroutine`, `table`, `os`, `string`, `math`, `vector`, `debug`, `utf8`, and `bit32`.
|
||||
* **`open_libraries(libraries: PackedByteArray)`**
|
||||
* Loads a specific set of libraries. The `libraries` array should contain integers corresponding to the `lua_Lib` enum (e.g., `[vm.LUA_BASE_LIB, vm.LUA_TABLE_LIB]`).
|
||||
* **`load_string(code: String, chunkname: String = "loadstring") -> int`**
|
||||
* Compiles a string of Luau code and pushes the resulting function onto the stack. It does not execute the code. Returns a `lua_Status` code (`LUA_OK` on success).
|
||||
* **`do_string(code: String, chunkname: String = "dostring") -> int`**
|
||||
* Compiles and immediately executes a string of Luau code. This is equivalent to `load_string` followed by `lua_pcall`. Returns a `lua_Status` code (`LUA_OK` on success). If an error occurs, the error message is pushed onto the stack.
|
||||
|
||||
### 4.4. Data Exchange API (GDLuau Specific)
|
||||
|
||||
These functions are custom helpers for moving data between Godot and Luau.
|
||||
|
||||
* `lua_pushvariant(var: Variant)`: Pushes any supported Godot `Variant` onto the stack. See [Data Type Conversions](#5-data-type-conversions).
|
||||
* `lua_pusharray(arr: Array)`: Pushes a Godot `Array` as a new Luau table.
|
||||
* `lua_pushdictionary(dict: Dictionary)`: Pushes a Godot `Dictionary` as a new Luau table.
|
||||
* `lua_pushobject(object: Object)`: Pushes a Godot `Object` (e.g., a `Node` or `RefCounted`) as Luau userdata. The object's lifetime is managed via reference counting for `RefCounted` types.
|
||||
* `lua_pushcallable(func: Callable, debugname: String = "") -> Error`: Pushes a Godot `Callable` as a Luau function. **Note**: Lambda (custom) callables are not supported.
|
||||
* `lua_tovariant(index: int) -> Variant`: Pops a value from the stack at `index` and converts it to a Godot `Variant`.
|
||||
* `lua_toarray(index: int) -> Array`: Converts a Luau table at `index` into a Godot `Array`.
|
||||
* `lua_todictionary(index: int) -> Dictionary`: Converts a Luau table at `index` into a Godot `Dictionary`.
|
||||
* `lua_tofunction(index: int) -> LuauFunction`: Creates a `LuauFunction` reference to the Luau function at `index`.
|
||||
* `lua_toobject(index: int) -> Object`: Converts Luau userdata at `index` back into a Godot `Object`. Returns `null` if the value is not a valid object userdata.
|
||||
* `lua_isobject(index: int) -> bool`: Checks if the value at `index` is a userdata representing a Godot `Object`.
|
||||
* `lua_isvalidobject(index: int) -> bool`: Checks if the userdata at `index` points to a valid (not freed) Godot `Object`.
|
||||
|
||||
**Example: Pushing and Getting a Node**
|
||||
```gdscript
|
||||
# GDScript
|
||||
func _ready():
|
||||
vm.open_all_libraries()
|
||||
# Push this node as a global variable 'player' in Luau
|
||||
vm.lua_pushobject(self)
|
||||
vm.lua_setglobal("player")
|
||||
|
||||
vm.lua_dostring("print(player)")
|
||||
``````lua
|
||||
-- LuaU
|
||||
-- Assuming the above GDScript ran, 'player' is a userdata
|
||||
-- representing the Godot node.
|
||||
print(player) -- Outputs something like: [Node:12345]
|
||||
```
|
||||
|
||||
### 4.5. Standard Luau API Bindings
|
||||
|
||||
The plugin exposes a vast portion of the standard Luau C API as methods on the `LuauVM` object. The function signatures are adapted for GDScript (e.g., C strings become Godot `String`s, integers become `int`).
|
||||
|
||||
For a detailed explanation of what each function does, please refer to the [Lua 5.1 Manual](https://www.lua.org/manual/5.1/manual.html#3), as Luau's API is based on it.
|
||||
|
||||
**Partial List of Bound Functions:**
|
||||
* **Stack Manipulation**: `lua_gettop`, `lua_settop`, `lua_pushvalue`, `lua_pop`, `lua_remove`, `lua_insert`, `lua_replace`, `lua_concat`.
|
||||
* **Pushing Primitives**: `lua_pushnil`, `lua_pushboolean`, `lua_pushinteger`, `lua_pushnumber`, `lua_pushstring`.
|
||||
* **Checking Types**: `lua_isboolean`, `lua_isfunction`, `lua_isnil`, `lua_isnone`, `lua_isnumber`, `lua_isstring`, `lua_istable`, `lua_isuserdata`, `lua_isvector`, `lua_type`, `lua_typename`.
|
||||
* **Accessing Values**: `lua_toboolean`, `lua_tointeger`, `lua_tonumber`, `lua_tostring`, `lua_tovector`, `lua_objlen`.
|
||||
* **Table Operations**: `lua_newtable`, `lua_createtable`, `lua_getfield`, `lua_setfield`, `lua_gettable`, `lua_settable`, `lua_rawget`, `lua_rawset`, `lua_rawgeti`, `lua_rawseti`.
|
||||
* **Execution**: `lua_call`, `lua_pcall`.
|
||||
* **Globals**: `lua_getglobal`, `lua_setglobal`.
|
||||
* **Metatables**: `lua_getmetatable`, `lua_setmetatable`.
|
||||
* **References**: `lua_ref`, `lua_unref`, `lua_getref`. (These are aliases for `luaL_ref`, etc.)
|
||||
* **Garbage Collection**: `lua_gc`.
|
||||
|
||||
### 4.6. Auxiliary Library (`luaL_`) Bindings
|
||||
|
||||
The auxiliary library provides higher-level helper functions.
|
||||
|
||||
* **Metatable Helpers**: `luaL_newmetatable`, `luaL_getmetatable`, `luaL_callmeta`, `luaL_getmetafield`, `luaL_hasmetatable`.
|
||||
* **Error Handling and Argument Checking**: `luaL_error`, `luaL_argcheck`, `luaL_checkany`, `luaL_checkint`, `luaL_checknumber`, `luaL_checkstring`, `luaL_checkvector`, `luaL_checkobject`, `luaL_checktype`, `luaL_where`, `luaL_typerror`.
|
||||
* **Other**: `luaL_checkstack`, `luaL_checkoption`.
|
||||
|
||||
### 4.7. Constants
|
||||
|
||||
The plugin binds many of Luau's internal constants as enums on the `LuauVM` class, allowing for type-safe usage in GDScript.
|
||||
|
||||
* **`lua_Status`**: `LUA_OK`, `LUA_YIELD`, `LUA_ERRRUN`, `LUA_ERRSYNTAX`, etc.
|
||||
* **`lua_Type`**: `LUA_TNIL`, `LUA_TBOOLEAN`, `LUA_TNUMBER`, `LUA_TSTRING`, `LUA_TTABLE`, etc.
|
||||
* **`lua_Lib`**: `LUA_BASE_LIB`, `LUA_TABLE_LIB`, `LUA_STRING_LIB`, etc.
|
||||
* **`lua_GCOp`**: `LUA_GCCOLLECT`, `LUA_GCSTOP`, `LUA_GCRESTART`, `LUA_GCCOUNT`, etc.
|
||||
* **Special Indices**: `LUA_REGISTRYINDEX`, `LUA_GLOBALSINDEX`.
|
||||
* **Other**: `LUA_MULTRET`, `LUA_REFNIL`, `LUA_NOREF`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Data Type Conversions
|
||||
|
||||
The following table summarizes how data types are marshaled between GDScript (`Variant`) and Luau.
|
||||
|
||||
| GDScript Type | Luau Type | Notes |
|
||||
| :--- | :--- | :--- |
|
||||
| `Nil` | `nil` | |
|
||||
| `bool` | `boolean` | |
|
||||
| `int` | `number` (integer) | |
|
||||
| `float` | `number` (double) | |
|
||||
| `String` | `string` | |
|
||||
| `PackedByteArray` | *Not directly supported* | |
|
||||
| `Array` | `table` (array-like) | A new table with integer keys starting from 1. |
|
||||
| `Dictionary` | `table` (dictionary-like) | Keys and values are converted recursively. |
|
||||
| `Vector2`, `Vector2i` | `vector` | Converted to a Luau vector. `z` and `w` are 0. |
|
||||
| `Vector3`, `Vector3i` | `vector` | Converted to a Luau vector. `w` is 0. |
|
||||
| `Vector4`, `Vector4i` | `vector` | |
|
||||
| `Object` | `userdata` | A special userdata that holds the object's instance ID. |
|
||||
| `Callable` | `function` | A C-closure is created in Luau that calls the Godot Callable. |
|
||||
| `LuauFunction` | `function` | Pushing is not supported; obtained via `lua_tofunction`. |
|
||||
|
||||
---
|
||||
|
||||
## 6. Luau Environment Features
|
||||
|
||||
### 6.1. Custom `print` Function
|
||||
|
||||
The global `print` function in Luau is overridden. Instead of printing to the standard console output, it concatenates all its arguments into a single string and emits the `stdout` signal on the `LuauVM` node.
|
||||
|
||||
**LuaU Example:**
|
||||
```lua
|
||||
print("Player health:", 100, "Mana:", 50)
|
||||
```
|
||||
|
||||
**GDScript Receiver:**
|
||||
```gdscript
|
||||
func _on_vm_stdout(message: String):
|
||||
# message will be "Player health: 100 Mana: 50"
|
||||
print("Message from Luau VM: ", message)
|
||||
```
|
||||
|
||||
### 6.2. `vector` Library
|
||||
|
||||
GDLuaU includes a custom `vector` library that is automatically loaded with `open_all_libraries`. This library allows Luau scripts to create and interact with vector types that are compatible with Godot's `Vector2/3/4`.
|
||||
|
||||
* **Constructor**: `vector(x: number, y: number, z: number, w: number)`
|
||||
* Creates a new vector. You can omit arguments; they will default to 0.
|
||||
* **Indexing**: Vectors can be indexed with numbers `1` through `4` to get the `x`, `y`, `z`, and `w` components respectively.
|
||||
* **`__tostring`**: Printing a vector will produce a human-readable string (e.g., `"1.0, 2.0, 3.0, 0.0"`).
|
||||
|
||||
**LuaU Example:**
|
||||
```lua
|
||||
local pos = vector(10, 25.5) -- Creates a vector(10, 25.5, 0, 0)
|
||||
local dir = vector(0, -1)
|
||||
local new_pos = pos + dir -- Vector math is supported
|
||||
print(new_pos) -- Outputs "10.0, 24.5, 0.0, 0.0"
|
||||
|
||||
-- Accessing components
|
||||
print("X component:", new_pos[1]) -- Outputs "X component: 10.0"```
|
||||
|
||||
---
|
||||
|
||||
## 7. Limitations & Caveats
|
||||
|
||||
* **Performance**: While Luau is highly performant, frequent and heavy data marshalling between Godot and Luau (e.g., converting large arrays/dictionaries every frame) can introduce overhead.
|
||||
* **Userdata**: The plugin does not expose the raw `userdata` or `lightuserdata` C API. Godot `Object`s are the only supported form of userdata, which are handled automatically.
|
||||
* **Memory Management**: The `LuauVM` uses Godot's memory functions (`memalloc`, `memfree`). Memory usage can be monitored with `lua_gc(LUA_GCCOUNT, 0)`. Be mindful of creating too many references between Godot and Luau that could lead to memory leaks if not managed correctly.
|
||||
* **Threading**: A `LuauVM` instance (`lua_State`) is not thread-safe. All interactions with a single VM must be done from the same thread.
|
||||
Binary file not shown.
Binary file not shown.
@@ -17,4 +17,5 @@ openssl = "0.10"
|
||||
base64 = "0.22"
|
||||
anyhow = "1.0"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
uuid = { version = "1.0", features = ["v4"] }
|
||||
uuid = { version = "1.0", features = ["v4"] }
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
@@ -144,4 +144,49 @@ impl GurtCAClient {
|
||||
|
||||
anyhow::bail!("Certificate issuance timed out")
|
||||
}
|
||||
|
||||
pub async fn fetch_ca_certificate(&self) -> Result<String> {
|
||||
if let Ok(ca_cert) = self.fetch_ca_via_http().await {
|
||||
return Ok(ca_cert);
|
||||
}
|
||||
|
||||
let response = self.gurt_client
|
||||
.get(&format!("{}/ca/root", self.ca_url))
|
||||
.await?;
|
||||
|
||||
if response.is_success() {
|
||||
let ca_cert = response.text()?;
|
||||
if ca_cert.contains("BEGIN CERTIFICATE") && ca_cert.contains("END CERTIFICATE") {
|
||||
Ok(ca_cert)
|
||||
} else {
|
||||
anyhow::bail!("Invalid CA certificate format received")
|
||||
}
|
||||
} else {
|
||||
anyhow::bail!("Failed to fetch CA certificate: HTTP {}", response.status_code)
|
||||
}
|
||||
}
|
||||
|
||||
async fn fetch_ca_via_http(&self) -> Result<String> {
|
||||
let http_url = self.ca_url
|
||||
.replace("gurt://", "http://")
|
||||
.replace(":8877", ":8876");
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let response = client
|
||||
.get(&format!("{}/ca/root", http_url))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
if response.status().is_success() {
|
||||
let ca_cert = response.text().await?;
|
||||
if ca_cert.contains("BEGIN CERTIFICATE") && ca_cert.contains("END CERTIFICATE") {
|
||||
println!("✅ Fetched CA certificate via HTTP bootstrap");
|
||||
Ok(ca_cert)
|
||||
} else {
|
||||
anyhow::bail!("Invalid CA certificate format received via HTTP")
|
||||
}
|
||||
} else {
|
||||
anyhow::bail!("HTTP bootstrap failed: {}", response.status())
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user