1 个不稳定版本
使用旧的 Rust 2015
0.2.1 | 2016 年 8 月 11 日 |
---|
#53 在 #api-server
30 星 & 3 关注者
150KB
3K SLoC
核心 API
核心 API 包含用于配置主机的端点和它们所依赖的底层 OS 抽象。通常,您会使用 Intecture Proj (proj/) 代替,它导出核心 API,尽管对于某些应用程序,核心 API 就足够了。
项目结构
核心 API 按端点组织成一系列目录(例如 command/
、host/
等)。每个端点内部有一个 providers/
目录,其中包含底层抽象。
用法
有关 API 用法,请参阅 示例。
lib.rs
:
Intecture 是一个用于管理服务器的 API。您可以将其视为 DevOps 工具,但没有复杂的生态系统和专有垃圾。
核心 API 是 Intecture 的核心。它包含所有用于配置主机的端点以及它们所依赖的底层 OS 抽象。通常,您将通过 intecture_proj 消费此 API,它导出 intecture_api
,尽管对于不需要正式结构的项目(例如安装程序),此 API 就足够了。
项目结构
核心 API 组织成一系列模块(称为“端点”,例如 command
、package
等),这些模块代表您通常手动执行的基本配置任务。每个端点内部有一个 providers
模块,其中包含为端点执行繁重工作的特定于 OS 的抽象。
例如,package
端点有一个名为 Package
的结构体。这是一个跨平台的抽象,用于管理服务器上的软件包。在这个抽象背后是特定软件包 提供者 的具体实现,例如 Yum 或 Apt。如果您通过 Package::new()
函数实例化一个新的 Package
对象,系统将自动选择最适合您服务器的提供者。所有端点都适用此规则。
主机
到目前为止,我们讨论了如何使用端点来自动化配置任务,但 Intecture 如何知道我们想要与哪个服务器通信呢?这就是我们需要的 host
端点。所有事物都从主机开始!顺便提一下——如果我们做“商品”,那可能就是 T 恤。不过,抛开糟糕的市场决策不谈,您需要创建一个主机才能进行任何操作。
主机分为 Local
和 Plain
两种类型。Local
类型指向您的本地机器,而 Plain
类型是一种远程主机类型,通过网络连接到远程机器。无论您选择哪种类型,只需将其作为所需内容传递给端点即可,Intecture 会完成其余的工作。
“为什么是
Plain
?”您可能会问。嗯,因为Plain
主机类型是一个使用 TCP 发送/接收 纯文本 数据的远程主机。
示例
以下是 examples/
文件夹中的 基本示例 的复制版
extern crate futures;
extern crate intecture_api;
extern crate tokio_core;
use futures::{Future, Stream};
use intecture_api::prelude::*;
use tokio_core::reactor::Core;
fn main() {
// These two lines are part of `tokio-core` and can be safely ignored. So
// long as they appear at the top of your code, all is fine with the world.
let mut core = Core::new().unwrap();
let handle = core.handle();
// Here's the meat of your project. In this example we're talking to our
// local machine, so we use the `Local` host type.
let host = Local::new(&handle).and_then(|host| {
// Ok, we're in! Now we can pass our `host` handle to other endpoints,
// which informs them of the server we mean to talk to.
// Let's start with something basic - a shell command.
let cmd = Command::new(&host, "whoami", None);
cmd.exec().and_then(|mut status| {
// At this point, our command is running. As the API is
// asynchronous, we don't have to wait for it to finish before
// inspecting its output. This is called "streaming".
// First let's grab the stream from `CommandStatus`. This stream is
// a stream of strings, each of which represents a line of command
// output. We can use the `for_each` combinator to print these
// lines to stdout.
//
// If printing isn't your thing, you are also free to lick them or
// whatever you're into. I'm not here to judge.
let stream = status.take_stream()
.unwrap() // Unwrap is fine here as we haven't called it before
.for_each(|line| { println!("{}", line); Ok(()) });
// Next, let's check on the result of our command.
// `CommandStatus` is a `Future` that represents the command's
// exit status. We can use the `map` combinator to print it out.*
//
// * Same caveat as above RE: printing. This is a safe
// place.
let status = status.map(|s| println!("This command {} {}",
if s.success { "succeeded" } else { "failed" },
if let Some(e) = s.code { format!("with code {}", e) } else { String::new() }));
// Finally, we need to return these two `Future`s (stream and
// status) so that they will be executed by the event loop. Sadly
// we can't return them both as a tuple, so we use the join
// combinator instead to turn them into a single `Future`. Easy!
stream.join(status)
})
});
// This line is part of `tokio-core` and is used to execute the
// chain of futures you've created above. You'll need to call
// `core.run()` for each host you interact with, otherwise your
// project will not run at all!
core.run(host).unwrap();
}
API 预览。
依赖关系
~16MB
~302K SLoC