Skip to content

Commit

Permalink
wrapping up account deletion (#6)
Browse files Browse the repository at this point in the history
* wrapping up account deletion

* bump to v0.3.4

* cargo updatez

* restrict concurrent table participation

* more readme updates
  • Loading branch information
dadleyy authored Jan 7, 2022
1 parent f610381 commit dcfc451
Show file tree
Hide file tree
Showing 16 changed files with 204 additions and 33 deletions.
3 changes: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ STICKBOT_REDIS_PORT=""
STICKBOT_REDIS_PASSWORD=""

STICKBOT_ONCORE_URL_ENV=""
STICKBOT_ADMIN_EMAILS=""
STICKBOT_MAX_ACTIVE_TABLES_PER_PLAYER=

BOXBOT_WORKER_DELAY=1000
STICKBOT_ADMIN_EMAILS=""
26 changes: 13 additions & 13 deletions Cargo.lock

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

5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@ This is a simple craps game engine implemented in rust.
| :video_camera: |
| --- |
| ![twowaiyo](https://user-images.githubusercontent.com/1545348/139085831-df999c07-08c0-49dd-99d6-7ad987dec412.gif) |


#### Web Application

The web application interface can be found at [/workspace/stickbot](/workspace/stickbot/README.md).
2 changes: 1 addition & 1 deletion workspace/bankah/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bankah"
version = "0.3.3"
version = "0.3.4"
edition = "2018"

[dependencies]
Expand Down
24 changes: 19 additions & 5 deletions workspace/bankah/src/jobs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,21 @@ pub struct JobWapper<T> {
pub attempts: u8,
}

impl<T> JobWapper<T> {
pub fn retry(self) -> Self {
let JobWapper { job, id, attempts } = self;
JobWapper {
job,
id,
attempts: attempts + 1,
}
}
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub enum TableAdminJob {
ReindexPopulations,
CleanupPlayerData(String),
}

#[derive(Debug, Deserialize, Serialize, Clone)]
Expand All @@ -43,12 +55,14 @@ impl TableJob {
}
}

pub fn retry(&self) -> Option<Self> {
pub fn admin(job: TableAdminJob) -> Self {
let id = uuid::Uuid::new_v4();
TableJob::Admin(JobWapper { job, id, attempts: 0 })
}

pub fn retry(self) -> Option<Self> {
match self {
TableJob::Bet(inner) => Some(TableJob::Bet(JobWapper {
attempts: inner.attempts + 1,
..inner.clone()
})),
TableJob::Bet(inner) => Some(TableJob::Bet(inner.retry())),
_ => None,
}
}
Expand Down
1 change: 1 addition & 0 deletions workspace/bankah/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,5 @@ pub struct PlayerState {
pub emails: Vec<String>,
pub nickname: String,
pub balance: u32,
pub tables: Vec<String>,
}
2 changes: 1 addition & 1 deletion workspace/stickbot/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "stickbot"
version = "0.3.3"
version = "0.3.4"
edition = "2018"

[lib]
Expand Down
31 changes: 31 additions & 0 deletions workspace/stickbot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## Stickbot

This a [rust] application is the http-based web api backend for [twowaiyo], using a simple REST api to allow players
to join, participate and leave games. The [emberjs] web-browser frontend is located at [github.com/dadleyy/oncore].

#### Developing Locally

The web backend currently relies on three third party services:

1. [mongodb] for peristing table and player state.
2. [redis] for the asynchronous background job queue.
3. [auth0] for handling the integration with third party OAuth providers.

At this time, free, hosted instances of mongodb and redis are available at [mongodb.com/cloud][mdbc] and [redislabs]
respectively. After creating the necessary accounts (or leveraging on-premise version of these), the `.env.example`
file located at the root of this repository can be used as a template for setting the credentials for authenticating
with these services.

Once the environment variables have been prepared, the main web process and background worker can be started using the
appropriate `cargo` aliases:


[rust]: https://www.rust-lang.org/
[twowaiyo]: https://github.com/dadleyy/twowaiyo
[mongodb]: https://www.mongodb.com/
[redis]: https://redis.io/
[mdbc]: https://www.mongodb.com/cloud
[redislabs]: https://app.redislabs.com/#/login
[auth0]: https://auth0.com/
[github.com/dadleyy/oncore]: https://github.com/dadleyy/oncore
[emberjs]: https://emberjs.com/
7 changes: 5 additions & 2 deletions workspace/stickbot/src/bin/boxbot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::time::Duration;

use stickbot;

use bankah::jobs::TableJob;
use bankah::jobs::{TableAdminJob, TableJob};

const POP_CMD: kramer::Command<&'static str, &'static str> =
kramer::Command::List::<_, &str>(kramer::ListCommand::Pop(
Expand Down Expand Up @@ -62,7 +62,10 @@ async fn work(services: &stickbot::Services) -> Result<()> {

let id = job.id();
let result = match &job {
TableJob::Admin(inner) => stickbot::processors::admin::reindex(&services, &inner.job).await,
TableJob::Admin(inner) => match &inner.job {
TableAdminJob::ReindexPopulations => stickbot::processors::admin::reindex(&services, &inner.job).await,
TableAdminJob::CleanupPlayerData(id) => stickbot::processors::admin::cleanup(&services, &id).await,
},
TableJob::Bet(inner) => stickbot::processors::bet(&services, &inner.job).await,
TableJob::Roll(inner) => stickbot::processors::roll(&services, &inner.job).await,
};
Expand Down
3 changes: 3 additions & 0 deletions workspace/stickbot/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@ pub const EMPTY_RESPONSE: &'static str = "";
pub const BOXBOT_DELAY_ENV: &'static str = "BOXBOT_WORKER_DELAY";

pub const STICKBOT_ADMIN_EMAILS_ENV: &'static str = "STICKBOT_ADMIN_EMAILS";

pub const STICKBOT_DEFAULT_MAX_ACTIVE_TABLES_PER_PLAYER: usize = 2;
pub const STICKBOT_MAX_ACTIVE_TABLES_PER_PLAYER_ENV: &'static str = "STICKBOT_MAX_ACTIVE_TABLES_PER_PLAYER";
62 changes: 59 additions & 3 deletions workspace/stickbot/src/processors/admin.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use bankah::jobs::{JobError, TableAdminJob, TableJobOutput};
use async_std::stream::StreamExt;

use crate::db::doc;
use bankah::jobs::{JobError, TableAdminJob, TableJob, TableJobOutput};

use crate::db::{doc, FindOneAndReplaceOptions, ReturnDocument};
use crate::Services;

pub async fn reindex<'a>(services: &Services, job: &TableAdminJob) -> Result<TableJobOutput, JobError> {
pub async fn reindex(services: &Services, job: &TableAdminJob) -> Result<TableJobOutput, JobError> {
log::info!("attempting to reindex table populations - {:?}", job);
let tables = services.tables();
let pipeline = vec![
Expand All @@ -23,3 +25,57 @@ pub async fn reindex<'a>(services: &Services, job: &TableAdminJob) -> Result<Tab
})?;
Ok(TableJobOutput::AdminOk)
}

pub async fn cleanup(services: &Services, id: &String) -> Result<TableJobOutput, JobError> {
log::debug!("cleaning up player '{}'", id);

let mut tables = match services
.tables()
.find(doc! { format!("seats.{}", id): { "$exists": true } }, None)
.await
{
Err(error) => {
log::warn!("unable to find any tables for user - {}", error);
return Ok(TableJobOutput::AdminOk);
}
Ok(cursor) => cursor,
};

while let Some(doc) = tables.next().await {
let mut state = match doc {
Err(error) => {
log::warn!("error loading next able - {}", error);
continue;
}
Ok(table) => table,
};

state.seats = state
.seats
.into_iter()
.filter(|(seat, _)| &seat.to_string() != id)
.collect();

let opts = FindOneAndReplaceOptions::builder()
.return_document(ReturnDocument::After)
.build();

if let Err(error) = services
.tables()
.find_one_and_replace(crate::db::lookup_for_uuid(&state.id), &state, opts)
.await
{
log::warn!("failed cleanup '{}' on table '{}': {}", id, &state.id, error);
}

log::debug!("next table - {:?}", state);
}

log::debug!("cleanup for player '{}' complete, reindexing tables", id);

if let Err(error) = services.queue(&TableJob::reindex()).await {
log::warn!("unable to queue reindexing job - {}", error);
}

Ok(TableJobOutput::AdminOk)
}
33 changes: 31 additions & 2 deletions workspace/stickbot/src/routes/account.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
use crate::web::{cookie as get_cookie, Error, Request, Result};
use serde::Serialize;

use crate::db;
use crate::web::{cookie as get_cookie, Body, Error, Request, Response, Result};

#[derive(Serialize)]
struct DeletionResponsePayload {
id: String,
}

pub async fn delete(request: Request) -> Result {
let cookie = get_cookie(&request).ok_or(Error::from_str(404, "no-cook"))?;
Expand All @@ -9,7 +17,28 @@ pub async fn delete(request: Request) -> Result {
.and_then(|authority| authority.player())
.ok_or(Error::from_str(404, ""))?;

let players = request.state().players();

log::debug!("player {} deleting account", player.id);

Ok("".into())
players
.delete_one(db::doc! { "id": player.id.to_string() }, None)
.await
.map_err(|error| {
log::warn!("unable to delete player record: {}", error);
error
})?;

log::debug!("player document '{}' deleted, queuing cleanup job", player.id);

let job = bankah::jobs::TableJob::admin(bankah::jobs::TableAdminJob::CleanupPlayerData(player.id.to_string()));
request.state().queue(&job).await.map_err(|error| {
log::warn!("unable to schedule player cleanup job - {}", error);
error
})?;

Body::from_json(&DeletionResponsePayload {
id: player.id.to_string(),
})
.map(|body| Response::builder(200).body(body).build())
}
1 change: 1 addition & 0 deletions workspace/stickbot/src/routes/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ fn mkplayer(userinfo: &UserInfo) -> std::io::Result<db::bson::Document> {
nickname,
balance: 10000,
emails: vec![userinfo.email.clone()],
tables: vec![],
};

bson::to_bson(&state)
Expand Down
Loading

0 comments on commit dcfc451

Please sign in to comment.