#toggle #flags #features #web-ui #flipper #list

feattle

为Rust提供功能开关,可扩展且具有后台同步和管理UI

13个版本 (2个稳定版)

2.0.0 2024年6月26日
1.0.0 2023年6月28日
0.10.0 2023年4月21日
0.9.0 2022年7月11日
0.2.5 2020年10月23日

#37 in 配置

Download history 133/week @ 2024-04-26 126/week @ 2024-05-03 120/week @ 2024-05-10 157/week @ 2024-05-17 246/week @ 2024-05-24 166/week @ 2024-05-31 77/week @ 2024-06-07 208/week @ 2024-06-14 225/week @ 2024-06-21 267/week @ 2024-06-28 189/week @ 2024-07-05 101/week @ 2024-07-12 97/week @ 2024-07-19 270/week @ 2024-07-26 75/week @ 2024-08-02 55/week @ 2024-08-09

每月501次下载

MIT/Apache

165KB
2.5K SLoC

Rust 2.5K SLoC // 0.0% comments JavaScript 198 SLoC Handlebars 177 SLoC

feattle

Crates.io Docs.rs CI Coverage Status

为Rust提供功能开关(简称为"feattles"),可扩展且具有后台同步和管理UI。

功能

  • 与后端存储自动同步的功能开关
  • 功能开关可以是简单的 bool,也可以是列表、映射和任意类型(通过FeattleValue trait)。
  • 具有文档、更改历史和验证的Web UI
  • 用于读取和设置开关的JSON API
  • 模块化和可扩展:根据需要使用捆绑功能中的任何部分。想使用不同的Web UI?不同的存储层?没问题。

示例

use feattle::*;
use std::sync::Arc;

/// A struct with your feature toggles: you can use primitive types (like `bool`, `i32`, etc),
/// standard collections (like `Vec`, `BTreeSet`, etc) or any arbitrary type that implements
/// the required trait.
feattles! {
    struct MyFeattles {
        /// Is this usage considered cool?
        is_cool: bool = true,
        /// Limit the number of "blings" available.
        /// This will not change the number of "blengs", though!
        max_blings: i32,
        /// List the actions that should not be available
        blocked_actions: Vec<String>,
    }
}

#[tokio::main]
async fn main() {
    // Store their values and history in AWS' S3
    use std::future::IntoFuture;
    use std::time::Duration;
    use tokio::net::TcpListener;
    let config = aws_config::load_from_env().await;
    let persistence = Arc::new(S3::new(
        &config,
        "my-bucket".to_owned(),
        "some/s3/prefix/".to_owned(),
    ));

    // Create a new instance
    let my_feattles = Arc::new(MyFeattles::new(persistence));

    // Poll the storage in the background
    BackgroundSync::new(&my_feattles).start().await;

    // Start the admin UI with `warp`
    let admin_panel = Arc::new(AdminPanel::new(my_feattles.clone(), "Project Panda - DEV".to_owned()));
    tokio::spawn(run_warp_server(admin_panel.clone(), ([127, 0, 0, 1], 3030)));

    // Or serve the admin panel with `axum`
    let router = axum_router(admin_panel);
    let listener = TcpListener::bind(("127.0.0.1", 3031)).await.unwrap();
    tokio::spawn(axum::serve(listener, router.into_make_service()).into_future());

    // Read values (note the use of `*`)
    assert_eq!(*my_feattles.is_cool(), true);
    assert_eq!(*my_feattles.max_blings(), 0);
    assert_eq!(*my_feattles.blocked_actions(), Vec::<String>::new());
}

您可以使用以下命令在本地运行完整示例:cargo run --example full --features='s3 uuid warp axum'

使用此代码,您将获得一个Web管理UI,如下所示

Home Web Admin UI

您可以使用此UI编辑当前值并查看其更改历史。例如,编辑一个enum时的预期效果如下

Edit enum

它还支持具有JSON编辑器和有用的错误诊断的复杂类型

Edit JSON

工作原理

宏将生成具有给定名称和可见性修饰符的结构体(默认为私有)。生成的结构体实现了Feattles,并为每个功能开关公开一个方法。

为每个属性创建的方法允许读取它们的当前值。例如,对于一个属性 is_cool: bool,将会有一个类似的方法 pub fn is_cool(&self) -> MappedRwLockReadGuard<bool>。注意使用了 parking_lot::MappedRwLockReadGuard,因为结构体的内部存储在 RwLock 后面,以控制并发访问。

属性使用以下语法创建:$key: $type [= $default]。您可以使用文档注释(以 /// 开头)来很好地描述它们在您的系统中的作用。您可以使用实现 FeattleValue 的任何类型,并且可以选择提供一个默认值。如果没有提供,默认值将使用 Default::default() 创建。

最低支持的 Rust 版本

截至本版本,最低支持的 Rust 版本为 1.76.0,已在 CI 中测试。补丁版本永远不会需要更高版本的最低支持版本。

可选功能

您可以轻松声明使用自定义类型、使用其他持久化存储逻辑或 Web 框架(或任何其他框架)的属性。对于一些开箱即用的功能,您可以激活以下 cargo 功能

  • uuid:将添加对 uuid::Uuid 的支持。
  • rusoto_s3:提供 RusotoS3 以与 AWS 的 S3 集成
  • aws_sdk_s3:提供 [S3] 以与 AWS 的 S3 集成
  • warp:提供 run_warp_server 以与 warp 进行快速集成
  • axum:提供 axum_router 以与 axum 进行快速集成

软件包组织

此软件包是这三个组件的简单重导出

  • feattle-coreCrates.io
  • feattle-syncCrates.io
  • feattle-uiCrates.io

将它们分开可以让底层集成更简洁。如果您正在创建一个软件包以提供不同的存储或管理,您只需要 feattle-core

许可协议

根据以下任一协议许可

由您选择。

贡献

除非您明确表示 otherwise,否则根据Apache-2.0许可证定义,您有意提交以包含在作品中的任何贡献,应按上述方式双重许可,无需附加条款或条件。

CONTRIBUTING.md

依赖项

~7–22MB
~290K SLoC