3 个版本
使用旧的 Rust 2015
0.1.2 | 2017 年 10 月 23 日 |
---|---|
0.1.1 | 2017 年 10 月 20 日 |
0.1.0 | 2017 年 10 月 18 日 |
#1780 in 网页编程
55KB
846 行
FDK: Fn 功能开发套件
此 crate 为 Fn Project 服务器端无服务器平台实现了实验性的功能开发套件。
提供的 API 隐藏了 Fn 平台合约的实现细节,允许用户专注于代码,并轻松实现函数即服务(Function as a Service,简称 Faas)程序。
用法
Fn 平台提供了一款 命令行工具 来初始化、构建和部署功能项目。按照 fn
工具快速入门指南学习 Fn 平台的基础知识。然后使用以下命令启动 Rust 功能项目:
fn init --runtime=rust <other options to fn command>
初始化器实际上会使用 cargo 生成功能项目的 cargo 二进制项目。然后可以像往常一样指定依赖项。
[dependencies]
fdk = "0.1"
示例
无状态的输入函数
这是一个简单的函数,它问候作为输入提供的名称。
extern crate fdk;
use std::process;
fn main() {
let exit_code = fdk::Function::new(fdk::STATELESS)
.run(|_, i: String| {
Ok(format!("Hello, {}!\n",
if i.is_empty() { "world".to_string() } else { i }))
});
process::exit(exit_code);
}
具有完整可测试实现的函数
此函数利用了 FDK 的功能,如配置和状态管理、错误处理以及提供测试包装器以测试函数代码作为在 Fn 平台上运行的功能。
extern crate fdk;
use std::process;
struct MyState {
greeting: String
}
impl MyState {
pub fn greeting(&self) -> &str { &self.greeting }
}
fn init(context: &fdk::RuntimeContext) -> Result<MyState, fdk::FunctionError> {
match context.config().get("GREETING") {
Some(s) => Ok(MyState {
greeting: s.clone()
}),
None => Err(fdk::FunctionError::initialization(
"Missing greeting in configuration\n",
)),
}
}
fn code(state: &mut MyState, i: String) -> Result<String, fdk::FunctionError> {
if !i.is_empty() {
Ok(format!("{}, {}!\n", state.greeting(), i).into())
} else {
Err(fdk::FunctionError::invalid_input(
"Requires a non-empty UTF-8 string\n",
))
}
}
fn main() {
let exit_code = fdk::Function::new(init).run(code);
process::exit(exit_code);
}
#[cfg(test)]
mod tests {
use fdk;
use init;
use code;
#[test]
fn test_normal_functionality() {
let mut testbench =
fdk::FunctionTestbench::new(init).with_config("GREETING", "Salutations");
let exit_code = testbench.enqueue_simple("Blah").run(code);
assert_eq!(exit_code, 0);
let mut responses = testbench.drain_responses();
assert_eq!(responses.len(), 1);
let rb = fdk::body_as_bytes(responses.pop().unwrap().body()).unwrap();
assert_eq!(String::from_utf8_lossy(&rb), "Salutations, Blah!\n");
}
}
直接处理 HTTP 请求和响应的函数
虽然可以进行输入和输出强制转换,以便您的函数仅处理您自己的类型,但有时直接操作请求和响应很有用。
FDK 使用来自知名 crate 的 hyper::Request
和 hyper::Response
类型来实现此目的,因此您的函数可以接收一个 hyper::Request
作为输入,并生成一个 hyper::Response
作为输出。
请注意,这允许您直接设置响应的自定义头和状态码,而不是依赖于 FDK 中的辅助实现,这些实现将错误与某些 HTTP 状态相关联。
extern crate hyper;
extern crate fdk;
use std::process;
struct MyState {
greeting: String
}
impl MyState {
pub fn greeting(&self) -> &str { &self.greeting }
}
fn init(context: &fdk::RuntimeContext) -> Result<MyState, fdk::FunctionError> {
match context.config().get("GREETING") {
Some(s) => Ok(MyState {
greeting: s.clone()
}),
None => Err(fdk::FunctionError::initialization(
"Missing greeting in configuration\n",
)),
}
}
fn main() {
let exit_code = fdk::Function::new(init)
.run(|state, req: hyper::Request| {
// Since we have raw access to the request we can inspect the
// headers and extract some data.
let host = match req.headers().get::<hyper::header::Host>() {
Some(h) => h.hostname().to_string(),
None => "NO HOST".to_string(),
};
let i = match fdk::body_as_bytes(req.body()) {
Ok(b) => {
match String::from_utf8(b) {
Ok(s) => s,
Err(_) => String::new()
}
}
Err(e) => {
return Err(e);
}
};
if i.is_empty() {
// We can produce an "error response" of our own instead of an
// Err value which would be converted to a 400 response with no
// headers.
let message = "Requires a non-empty UTF-8 string!";
let message_length = message.as_bytes().len() as u64;
Ok(
hyper::Response::new()
.with_status(hyper::StatusCode::BadRequest)
.with_header(hyper::header::Host::new(host.clone(), None))
.with_header(hyper::header::ContentLength(message_length))
.with_body(message)
)
} else {
let message = format!("{}, {}!\n", state.greeting(), i);
let message_length = message.as_bytes().len() as u64;
Ok(
hyper::Response::new()
.with_status(hyper::StatusCode::Ok)
.with_header(hyper::header::Host::new(host.clone(), None))
.with_header(hyper::header::ContentLength(message_length))
.with_body(message)
)
}
});
process::exit(exit_code);
}
依赖项
~10MB
~172K SLoC