4个版本 (2个稳定版)
1.1.0 | 2023年10月5日 |
---|---|
1.0.0 | 2023年6月8日 |
0.1.9 | 2023年6月8日 |
0.1.8 | 2022年9月16日 |
#183 在 认证
每月 172 次下载
72KB
1.5K SLoC
Smartcar Rust SDK
用于向Smartcar API发送请求的Rust库crate
概述
Smartcar API 允许您通过HTTP请求读取车辆数据并向车辆发送命令(锁定、解锁)。
要从Web或移动应用程序向车辆发送请求,最终用户必须使用 Smartcar Connect 将其车辆连接。此流程遵循OAuth规范,并将返回一个 code
,可用于从Smartcar获取访问令牌。
Smartcar Rust SDK提供以下方法:
- 生成重定向到Connect的链接。
- 使用从Connect获得的
code
向Smartcar发出请求以获取访问令牌和刷新令牌 - 使用在第2步中获得的访问令牌向Smartcar API发出请求以读取车辆数据并向车辆发送命令。
在集成Smartcar SDK之前,您需要在 Smartcar开发者门户 中注册一个应用程序。如果您无法访问仪表板,请 请求访问。
请注意,Rust SDK仅支持Smartcar API的2.0版本。
安装
将以下内容添加到您的 Cargo.toml
[dependencies]
smartcar = "1.0.0"
流程
-
使用您的
client_id
、client_secret
和redirect_uri
创建一个新的AuthClient
结构。 -
使用
<AuthClient>.get_auth_url
并带有所需的scope
将用户重定向到Smartcar Connect。 -
用户将登录,然后接受或拒绝您的
scope
的权限。 -
如果用户接受了您的权限
a. 处理对您的
redirect_uri
的GET请求。它将有一个查询code
,表示用户的同意。b. 使用以下代码通过
<AuthClient>.exchange_code
来获取一个Access
结构体。这个结构体包含你的令牌:access_token
(有效期3小时)和refresh_token
(有效期60天)*。 -
使用
get_vehicles
获取一个包含车主所有车辆ID的Vehicles
结构体。 -
使用前一步响应中的
id
和第4步中的access_token
创建一个新的Vehicle
(单数)结构体。 -
开始向Smartcar API发送请求!
* 为了进行后续请求,您需要将令牌保存到Access结构体中某个地方。
** 当您的访问令牌过期时,使用<AuthClient>.exchange_refresh_token
和您的refresh_token
来获取一组新的令牌。
入门指南
让我们看看使用axum web框架的smartcar
的基本用法。在这个例子中,我们将设置一个简单的服务器,它运行在localhost 3000上,以运行上述流程,以获取车辆的制造商、型号和年份。
请参阅./example/getting-started.rs中的代码。
对于不包含Web框架集成的更简单的示例,请查看./example/getting-started-cli.rs。
要求
- Rust/cargo
- 浏览器
如何运行此示例
- 克隆此仓库,然后
cd
进入目录。 - 在Smartcar仪表板中设置一个新的重定向URI。
- 添加
https://127.0.0.1:3000/callback
- 添加
- 在./example/getting-started.rs中找到
get_auth_client
,并用您的仪表板中的实际客户端凭据替换假凭据。- 假凭据以前缀
"REPLACE_WITH_YOUR_"
开头。
- 假凭据以前缀
- 使用带有示例标志的cargo run运行示例
cargo run --example=getting-started
-
在浏览器中,访问
http://locahost:3000/login
以查看Smartcar Connect流程。此示例在测试模式下运行,使用随机数据和假车辆。- 通常,您的用户将完成此流程。在此示例中,您将亲自完成此流程。
- 选择任何制造商并输入假电子邮件/密码
- 例如:用户名:
"[email protected]"
,密码:"blah"
-
登录并批准权限后,您应该会收到一个包含车辆制造商、型号、年份和ID的JSON响应。
跟随您终端中的打印语句来查看步骤!
** example/getting-started.rs中的打印语句对应于上面提到的7步流程。为了减少噪音,下面的代码不包括打印语句。
入门指南(使用axum web框架)
use axum::extract::Query;
use axum::http::StatusCode;
use axum::response::{IntoResponse, Redirect};
use axum::Json;
use axum::{routing::get, Router};
use serde::Deserialize;
use serde_json::json;
use smartcar::*;
use auth_client::{AuthClient, AuthUrlOptionsBuilder};
use response::{Meta, VehicleAttributes};
use vehicle::Vehicle;
#[tokio::main]
async fn main() {
let app = Router::new()
.route("/login", get(login))
.route("/callback", get(callback));
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
/// Helper for creating an Auth Client instance with your credentials
fn get_auth_client() -> AuthClient {
AuthClient::new(
"REPLACE_WITH_YOUR_SMARTCAR_CLIENT_ID",
"REPLACE_WITH_YOUR_SMARTCAR_CLIENT_SECRET",
"REPLACE_WITH_YOUR_SMARTCAR_REDIRECT_URI.COM",
true,
)
}
/// Smartcar Connect Flow
async fn login() -> Redirect {
// Flow - Step 1
let auth_client = get_auth_client();
let scope = ScopeBuilder::new().add_permission(Permission::ReadVehicleInfo);
let auth_url_options = AuthUrlOptionsBuilder::new().set_force_prompt(true);
// Flow - Step 2
let auth_url = auth_client.get_auth_url(&scope, Some(&auth_url_options));
Redirect::to(&auth_url)
}
#[derive(Deserialize)]
struct Callback {
code: Option<String>,
error: Option<String>,
}
async fn callback(q: Query<Callback>) -> impl IntoResponse {
// Flow - Step 3 completed, starting 4a
// If user denies you access, you'll see this
if let Some(_) = &q.error {
return (
StatusCode::EXPECTATION_FAILED,
Json(json!("User delined during Smartcar Connect")),
);
};
// This is the code that represents the user’s consent to grant you permission
// to read their vehicle's attributes. This code must be exchanged for an
// access token to start making requests to the vehicle.
let code = &q.code.to_owned().unwrap();
match get_attributes_handler(&code).await {
Err(_) => {
return (
StatusCode::EXPECTATION_FAILED,
Json(json!("attributes request failed")),
)
}
Ok((attributes, _)) => {
(
StatusCode::OK,
Json(json!(attributes)),
)
}
}
}
async fn get_attributes_handler(
auth_code: &str,
) -> Result<(VehicleAttributes, Meta), smartcar::error::Error> {
let client = get_auth_client();
// Flow - Step 4b
let (access, _) = client.exchange_code(auth_code).await?;
// Flow - Step 5
let (vehicle_ids, _) = smartcar::get_vehicles(&access, None, None).await?;
// Flow - Step 6
let vehicle = Vehicle::new(&vehicle_ids.vehicles[0], &access.access_token);
// Flow - Step 7
let (attributes, meta) = vehicle.attributes().await?;
Ok((attributes, meta))
}
依赖关系
~7–20MB
~296K SLoC