Skip to content

Commit

Permalink
Adds persistence and clean up
Browse files Browse the repository at this point in the history
  • Loading branch information
Tarik Eshaq committed Jul 22, 2020
1 parent 1ef579b commit 3f37db4
Show file tree
Hide file tree
Showing 13 changed files with 317 additions and 114 deletions.
21 changes: 14 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "experiments"
name = "nimbus_experiments"
version = "0.1.0"
authors = ["Tarik Eshaq <[email protected]>"]
edition = "2018"
Expand All @@ -11,17 +11,24 @@ url = "2.1"
serde = { version = "1", features = ["rc"] }
serde_derive = "1"
serde_json = "1"
# This now references a local path on my own device. If we end up actually using viaduct,
# We should maybe publish it as crate (similar to ffi-support)
viaduct = { path = "../application-services/components/viaduct" }
anyhow = "1.0"
rand = "0.7"
log = "0.4"
viaduct = { git = "https://github.com/mozilla/application-services" }
ffi-support = "0.4"
thiserror = "1"
rkv = "0.10"
lazy_static = "1.4"
uuid = { version = "0.8", features = ["serde", "v4"]}
prost = "0.6"

[build-dependencies]
prost-build = { version = "0.6" }

[lib]
name = "nimbus_experiments"
crate-type = ["lib"]

[dev-dependencies]
# This now references a local path on my own device. If we end up actually using viaduct,
# We should maybe publish it as crate (similar to ffi-support)
viaduct-reqwest = { path = "../application-services/components/support/viaduct-reqwest" }
viaduct-reqwest = { git = "https://github.com/mozilla/application-services" }

7 changes: 7 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

fn main() {
prost_build::compile_protos(&["src/experiments_msg_types.proto"], &["src/"]).unwrap();
}
8 changes: 2 additions & 6 deletions examples/experiment.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
use anyhow::Result;
use experiments::Experiments;
use nimbus_experiments::{AppContext, Experiments};
fn main() -> Result<()> {
viaduct_reqwest::use_reqwest_backend();
let exp = Experiments::new(
"https://kinto.dev.mozaws.net/v1/",
"default",
"messaging-collection",
);
let exp = Experiments::new(AppContext::default(), "./mydb");
let enrolled_exp = exp.get_enrolled_experiments();
exp.get_experiments().iter().for_each(|e| {
print!(
Expand Down
24 changes: 0 additions & 24 deletions ffi/Cargo.toml

This file was deleted.

37 changes: 0 additions & 37 deletions ffi/src/lib.rs

This file was deleted.

1 change: 0 additions & 1 deletion src/buckets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */


//! This might be where the bucketing logic can go
//! It would be different from current experimentation tools
//! There is a namespacing concept to allow users to be in multiple
Expand Down
6 changes: 4 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// Not implemented yet!!!
// This is purely boilerplate to communicate over the ffi
//! Not implemented yet!!!
//! This is purely boilerplate to communicate over the ffi
//! We should define real variants for our error and use proper
//! error propegation (we can use the `thiserror` crate for that)
use ffi_support::{ErrorCode, ExternError};
#[derive(Debug, thiserror::Error)]
pub enum Error {
Expand Down
3 changes: 3 additions & 0 deletions src/experiments.idl
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# This is a test file for defining WebIDL for uniffi
# For the time being, it is not used for anything!
# However, if we use uniffi in the future, we could define
# The api here. (Unless uniffi changes to a non WebIDL way (looking at you proc-macros))
namespace experiments {};
interface Experiments {
constructor();
Expand Down
24 changes: 24 additions & 0 deletions src/experiments_msg_types.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
syntax = "proto2";

// This kinda beats the purpose of using protobufs since we have one file here/
// And a duplicate in the glean PR, but bear with me :)
// Eventually once we figure out the details of where each part lives, we'll merge the proto files
// into one

package mozilla.telemetry.glean.protobuf;

option java_package = "mozilla.telemtery.glean";
option java_outer_classname = "MsgTypes";
option swift_prefix = "MsgTypes_";
option optimize_for = LITE_RUNTIME;

message AppContext {
optional string app_id = 1;
optional string app_version = 2;
optional string locale_language = 3;
optional string locale_country = 4;
optional string device_manufacturer = 5;
optional string device_model = 6;
optional string region = 7;
optional string debug_tag = 8;
}
69 changes: 69 additions & 0 deletions src/ffi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::os::raw::c_char;

use super::{error::Result, msg_types, AppContext, Experiments};
use ffi_support::{define_handle_map_deleter, ConcurrentHandleMap, ExternError, FfiStr};

lazy_static::lazy_static! {
static ref EXPERIMENTS: ConcurrentHandleMap<Experiments> = ConcurrentHandleMap::new();
}

#[no_mangle]
pub extern "C" fn experiments_new(
app_ctx: *const u8,
app_ctx_len: i32,
db_path: FfiStr<'_>,
error: &mut ExternError,
) -> u64 {
EXPERIMENTS.insert_with_result(error, || -> Result<Experiments> {
let app_ctx = unsafe {
from_protobuf_ptr::<AppContext, msg_types::AppContext>(app_ctx, app_ctx_len).unwrap()
}; // Todo: make the whole function unsafe and implement proper error handling in error.rs
log::info!("=================== Initializing experiments ========================");
Ok(Experiments::new(app_ctx, db_path.as_str()))
})
}

#[no_mangle]
pub extern "C" fn experiments_get_branch(
handle: u64,
branch: FfiStr<'_>,
error: &mut ExternError,
) -> *mut c_char {
EXPERIMENTS.call_with_result(error, handle, |experiment| -> Result<String> {
log::info!("==================== Getting branch ========================");
let branch_name = experiment.get_experiment_branch(branch.as_str())?;
Ok(branch_name)
})
}

define_handle_map_deleter!(EXPERIMENTS, experiements_destroy);

/// # Safety
/// data is a raw pointer to the protobuf data
/// get_buffer will return an error if the length is invalid,
/// or if the pointer is a null pointer
pub unsafe fn from_protobuf_ptr<T, F: prost::Message + Default + Into<T>>(
data: *const u8,
len: i32,
) -> anyhow::Result<T> {
let buffer = get_buffer(data, len)?;
let item: Result<F, _> = prost::Message::decode(buffer);
item.map(|inner| inner.into()).map_err(|e| e.into())
}

unsafe fn get_buffer<'a>(data: *const u8, len: i32) -> anyhow::Result<&'a [u8]> {
match len {
len if len < 0 => anyhow::bail!("Invalid length"),
0 => Ok(&[]),
_ => {
if data.is_null() {
anyhow::bail!("Null pointer")
}
Ok(std::slice::from_raw_parts(data, len as usize))
}
}
}
16 changes: 9 additions & 7 deletions src/http_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! This is a simple Http client that uses viaduct to retrieve experiment data from the server
//! Currently configured to use Kinto and the old schema, although that would change once we start
//! Working on the real Nimbus schema.
use super::Experiment;
use anyhow::Result;
use serde_derive::*;
Expand Down Expand Up @@ -66,13 +70,11 @@ impl SettingsClient for Client {
&self.bucket_name, &self.collection_name
);
let url = self.base_url.join(&path)?;
let req = Request::get(url)
.header(
"User-Agent",
"Experiments Rust Component <[email protected]>",
)?;
// Note: I removed the auth info which was for a test account that is public
// But gitgaurdian complained so I removed it.
let req = Request::get(url).header(
"User-Agent",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:77.0) Gecko/20100101 Firefox/77.0",
)?;
// TODO: Add authentication based on server requirements
let resp = self.make_request(req)?.json::<RecordsResponse>()?;
Ok(resp.data)
}
Expand Down
Loading

0 comments on commit 3f37db4

Please sign in to comment.