Skip to content

Commit

Permalink
Implement redis datasource (#25)
Browse files Browse the repository at this point in the history
* chore: refactors the way datasources are handled so that we can support more than a single data source, especially ones that may need to be mutable

* chore: introduce test containers

* feat: implement redis datasource
  • Loading branch information
sighphyre authored Jan 31, 2023
1 parent bcc2051 commit 0b2537f
Show file tree
Hide file tree
Showing 19 changed files with 381 additions and 68 deletions.
141 changes: 137 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ We support running in various modes, from a [local version](#offline) to a full

You have a need to have full control of both the data your clients will get and which keys can be used to access the server. This mode needs a downloaded JSON dump of a result from a query against an Unleash server on the [/api/client/features](https://docs.getunleash.io/reference/api/unleash/get-client-feature) endpoint as well as a comma-separated list of keys that should be allowed to access the server.

If your keys follow the Unleash API key format `[project]:[environment].<somesecret>`, Edge will filter the features dump to match the project contained in the key.
If your keys follow the Unleash API key format `[project]:[environment].<somesecret>`, Edge will filter the features dump to match the project contained in the key.

If you'd rather use a simple key like `secret-123`, any query against `/api/client/features` will receive the dump passed in on the command line.
If you'd rather use a simple key like `secret-123`, any query against `/api/client/features` will receive the dump passed in on the command line.

Any query against `/api/frontend` or `/api/proxy` with a valid key will receive only enabled toggles.
To launch in this mode, run
Expand All @@ -57,4 +57,4 @@ TODO: Document proxy mode
TODO: Document edge mode

## Development
See our [Contributors guide](./CONTRIBUTING.md) as well as our [development-guide](./development-guide.md)
See our [Contributors guide](./CONTRIBUTING.md) as well as our [development-guide](./development-guide.md)
9 changes: 7 additions & 2 deletions development-guide.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
### Tools
* Install Rust using [rustup](https://rustup.rs)
* Copy the pre-commit hook in the hooks folder into .git/hooks/pre-commit
* Copy the pre-commit hook in the hooks folder into .git/hooks/pre-commit

```shell
cp hooks/* .git/hooks/
Expand All @@ -18,4 +18,9 @@ cp hooks/* .git/hooks/

### Common commands

- `cargo add ...` - Add a dependency to the Cargo.toml file
- `cargo add ...` - Add a dependency to the Cargo.toml file


### Testing

By default `cargo test` will run all the tests. If you want to exclude the expensive integration tests you can instead run `cargo test --bin unleash-edge`.
2 changes: 2 additions & 0 deletions server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ dotenv = { version = "0.15.0", features = ["clap"] }
opentelemetry = { version = "0.18.0", features = ["trace", "rt-tokio", "metrics"] }
opentelemetry-prometheus = "0.11.0"
prometheus = { version = "0.13.3", features = ["process"] }
redis = "0.22.3"
rustls = "0.20.8"
rustls-pemfile = "1.0.2"
serde = { version = "1.0.152", features = ["derive"] }
Expand All @@ -37,6 +38,7 @@ unleash-yggdrasil = "0.4.2"
[dev-dependencies]
env_logger = "0.10.0"
test-case = "2.2.2"
testcontainers = "0.14.0"

[build-dependencies]
shadow-rs = "0.20.0"
33 changes: 32 additions & 1 deletion server/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,41 @@
use std::path::PathBuf;

use clap::{Args, Parser, Subcommand};
use clap::{ArgGroup, Args, Parser, Subcommand};

#[derive(Subcommand, Debug, Clone)]
pub enum EdgeMode {
Offline(OfflineArgs),
Edge(EdgeArgs),
}

pub enum EdgeArg {
Redis(String),
Dynamo(String),
}

impl From<EdgeArgs> for EdgeArg {
fn from(value: EdgeArgs) -> Self {
if let Some(redis_url) = value.redis_url {
return EdgeArg::Redis(redis_url);
};
if let Some(dynamo_url) = value.dynamo_url {
return EdgeArg::Dynamo(dynamo_url);
}
panic!("Unknown argument for edge type"); //This shouldn't be reachable without programmer error, that's what it's for
}
}

#[derive(Args, Debug, Clone)]
#[command(group(
ArgGroup::new("data-provider")
.required(true)
.args(["redis_url", "dynamo_url"]),
))]
pub struct EdgeArgs {
#[clap(short, long, env)]
pub redis_url: Option<String>,
#[clap(short, long, env)]
pub dynamo_url: Option<String>,
}

#[derive(Args, Debug, Clone)]
Expand Down
2 changes: 1 addition & 1 deletion server/src/client_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ async fn features(
edge_token: EdgeToken,
features_source: web::Data<dyn EdgeProvider>,
) -> EdgeJsonResult<ClientFeatures> {
let client_features = features_source.get_client_features(edge_token);
let client_features = features_source.get_client_features(edge_token)?;
Ok(Json(client_features))
}

Expand Down
2 changes: 2 additions & 0 deletions server/src/data_sources/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod redis_provider;
pub mod offline_provider;
Loading

0 comments on commit 0b2537f

Please sign in to comment.