196 lines
5.1 KiB
Rust
196 lines
5.1 KiB
Rust
use std::convert::TryFrom;
|
|
use uuid::Uuid;
|
|
// use rand::prelude::*;
|
|
|
|
use serde_cbor::{from_slice};
|
|
use postgres::transaction::Transaction;
|
|
|
|
use failure::Error;
|
|
use failure::err_msg;
|
|
|
|
use account;
|
|
use account::Account;
|
|
|
|
use construct::{Construct, construct_select, construct_write};
|
|
use img::{img_molecular_write};
|
|
|
|
pub const FREE_MTX: [MtxVariant; 2] = [
|
|
MtxVariant::Rename,
|
|
MtxVariant::Reimage,
|
|
];
|
|
|
|
#[derive(Debug,Copy,Clone,Serialize,Deserialize)]
|
|
pub enum MtxVariant {
|
|
Rename,
|
|
Reimage,
|
|
ArchitectureMolecular,
|
|
ArchitectureInvader,
|
|
}
|
|
|
|
impl MtxVariant {
|
|
fn to_sql(&self) -> String {
|
|
format!("{:?}", *self)
|
|
}
|
|
}
|
|
|
|
// could use postgres-derive
|
|
// but enums in pg are a bit of a pain
|
|
impl TryFrom<String> for MtxVariant {
|
|
type Error = Error;
|
|
fn try_from(v: String) -> Result<MtxVariant, Error> {
|
|
match v.as_ref() {
|
|
"Rename" => Ok(MtxVariant::Rename),
|
|
"Reimage" => Ok(MtxVariant::Reimage),
|
|
"ArchitectureMolecular" => Ok(MtxVariant::ArchitectureMolecular),
|
|
"ArchitectureInvader" => Ok(MtxVariant::ArchitectureInvader),
|
|
_ => Err(format_err!("mtx variant not found variant={:?}", v)),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug,Copy,Clone,Serialize,Deserialize)]
|
|
pub struct Mtx {
|
|
id: Uuid,
|
|
account: Uuid,
|
|
variant: MtxVariant,
|
|
}
|
|
|
|
pub fn apply(tx: &mut Transaction, account: &Account, variant: MtxVariant, construct_id: Uuid) -> Result<Vec<Construct>, Error> {
|
|
let mtx = select(tx, variant, account.id)?;
|
|
let construct = construct_select(tx, construct_id, account.id)?;
|
|
|
|
match mtx.variant {
|
|
MtxVariant::Reimage => reimage(tx, construct)?,
|
|
_ => unimplemented!(),
|
|
};
|
|
|
|
account::debit(tx, account.id, 1)?;
|
|
account::account_constructs(tx, account)
|
|
}
|
|
|
|
pub fn reimage(tx: &mut Transaction, mut construct: Construct) -> Result<Construct, Error> {
|
|
construct = construct.new_img();
|
|
|
|
img_molecular_write(construct.img)?;
|
|
|
|
construct = construct_write(tx, construct)?;
|
|
|
|
Ok(construct)
|
|
}
|
|
|
|
pub fn select(tx: &mut Transaction, variant: MtxVariant, account: Uuid) -> Result<Mtx, Error> {
|
|
let query = "
|
|
SELECT id, account, variant
|
|
FROM mtx
|
|
WHERE account = $1
|
|
AND variant = $2
|
|
FOR UPDATE;
|
|
";
|
|
|
|
let result = tx
|
|
.query(query, &[&account, &variant.to_sql()])?;
|
|
|
|
if let Some(row) = result.iter().next() {
|
|
let id: Uuid = row.get(0);
|
|
let account: Uuid = row.get(1);
|
|
let v_str: String = row.get(2);
|
|
let variant = MtxVariant::try_from(v_str)?;
|
|
|
|
Ok(Mtx { id, account, variant })
|
|
} else {
|
|
Err(format_err!("mtx not found account={:?} variant={:?}", account, variant))
|
|
}
|
|
}
|
|
|
|
impl Mtx {
|
|
pub fn new(variant: MtxVariant, account: Uuid) -> Mtx {
|
|
match variant {
|
|
_ => Mtx { id: Uuid::new_v4(), account, variant },
|
|
// MtxVariant::ArchitectureInvader => Mtx { id: Uuid::new_v4(), account, variant: self },
|
|
// MtxVariant::ArchitectureMolecular => Mtx { id: Uuid::new_v4(), account, variant: self },
|
|
}
|
|
}
|
|
|
|
pub fn account_list(tx: &mut Transaction, account: Uuid) -> Result<Vec<Mtx>, Error> {
|
|
let query = "
|
|
SELECT data, id
|
|
FROM mtx
|
|
WHERE account = $1;
|
|
";
|
|
|
|
let result = tx
|
|
.query(query, &[&account])?;
|
|
|
|
let values = result.into_iter().filter_map(|row| {
|
|
let bytes: Vec<u8> = row.get(0);
|
|
// let id: Uuid = row.get(1);
|
|
|
|
match from_slice::<Mtx>(&bytes) {
|
|
Ok(i) => Some(i),
|
|
Err(e) => {
|
|
warn!("{:?}", e);
|
|
None
|
|
}
|
|
}
|
|
}).collect::<Vec<Mtx>>();
|
|
|
|
return Ok(values);
|
|
}
|
|
|
|
pub fn delete(tx: &mut Transaction, id: Uuid) -> Result<(), Error> {
|
|
let query = "
|
|
DELETE
|
|
FROM mtx
|
|
WHERE id = $1;
|
|
";
|
|
|
|
let result = tx
|
|
.execute(query, &[&id])?;
|
|
|
|
if result != 1 {
|
|
return Err(format_err!("unable to delete mtx {:?}", id));
|
|
}
|
|
|
|
info!("mtx deleted {:?}", id);
|
|
|
|
return Ok(());
|
|
}
|
|
|
|
pub fn insert(&self, tx: &mut Transaction) -> Result<&Mtx, Error> {
|
|
let query = "
|
|
INSERT INTO mtx (id, account, variant)
|
|
VALUES ($1, $2, $3)
|
|
RETURNING id, account;
|
|
";
|
|
|
|
let result = tx
|
|
.query(query, &[&self.id, &self.account, &self.variant.to_sql()])?;
|
|
|
|
result.iter().next().ok_or(err_msg("mtx not written"))?;
|
|
|
|
info!("wrote mtx {:?}", self);
|
|
|
|
return Ok(self);
|
|
}
|
|
|
|
// pub fn update(&self, tx: &mut Transaction) -> Result<&Mtx, Error> {
|
|
// let query = "
|
|
// UPDATE mtx
|
|
// SET data = $1, updated_at = now()
|
|
// WHERE id = $2
|
|
// RETURNING id, data;
|
|
// ";
|
|
|
|
// let result = tx
|
|
// .query(query, &[&self.id, &to_vec(self)?])?;
|
|
|
|
// if let None = result.iter().next() {
|
|
// return Err(err_msg("mtx not written"));
|
|
// }
|
|
|
|
// info!("wrote mtx {:?}", self);
|
|
|
|
// return Ok(self);
|
|
// }
|
|
}
|