网页开发
Valkyrie 提供了现代化的网页开发框架,支持服务端渲染、客户端应用、WebAssembly 集成、实时通信等功能,为构建高性能 Web 应用提供完整的解决方案。
Web 服务器框架
HTTP 服务器
valkyrie
# HTTP 服务器核心
class WebServer {
router: Router,
middleware_stack: Vector<Box<dyn Middleware>>,
config: ServerConfig,
thread_pool: ThreadPool,
}
class ServerConfig {
host: String,
port: u16,
max_connections: usize,
request_timeout: Duration,
static_files_dir: Option<String>,
enable_compression: bool,
}
imply WebServer {
new(config: ServerConfig) -> Self {
WebServer {
router: Router::new(),
middleware_stack: Vec::new(),
config,
thread_pool: ThreadPool::new(num_cpus::get()),
}
}
route(&mut self, method: HttpMethod, path: &str, handler: imply Handler) {
self.router.add_route(method, path, Box::new(handler))
}
get(&mut self, path: &str, handler: imply Handler) {
self.route(HttpMethod::GET, path, handler)
}
post(&mut self, path: &str, handler: imply Handler) {
self.route(HttpMethod::POST, path, handler)
}
put(&mut self, path: &str, handler: imply Handler) {
self.route(HttpMethod::PUT, path, handler)
}
delete(&mut self, path: &str, handler: imply Handler) {
self.route(HttpMethod::DELETE, path, handler)
}
use_middleware(&mut self, middleware: imply Middleware) {
self.middleware_stack.push(Box::new(middleware))
}
serve_static(&mut self, path: &str, dir: &str) {
let static_handler = StaticFileHandler::new(dir)
self.get(&@format("{}/*", path), static_handler)
}
async micro listen(&self) -> Result<(), ServerError> {
let addr = @format("{}:{}", self.config.host, self.config.port)
let listener = TcpListener::bind(&addr).await?
@println("Server listening on http://{}", addr)
loop {
let (stream, _) = listener.accept().await?
let router = self.router.clone()
let middleware = self.middleware_stack.clone()
self.thread_pool.spawn(async move {
if let Err(e) = handle_connection(stream, router, middleware).await {
@eprintln("Error handling connection: {}", e)
}
})
}
}
}
# 请求处理
async micro handle_connection(
mut stream: TcpStream,
router: Router,
middleware: Vector<Box<dyn Middleware>>
) -> Result<(), Box<dyn std::error::Error>> {
let mut buffer = [0; 1024]
stream.read(&mut buffer).await?
let request = HttpRequest::parse(&buffer)?
let mut context = RequestContext::new(request)
# 执行中间件链
for middleware in &middleware {
middleware.process(&mut context).await?
if context.response.is_some() {
break
}
}
# 如果中间件没有生成响应,则路由到处理器
if context.response.is_none() {
if let Some(handler) = router.find_handler(&context.request) {
let response = handler.handle(&context.request).await?
context.response = Some(response)
} else {
context.response = Some(HttpResponse::not_found())
}
}
# 发送响应
if let Some(response) = context.response {
let response_bytes = response.to_bytes()
stream.write_all(&response_bytes).await?
}
Ok(())
}路由系统
valkyrie
# 路由器
class Router {
routes: Vector<Route>,
groups: Vector<RouteGroup>,
}
class Route {
method: HttpMethod,
pattern: PathPattern,
handler: Box<dyn Handler>,
middleware: Vector<Box<dyn Middleware>>,
}
class RouteGroup {
prefix: String,
routes: Vector<Route>,
middleware: Vector<Box<dyn Middleware>>,
}
enum PathPattern {
Static(String),
Dynamic(String, Vector<String>), # 模式和参数名
Wildcard(String),
}
imply Router {
new() -> Self {
Router {
routes: Vec::new(),
groups: Vec::new(),
}
}
add_route(&mut self, method: HttpMethod, path: &str, handler: Box<dyn Handler>) {
let pattern = PathPattern::parse(path)
let route = Route {
method,
pattern,
handler,
middleware: Vec::new(),
}
self.routes.push(route)
}
group(&mut self, prefix: &str) -> RouteGroupBuilder {
RouteGroupBuilder::new(prefix, self)
}
find_handler(&self, request: &HttpRequest) -> Option<&dyn Handler> {
# 首先检查路由组
for group in &self.groups {
if request.path.starts_with(&group.prefix) {
let sub_path = &request.path[group.prefix.len()..]
for route in &group.routes {
if route.method == request.method && route.pattern.matches(sub_path) {
return Some(route.handler.as_ref())
}
}
}
}
# 然后检查全局路由
for route in &self.routes {
if route.method == request.method && route.pattern.matches(&request.path) {
return Some(route.handler.as_ref())
}
}
None
}
}
imply PathPattern {
parse(path: &str) -> Self {
if path.contains(':') {
let mut params = Vec::new()
let pattern = path.split('/').map(|segment| {
if segment.starts_with(':') {
params.push(segment[1..])
"([^/]+)"
} else {
regex::escape(segment)
}
}).collect::<Vector<_>>().join("/")
PathPattern::Dynamic(pattern, params)
} else if path.ends_with("*") {
PathPattern::Wildcard(path[..path.len()-1])
} else {
PathPattern::Static(path)
}
}
matches(&self, path: &str) -> bool {
match self {
PathPattern::Static(pattern) => pattern == path,
PathPattern::Dynamic(pattern, _) => {
let regex = Regex::new(pattern).unwrap()
regex.is_match(path)
},
PathPattern::Wildcard(prefix) => path.starts_with(prefix),
}
}
extract_params(&self, path: &str) -> HashMap<String, String> {
let mut params = HashMap::new()
if let PathPattern::Dynamic(pattern, param_names) = self {
let regex = Regex::new(pattern).unwrap()
if let Some(captures) = regex.captures(path) {
for (i, name) in param_names.iter().enumerate() {
if let Some(value) = captures.get(i + 1) {
params.insert(name.clone(), value.as_str())
}
}
}
}
params
}
}请求和响应处理
valkyrie
# HTTP 请求
class HttpRequest {
method: HttpMethod
path: String
query_params: HashMap<String, String>
headers: HashMap<String, String>
body: Vector<u8>
params: HashMap<String, String> # 路由参数
}
↯[derive(Clone, PartialEq)]
union HttpMethod {
GET,
POST,
PUT,
DELETE,
PATCH,
HEAD,
OPTIONS,
}
imply HttpRequest {
parse(buffer: &[u8]) -> Result<Self, ParseError> {
let request_str = String::from_utf8_lossy(buffer)
let lines: Vector<&str> = request_str.lines().collect()
if lines.is_empty() {
return Err(ParseError::InvalidRequest)
}
# 解析请求行
let request_line_parts: Vector<&str> = lines[0].split_whitespace().collect()
if request_line_parts.len() < 3 {
return Err(ParseError::InvalidRequestLine)
}
let method = HttpMethod::from_str(request_line_parts[0])?
let url_parts: Vector<&str> = request_line_parts[1].splitn(2, '?').collect()
let path = url_parts[0]
# 解析查询参数
let query_params = if url_parts.len() > 1 {
parse_query_string(url_parts[1])
} else {
HashMap::new()
}
# 解析头部
let mut headers = HashMap::new()
let mut body_start = 1
for (i, line) in lines.iter().enumerate().skip(1) {
if line.is_empty() {
body_start = i + 1
break
}
if let Some(colon_pos) = line.find(':') {
let key = line[..colon_pos].trim().to_lowercase()
let value = line[colon_pos + 1..].trim()
headers.insert(key, value)
}
}
# 解析请求体
let body = if body_start < lines.len() {
lines[body_start..].join("\n").into_bytes()
} else {
Vec::new()
}
Ok(HttpRequest {
method,
path,
query_params,
headers,
body,
params: HashMap::new(),
})
}
get_header(&self, name: &str) -> Option<&String> {
self.headers.get(&name.to_lowercase())
}
get_param(&self, name: &str) -> Option<&String> {
self.params.get(name)
}
get_query(&self, name: &str) -> Option<&String> {
self.query_params.get(name)
}
json<T: DeEncodeOwned>(&self) -> Result<T, serde_json::Error> {
serde_json::from_slice(&self.body)
}
form_data(&self) -> HashMap<String, String> {
if let Some(content_type) = self.get_header("content-type") {
if content_type.contains("application/x-www-form-urlencoded") {
let body_str = String::from_utf8_lossy(&self.body)
return parse_query_string(&body_str)
}
}
HashMap::new()
}
}
# HTTP 响应
class HttpResponse {
status_code: u16
status_text: String
headers: HashMap<String, String>
body: Vector<u8>
}
imply HttpResponse {
new(status_code: u16) -> Self {
let status_text = match status_code {
200 => "OK",
201 => "Created",
400 => "Bad Request",
401 => "Unauthorized",
403 => "Forbidden",
404 => "Not Found",
500 => "Internal Server Error",
_ => "Unknown",
}
HttpResponse {
status_code,
status_text,
headers: HashMap::new(),
body: Vec::new(),
}
}
ok() -> Self {
Self::new(200)
}
created() -> Self {
Self::new(201)
}
bad_request() -> Self {
Self::new(400)
}
not_found() -> Self {
Self::new(404)
}
internal_error() -> Self {
Self::new(500)
}
with_header(mut self, name: &str, value: &str) -> Self {
self.headers.insert(name, value)
self
}
with_json<T: Encode>(mut self, data: &T) -> Result<Self, serde_json::Error> {
let json_str = serde_json::to_string(data)?
self.body = json_str.into_bytes()
self.headers.insert("Content-Type", "application/json")
Ok(self)
}
with_html(mut self, html: &str) -> Self {
self.body = html.as_bytes().to_vec()
self.headers.insert("Content-Type", "text/html; charset=utf-8")
self
}
with_text(mut self, text: &str) -> Self {
self.body = text.as_bytes().to_vec()
self.headers.insert("Content-Type", "text/plain; charset=utf-8")
self
}
redirect(location: &str) -> Self {
Self::new(302).with_header("Location", location)
}
to_bytes(&self) -> Vector<u8> {
let mut response = @format(
"HTTP/1.1 {} {}\r\n",
self.status_code,
self.status_text
)
# 添加头部
for (key, value) in &self.headers {
response.push_str(&@format("{}:{}\r\n", key, value))
}
# 添加 Content-Length
response.push_str(&@format("Content-Length: {}\r\n", self.body.len()))
response.push_str("\r\n")
let mut bytes = response.into_bytes()
bytes.extend_from_slice(&self.body)
bytes
}
}中间件系统
中间件接口
valkyrie
# 中间件特征
trait Middleware: Send + Sync {
async micro process(&self, context: &mut RequestContext) -> Result<(), MiddlewareError>
}
class RequestContext {
request: HttpRequest
response: Option<HttpResponse>
data: HashMap<String, Box<dyn Any + Send + Sync>>
}
imply RequestContext {
new(request: HttpRequest) -> Self {
RequestContext {
request,
response: None,
data: HashMap::new(),
}
}
set_data<T: Any + Send + Sync>(&mut self, key: &str, value: T) {
self.data.insert(key, Box::new(value))
}
get_data<T: Any + Send + Sync>(&self, key: &str) -> Option<&T> {
self.data.get(key)?.downcast_ref::<T>()
}
}
# 日志中间件
class LoggingMiddleware {
format: String
}
imply LoggingMiddleware {
new() -> Self {
LoggingMiddleware {
format: "{method} {path} - {status} ({duration}ms)",
}
}
}
imply Middleware for LoggingMiddleware {
async micro process(&self, context: &mut RequestContext) -> Result<(), MiddlewareError> {
let start_time = std::time::Instant::now()
# 记录请求开始
@println("[{}] {} {}",
chrono::Utc::now().format("%Y-%m-%d %H:%M:%S"),
context.request.method.as_str(),
context.request.path
)
# 在响应数据中存储开始时间
context.set_data("start_time", start_time)
Ok(())
}
}
# CORS 中间件
class CorsMiddleware {
allowed_origins: Vector<String>
allowed_methods: Vector<HttpMethod>
allowed_headers: Vector<String>
max_age: u32
}
imply CorsMiddleware {
new() -> Self {
CorsMiddleware {
allowed_origins: vec!["*"],
allowed_methods: vec![HttpMethod::GET, HttpMethod::POST, HttpMethod::PUT, HttpMethod::DELETE],
allowed_headers: vec!["Content-Type", "Authorization"],
max_age: 86400,
}
}
allow_origin(mut self, origin: &str) -> Self {
self.allowed_origins = vec![origin]
self
}
allow_methods(mut self, methods: Vector<HttpMethod>) -> Self {
self.allowed_methods = methods
self
}
}
imply Middleware for CorsMiddleware {
async micro process(&self, context: &mut RequestContext) -> Result<(), MiddlewareError> {
# 处理预检请求
if context.request.method == HttpMethod::OPTIONS {
let response = HttpResponse::ok()
.with_header("Access-Control-Allow-Origin", &self.allowed_origins.join(", "))
.with_header("Access-Control-Allow-Methods",
&self.allowed_methods.iter().map(|m| m.as_str()).collect::<Vector<_>>().join(", "))
.with_header("Access-Control-Allow-Headers", &self.allowed_headers.join(", "))
.with_header("Access-Control-Max-Age", &self.max_age)
context.response = Some(response)
return Ok(())
}
# 为其他请求添加 CORS 头
if let Some(ref mut response) = context.response {
response.headers.insert("Access-Control-Allow-Origin",
self.allowed_origins.join(", "))
}
Ok(())
}
}
# 认证中间件
class AuthMiddleware {
secret_key: String,
protected_paths: Vector<String>,
}
imply AuthMiddleware {
new(secret_key: &str) -> Self {
AuthMiddleware {
secret_key: secret_key,
protected_paths: Vec::new(),
}
}
protect_path(mut self, path: &str) -> Self {
self.protected_paths.push(path)
self
}
verify_token(&self, token: &str) -> Result<Claims, AuthError> {
# JWT 令牌验证逻辑
jwt::decode::<Claims>(
token,
&DecodingKey::from_secret(self.secret_key.as_ref()),
&Validation::default()
).map(|data| data.claims)
.map_err(|_| AuthError::InvalidToken)
}
}
imply Middleware for AuthMiddleware {
async micro process(&self, context: &mut RequestContext) -> Result<(), MiddlewareError> {
# 检查路径是否需要保护
let needs_auth = self.protected_paths.iter()
.any(|path| context.request.path.starts_with(path))
if !needs_auth {
return Ok(())
}
# 提取认证令牌
let token = context.request.get_header("authorization")
.and_then(|auth| auth.strip_prefix("Bearer "))
.ok_or(MiddlewareError::Unauthorized)?;
# 验证令牌
match self.verify_token(token) {
Ok(claims) => {
context.set_data("user_claims", claims)
Ok(())
},
Err(_) => {
context.response = Some(HttpResponse::new(401).with_text("Unauthorized"))
Ok(())
}
}
}
}模板引擎
HTML 模板系统
valkyrie
# 模板引擎
class TemplateEngine {
templates: HashMap<String, Template>,
template_dir: String,
cache_enabled: bool,
}
class Template {
name: String,
content: String,
compiled: CompiledTemplate,
}
class CompiledTemplate {
blocks: Vector<TemplateBlock>,
}
enum TemplateBlock {
Text(String),
Variable(String),
Loop {
variable: String,
items: String,
body: Vector<TemplateBlock>,
},
Condition {
expression: String,
then_body: Vector<TemplateBlock>,
else_body: Option<Vector<TemplateBlock>>,
},
Include(String),
}
imply TemplateEngine {
new(template_dir: &str) -> Self {
TemplateEngine {
templates: HashMap::new(),
template_dir: template_dir,
cache_enabled: true,
}
}
load_template(&mut self, name: &str) -> Result<(), TemplateError> {
let path = @format("{}/{}.html", self.template_dir, name)
let content = std::fs::read_to_string(&path)
.map_err(|_| TemplateError::TemplateNotFound(name))?;
let compiled = self.compile_template(&content)?;
let template = Template {
name: name,
content,
compiled,
}
self.templates.insert(name, template)
Ok(())
}
render(&mut self, name: &str, context: &TemplateContext) -> Result<String, TemplateError> {
if !self.templates.contains_key(name) {
self.load_template(name)?
}
let template = self.templates.get(name).unwrap()
self.render_blocks(&template.compiled.blocks, context)
}
compile_template(&self, content: &str) -> Result<CompiledTemplate, TemplateError> {
let mut blocks = Vec::new()
let mut chars = content.chars().peekable()
let mut current_text = String::new()
while let Some(ch) = chars.next() {
if ch == '{' && chars.peek() == Some(&'{') {
chars.next() # 消费第二个 '{'
# 保存当前文本块
if !current_text.is_empty() {
blocks.push(TemplateBlock::Text(current_text.clone()))
current_text.clear()
}
# 解析模板表达式
let mut expression = String::new()
let mut brace_count = 0
while let Some(ch) = chars.next() {
if ch == '}' && chars.peek() == Some(&'}') && brace_count == 0 {
chars.next() # 消费第二个 '}'
break
}
if ch == '{' { brace_count += 1 }
if ch == '}' { brace_count -= 1 }
expression.push(ch)
}
# 解析表达式类型
let block = self.parse_expression(&expression.trim())?;
blocks.push(block)
} else {
current_text.push(ch)
}
}
# 添加最后的文本块
if !current_text.is_empty() {
blocks.push(TemplateBlock::Text(current_text))
}
Ok(CompiledTemplate { blocks })
}
parse_expression(&self, expr: &str) -> Result<TemplateBlock, TemplateError> {
if expr.starts_with("for ") {
# 解析循环: for item in items
let parts: Vector<&str> = expr.split_whitespace().collect()
if parts.len() >= 4 && parts[2] == "in" {
return Ok(TemplateBlock::Loop {
variable: parts[1],
items: parts[3],
body: Vec::new(), # 需要进一步解析
})
}
} else if expr.starts_with("if ") {
# 解析条件: if condition
let condition = expr[3..].trim()
return Ok(TemplateBlock::Condition {
expression: condition,
then_body: Vec::new(),
else_body: None,
})
} else if expr.starts_with("include ") {
# 解析包含: include "template_name"
let template_name = expr[8..].trim().trim_matches('"')
return Ok(TemplateBlock::Include(template_name))
} else {
# 变量替换
return Ok(TemplateBlock::Variable(expr))
}
Err(TemplateError::InvalidExpression(expr))
}
render_blocks(&self, blocks: &[TemplateBlock], context: &TemplateContext) -> Result<String, TemplateError> {
let mut result = String::new()
for block in blocks {
match block {
TemplateBlock::Text(text) => {
result.push_str(text)
},
TemplateBlock::Variable(var_name) => {
if let Some(value) = context.get(var_name) {
result.push_str(&value)
}
},
TemplateBlock::Loop { variable, items, body } => {
if let Some(TemplateValue::Array(arr)) = context.get(items) {
for item in arr {
let mut loop_context = context.clone()
loop_context.set(variable, item.clone())
result.push_str(&self.render_blocks(body, &loop_context)?)
}
}
},
TemplateBlock::Condition { expression, then_body, else_body } => {
if self.evaluate_condition(expression, context)? {
result.push_str(&self.render_blocks(then_body, context)?)
} else if let Some(else_body) = else_body {
result.push_str(&self.render_blocks(else_body, context)?)
}
},
TemplateBlock::Include(template_name) => {
# 递归渲染包含的模板
let included = self.render(template_name, context)?;
result.push_str(&included)
},
}
}
Ok(result)
}
}
# 模板上下文
↯[derive(Clone)]
class TemplateContext {
variables: HashMap<String, TemplateValue>,
}
↯[derive(Clone)]
enum TemplateValue {
String(String),
Number(f64),
Boolean(bool),
Array(Vector<TemplateValue>),
Object(HashMap<String, TemplateValue>),
}
imply TemplateContext {
new() -> Self {
TemplateContext {
variables: HashMap::new(),
}
}
set(&mut self, key: &str, value: TemplateValue) {
self.variables.insert(key, value)
}
get(&self, key: &str) -> Option<&TemplateValue> {
self.variables.get(key)
}
from_json(json: serde_json::Value) -> Self {
let mut context = TemplateContext::new()
context.set("data", Self::json_to_template_value(json))
context
}
json_to_template_value(json: serde_json::Value) -> TemplateValue {
match json {
serde_json::Value::String(s) => TemplateValue::String(s),
serde_json::Value::Number(n) => TemplateValue::Number(n.as_f64().unwrap_or(0.0)),
serde_json::Value::Bool(b) => TemplateValue::Boolean(b),
serde_json::Value::Array(arr) => {
let values = arr.into_iter().map(Self::json_to_template_value).collect()
TemplateValue::Array(values)
},
serde_json::Value::Object(obj) => {
let mut map = HashMap::new()
for (k, v) in obj {
map.insert(k, Self::json_to_template_value(v))
}
TemplateValue::Object(map)
},
serde_json::Value::Null => TemplateValue::String(String::new()),
}
}
}WebAssembly 集成
WASM 模块加载
valkyrie
# WebAssembly 运行时
class WasmRuntime {
modules: HashMap<String, WasmModule>,
instance_pool: Vector<WasmInstance>,
}
class WasmModule {
name: String,
bytecode: Vector<u8>,
exports: Vector<WasmExport>,
imports: Vector<WasmImport>,
}
class WasmInstance {
module_name: String,
instance: wasmtime::Instance,
store: wasmtime::Store<()>,
}
class WasmExport {
name: String,
function_type: WasmFunctionType,
}
class WasmImport {
module: String,
name: String,
function_type: WasmFunctionType,
}
class WasmFunctionType {
params: Vector<WasmValueType>,
results: Vector<WasmValueType>,
}
enum WasmValueType {
I32,
I64,
F32,
F64,
}
imply WasmRuntime {
new() -> Self {
WasmRuntime {
modules: HashMap::new(),
instance_pool: Vec::new(),
}
}
load_module(&mut self, name: &str, wasm_bytes: Vector<u8>) -> Result<(), WasmError> {
let engine = wasmtime::Engine::default()
let module = wasmtime::Module::new(&engine, &wasm_bytes)
.map_err(|e| WasmError::CompilationFailed(e))?;
# 分析模块导出和导入
let exports = self.analyze_exports(&module)?
let imports = self.analyze_imports(&module)?
let wasm_module = WasmModule {
name: name,
bytecode: wasm_bytes,
exports,
imports,
}
self.modules.insert(name, wasm_module)
Ok(())
}
create_instance(&mut self, module_name: &str) -> Result<usize, WasmError> {
let module = self.modules.get(module_name)
.ok_or_else(|| WasmError::ModuleNotFound(module_name))?;
let engine = wasmtime::Engine::default()
let wasm_module = wasmtime::Module::new(&engine, &module.bytecode)
.map_err(|e| WasmError::CompilationFailed(e))?;
let mut store = wasmtime::Store::new(&engine, ())
# 创建导入对象
let mut imports = Vec::new()
for import in &module.imports {
let func = self.create_host_function(&import, &mut store)?
imports.push(func.into())
}
let instance = wasmtime::Instance::new(&mut store, &wasm_module, &imports)
.map_err(|e| WasmError::InstantiationFailed(e))?;
let wasm_instance = WasmInstance {
module_name: module_name,
instance,
store,
}
self.instance_pool.push(wasm_instance)
Ok(self.instance_pool.len() - 1)
}
call_function(
&mut self,
instance_id: usize,
function_name: &str,
args: Vector<WasmValue>
) -> Result<Vector<WasmValue>, WasmError> {
let instance = self.instance_pool.get_mut(instance_id)
.ok_or(WasmError::InvalidInstance)?;
let func = instance.instance
.get_typed_func::<(i32, i32), i32>(&mut instance.store, function_name)
.map_err(|e| WasmError::FunctionNotFound(e))?;
# 转换参数
let wasm_args: Vector<wasmtime::Val> = args.into_iter().map(|arg| {
match arg {
WasmValue::I32(v) => wasmtime::Val::I32(v),
WasmValue::I64(v) => wasmtime::Val::I64(v),
WasmValue::F32(v) => wasmtime::Val::F32(v.to_bits()),
WasmValue::F64(v) => wasmtime::Val::F64(v.to_bits()),
}
}).collect()
# 调用函数
let mut results = vec![wasmtime::Val::I32(0); 1] # 假设返回一个 i32
func.call(&mut instance.store, &wasm_args, &mut results)
.map_err(|e| WasmError::ExecutionFailed(e))?;
# 转换结果
let wasm_results: Vector<WasmValue> = results.into_iter().map(|val| {
match val {
wasmtime::Val::I32(v) => WasmValue::I32(v),
wasmtime::Val::I64(v) => WasmValue::I64(v),
wasmtime::Val::F32(v) => WasmValue::F32(f32::from_bits(v)),
wasmtime::Val::F64(v) => WasmValue::F64(f64::from_bits(v)),
_ => WasmValue::I32(0),
}
}).collect()
Ok(wasm_results)
}
}
↯[derive(Clone)]
enum WasmValue {
I32(i32),
I64(i64),
F32(f32),
F64(f64),
}实时通信
WebSocket 支持
valkyrie
# WebSocket 服务器
class WebSocketServer {
connections: HashMap<ConnectionId, WebSocketConnection>,
message_handlers: HashMap<String, Box<dyn MessageHandler>>,
next_connection_id: ConnectionId,
}
class WebSocketConnection {
id: ConnectionId,
socket: WebSocket,
user_id: Option<String>,
rooms: HashSet<String>,
last_ping: Instant,
}
trait MessageHandler: Send + Sync {
async micro handle(&self, connection_id: ConnectionId, message: WebSocketMessage) -> Result<(), WebSocketError>
}
↯[derive(Clone)]
enum WebSocketMessage {
Text(String),
Binary(Vector<u8>),
Ping(Vector<u8>),
Pong(Vector<u8>),
Close(Option<CloseFrame>),
}
class CloseFrame {
code: u16,
reason: String,
}
imply WebSocketServer {
new() -> Self {
WebSocketServer {
connections: HashMap::new(),
message_handlers: HashMap::new(),
next_connection_id: 0,
}
}
on_message<H: MessageHandler>(&mut self, message_type: &str, handler: H) {
self.message_handlers.insert(message_type, Box::new(handler))
}
async micro handle_connection(&mut self, socket: WebSocket) -> Result<(), WebSocketError> {
let connection_id = self.next_connection_id
self.next_connection_id += 1
let connection = WebSocketConnection {
id: connection_id,
socket,
user_id: None,
rooms: HashSet::new(),
last_ping: Instant::now(),
}
self.connections.insert(connection_id, connection)
# 启动消息处理循环
self.message_loop(connection_id).await
}
async micro message_loop(&mut self, connection_id: ConnectionId) -> Result<(), WebSocketError> {
loop {
let connection = self.connections.get_mut(&connection_id)
.ok_or(WebSocketError::ConnectionNotFound)?;
# 接收消息
match connection.socket.next().await {
Some(Ok(msg)) => {
let ws_message = match msg {
tungstenite::Message::Text(text) => WebSocketMessage::Text(text),
tungstenite::Message::Binary(data) => WebSocketMessage::Binary(data),
tungstenite::Message::Ping(data) => WebSocketMessage::Ping(data),
tungstenite::Message::Pong(data) => WebSocketMessage::Pong(data),
tungstenite::Message::Close(frame) => {
let close_frame = frame.map(|f| CloseFrame {
code: f.code.into(),
reason: f.reason,
})
WebSocketMessage::Close(close_frame)
},
}
# 处理消息
self.handle_message(connection_id, ws_message).await?
},
Some(Err(e)) => {
@eprintln("WebSocket error: {}", e)
break
},
None => {
# 连接关闭
break
}
}
}
# 清理连接
self.connections.remove(&connection_id)
Ok(())
}
async micro handle_message(
&mut self,
connection_id: ConnectionId,
message: WebSocketMessage
) -> Result<(), WebSocketError> {
match &message {
WebSocketMessage::Text(text) => {
# 尝试解析为 JSON 消息
if let Ok(json_msg) = serde_json::from_str::<serde_json::Value>(text) {
if let Some(msg_type) = json_msg.get("type").and_then(|t| t.as_str()) {
if let Some(handler) = self.message_handlers.get(msg_type) {
handler.handle(connection_id, message).await?
}
}
}
},
WebSocketMessage::Ping(data) => {
# 响应 ping
self.send_to_connection(connection_id, WebSocketMessage::Pong(data.clone())).await?
},
WebSocketMessage::Close(_) => {
# 处理连接关闭
self.connections.remove(&connection_id)
},
_ => {}
}
Ok(())
}
async micro send_to_connection(
&mut self,
connection_id: ConnectionId,
message: WebSocketMessage
) -> Result<(), WebSocketError> {
let connection = self.connections.get_mut(&connection_id)
.ok_or(WebSocketError::ConnectionNotFound)?;
let tungstenite_msg = match message {
WebSocketMessage::Text(text) => tungstenite::Message::Text(text),
WebSocketMessage::Binary(data) => tungstenite::Message::Binary(data),
WebSocketMessage::Ping(data) => tungstenite::Message::Ping(data),
WebSocketMessage::Pong(data) => tungstenite::Message::Pong(data),
WebSocketMessage::Close(frame) => {
let close_frame = frame.map(|f| tungstenite::protocol::CloseFrame {
code: tungstenite::protocol::frame::coding::CloseCode::from(f.code),
reason: f.reason.into(),
})
tungstenite::Message::Close(close_frame)
},
}
connection.socket.send(tungstenite_msg).await
.map_err(|e| WebSocketError::SendFailed(e))
}
async micro broadcast_to_room(&mut self, room: &str, message: WebSocketMessage) -> Result<(), WebSocketError> {
let connection_ids: Vector<ConnectionId> = self.connections
.iter()
.filter(|(_, conn)| conn.rooms.contains(room))
.map(|(id, _)| *id)
.collect()
for connection_id in connection_ids {
self.send_to_connection(connection_id, message.clone()).await?
}
Ok(())
}
join_room(&mut self, connection_id: ConnectionId, room: &str) -> Result<(), WebSocketError> {
let connection = self.connections.get_mut(&connection_id)
.ok_or(WebSocketError::ConnectionNotFound)?;
connection.rooms.insert(room)
Ok(())
}
leave_room(&mut self, connection_id: ConnectionId, room: &str) -> Result<(), WebSocketError> {
let connection = self.connections.get_mut(&connection_id)
.ok_or(WebSocketError::ConnectionNotFound)?;
connection.rooms.remove(room)
Ok(())
}
}完整的 Web 应用示例
博客应用
valkyrie
# 博客应用主函数
async micro main() -> Result<(), Box<dyn std::error::Error>> {
let config = ServerConfig {
host: "127.0.0.1",
port: 8080,
max_connections: 1000,
request_timeout: Duration::from_secs(30),
static_files_dir: Some("./static"),
enable_compression: true,
}
let mut server = WebServer::new(config)
# 添加中间件
server.use_middleware(LoggingMiddleware::new())
server.use_middleware(CorsMiddleware::new().allow_origin("*"))
# 静态文件服务
server.serve_static("/static", "./static")
# 博客路由
server.get("/", blog_index)
server.get("/posts/:id", blog_post)
server.get("/api/posts", api_posts)
server.post("/api/posts", api_create_post)
server.put("/api/posts/:id", api_update_post)
server.delete("/api/posts/:id", api_delete_post)
# 用户认证路由
server.post("/api/auth/login", auth_login)
server.post("/api/auth/register", auth_register)
server.get("/api/auth/profile", auth_profile)
# 启动服务器
@println("Starting blog server on http://127.0.0.1:8080")
server.listen().await
}
# 博客首页
async micro blog_index(request: &HttpRequest) -> Result<HttpResponse, HandlerError> {
let mut template_engine = TemplateEngine::new("./templates")
# 获取最新文章
let posts = get_recent_posts(10).await?
let mut context = TemplateContext::new()
context.set("title", TemplateValue::String("我的博客"))
context.set("posts", posts_to_template_value(posts))
let html = template_engine.render("index", &context)?
Ok(HttpResponse::ok().with_html(&html))
}
# 文章详情页
async micro blog_post(request: &HttpRequest) -> Result<HttpResponse, HandlerError> {
let post_id = request.get_param("id")
.ok_or(HandlerError::BadRequest("Missing post ID"))?;
let post = get_post_by_id(post_id).await?
.ok_or(HandlerError::NotFound)?;
let mut template_engine = TemplateEngine::new("./templates")
let mut context = TemplateContext::new()
context.set("title", TemplateValue::String(post.title.clone()))
context.set("post", post_to_template_value(post))
let html = template_engine.render("post", &context)?
Ok(HttpResponse::ok().with_html(&html))
}
# API: 获取文章列表
async micro api_posts(request: &HttpRequest) -> Result<HttpResponse, HandlerError> {
let page = request.get_query("page")
.and_then(|p| p.parse::<u32>().ok())
.unwrap_or(1)
let limit = request.get_query("limit")
.and_then(|l| l.parse::<u32>().ok())
.unwrap_or(10)
let posts = get_posts_paginated(page, limit).await?
let response_data = serde_json::@json({
"posts": posts,
"page": page,
"limit": limit
})
HttpResponse::ok().with_json(&response_data)
.map_err(|e| HandlerError::InternalError(e))
}
# API: 创建文章
async micro api_create_post(request: &HttpRequest) -> Result<HttpResponse, HandlerError> {
let post_data: CreatePostRequest = request.json()
.map_err(|e| HandlerError::BadRequest(e))?;
# 验证数据
if post_data.title.is_empty() || post_data.content.is_empty() {
return Err(HandlerError::BadRequest("Title and content are required"))
}
let post = create_post(post_data).await?
HttpResponse::created().with_json(&post)
.map_err(|e| HandlerError::InternalError(e))
}
# 数据模型
↯[derive(Encode, DeEncode)]
class Post {
id: u32
title: String
content: String
author: String
created_at: chrono::DateTime<chrono::Utc>
updated_at: chrono::DateTime<chrono::Utc>
}
↯[derive(DeEncode)]
class CreatePostRequest {
title: String
content: String
author: String
}
# 数据库操作
async micro get_recent_posts(limit: u32) -> Result<Vector<Post>, DatabaseError> {
# 数据库查询逻辑
Ok(vec![])
}
async micro get_post_by_id(id: &str) -> Result<Option<Post>, DatabaseError> {
# 数据库查询逻辑
Ok(None)
}
async micro create_post(data: CreatePostRequest) -> Result<Post, DatabaseError> {
# 数据库插入逻辑
Ok(Post {
id: 1,
title: data.title,
content: data.content,
author: data.author,
created_at: chrono::Utc::now(),
updated_at: chrono::Utc::now(),
})
}Valkyrie 网页开发框架提供了完整的现代 Web 开发工具链,支持高性能服务器、灵活的路由系统、强大的模板引擎、WebAssembly 集成和实时通信功能,为构建各种规模的 Web 应用提供了坚实的基础。