diff --git a/bin/build.sh b/bin/build.sh
index 0a5c59db..61f54ed9 100755
--- a/bin/build.sh
+++ b/bin/build.sh
@@ -23,6 +23,8 @@ sudo chown $MNML_USER: /opt/mnml
sudo mkdir -p /var/lib/mnml
sudo chown $MNML_USER: /var/lib/mnml
mkdir -p /var/lib/mnml/public
+mkdir -p /var/lib/mnml/public/imgs
+mkdir -p /var/lib/mnml/data
sudo mkdir -p /var/log/mnml
sudo chown $MNML_USER: /var/log/mnml
diff --git a/client/src/components/login.jsx b/client/src/components/login.jsx
index 8bab0983..5e8c6876 100644
--- a/client/src/components/login.jsx
+++ b/client/src/components/login.jsx
@@ -3,7 +3,7 @@ const preact = require('preact');
const { Component } = require('preact')
const { connect } = require('preact-redux');
-const { postData } = require('../utils');
+const { postData, errorToast } = require('../utils');
const addState = connect(
(state) => {
@@ -12,14 +12,26 @@ const addState = connect(
} = state;
function submitLogin(name, password) {
postData('/login', { name, password })
- .then(data => ws.connect())
- .catch(error => console.error(error));
+ .then(res => {
+ if (!res.ok) return errorToast(res);
+ res.text()
+ })
+ .then(res => {
+ ws.connect();
+ })
+ .catch(error => errorToast(error));
}
function submitRegister(name, password, code) {
postData('/register', { name, password, code })
- .then(data => ws.connect())
- .catch(error => console.error(error));
+ .then(res => {
+ if (!res.ok) return errorToast(res);
+ res.text()
+ })
+ .then(res => {
+ ws.connect();
+ })
+ .catch(error => errorToast(error));
}
return {
diff --git a/client/src/events.jsx b/client/src/events.jsx
index 7f975a1d..951488a2 100644
--- a/client/src/events.jsx
+++ b/client/src/events.jsx
@@ -194,7 +194,7 @@ function registerEvents(store) {
function errorPrompt(type) {
const message = errMessages[type];
const OK_BUTTON = '';
- toast.info({
+ toast.error({
theme: 'dark',
color: 'black',
timeout: false,
diff --git a/client/src/utils.jsx b/client/src/utils.jsx
index 3dcf01b5..6a3bb804 100644
--- a/client/src/utils.jsx
+++ b/client/src/utils.jsx
@@ -1,5 +1,6 @@
const preact = require('preact');
const get = require('lodash/get');
+const toast = require('izitoast');
const shapes = require('./components/shapes');
@@ -369,6 +370,16 @@ function postData(url = '/', data = {}) {
});
}
+function errorToast(message) {
+ toast.error({
+ position: 'topRight',
+ drag: false,
+ close: false,
+ message,
+ });
+}
+
+
module.exports = {
stringSort,
convertItem,
@@ -377,6 +388,7 @@ module.exports = {
getCombatSequence,
getCombatText,
postData,
+ errorToast,
NULL_UUID,
STATS,
COLOURS,
diff --git a/etc/nginx/sites-available/mnml.gg.PRODUCTION.nginx.conf b/etc/nginx/sites-available/mnml.gg.PRODUCTION.nginx.conf
index 4b87e27d..f80ca78e 100644
--- a/etc/nginx/sites-available/mnml.gg.PRODUCTION.nginx.conf
+++ b/etc/nginx/sites-available/mnml.gg.PRODUCTION.nginx.conf
@@ -1,3 +1,6 @@
+error_log /var/log/mnml/nginx.error.log;
+access_log /var/log/mnml/nginx.access.log;
+
upstream mnml {
server 127.0.0.1:40000;
}
diff --git a/server/src/construct.rs b/server/src/construct.rs
index 6e2c7ceb..3f2b04c0 100644
--- a/server/src/construct.rs
+++ b/server/src/construct.rs
@@ -12,6 +12,7 @@ use skill::{Skill, Cast, Immunity, Disable, Event};
use effect::{Cooldown, Effect, Colour};
use spec::{Spec};
use item::{Item};
+use img::{img_molecular_create};
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct Colours {
@@ -857,8 +858,9 @@ pub fn construct_spawn(tx: &mut Transaction, params: ConstructSpawnParams, accou
let _returned = result.iter().next().ok_or(err_msg("no row returned"))?;
- // info!("{:?} spawned construct {:}", account.id, construct.id);
+ img_molecular_create(construct.img)?;
+ info!("spawned construct account={:} construct={:?}", account, construct);
return Ok(construct);
}
diff --git a/server/src/img.rs b/server/src/img.rs
new file mode 100644
index 00000000..017109ec
--- /dev/null
+++ b/server/src/img.rs
@@ -0,0 +1,24 @@
+use uuid::Uuid;
+use rand::prelude::*;
+use std::fs::copy;
+
+use failure::Error;
+use failure::err_msg;
+
+pub fn img_molecular_create(id: Uuid) -> Result {
+ let mut rng = thread_rng();
+
+ for _i in 0..100 {
+ let mol: u32 = rng.gen_range(0, 10000);
+ let src = format!("/var/lib/mnml/data/molecules/{}.svg", mol);
+ println!("{:?}", src);
+ let dest = format!("/var/lib/mnml/public/imgs/{}.svg", id);
+ println!("{:?}", dest);
+ if let Ok(_bytes) = copy(&src, &dest) {
+ info!("new molecule avatar generated src={:?} dest={:?}", src, dest);
+ return Ok(id);
+ }
+ }
+
+ return Err(err_msg("too many missing molecules. wrong directory?"))
+}
\ No newline at end of file
diff --git a/server/src/main.rs b/server/src/main.rs
index 7ee34ef6..dfa19ada 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -30,6 +30,7 @@ mod effect;
mod game;
mod instance;
mod item;
+mod img;
mod mob;
mod mtx;
mod names;
diff --git a/server/src/net.rs b/server/src/net.rs
index 21d67e70..f737c849 100644
--- a/server/src/net.rs
+++ b/server/src/net.rs
@@ -12,7 +12,7 @@ use r2d2::{Pool};
use r2d2::{PooledConnection};
use r2d2_postgres::{TlsMode, PostgresConnectionManager};
-use rpc::{RpcErrorResponse, AccountLoginParams, AccountCreateParams};
+use rpc::{AccountLoginParams, AccountCreateParams};
use warden::{warden};
use pubsub::{pg_listen};
use ws::{connect};
@@ -24,7 +24,12 @@ pub type PgPool = Pool;
const DB_POOL_SIZE: u32 = 20;
-#[derive(Fail, Debug)]
+#[derive(Debug,Clone,Serialize,Deserialize)]
+pub struct JsonError {
+ pub err: String
+}
+
+#[derive(Fail, Debug, Serialize, Deserialize)]
pub enum MnmlHttpError {
// User Facing Errors
#[fail(display="internal server error")]
@@ -33,16 +38,22 @@ pub enum MnmlHttpError {
Unauthorized,
#[fail(display="bad request")]
BadRequest,
+ #[fail(display="account name taken or invalid")]
+ AccountNameTaken,
+ #[fail(display="password unacceptable. must be > 11 characters")]
+ PasswordUnacceptable,
+ #[fail(display="invalid code. https://discord.gg/YJJgurM")]
+ InvalidCode,
}
impl ResponseError for MnmlHttpError {
fn error_response(&self) -> HttpResponse {
match *self {
MnmlHttpError::ServerError => HttpResponse::InternalServerError()
- .json(RpcErrorResponse { err: self.to_string() }),
+ .json(JsonError { err: self.to_string() }),
MnmlHttpError::BadRequest => HttpResponse::BadRequest()
- .json(RpcErrorResponse { err: self.to_string() }),
+ .json(JsonError { err: self.to_string() }),
MnmlHttpError::Unauthorized => HttpResponse::Unauthorized()
.cookie(Cookie::build("x-auth-token", "")
@@ -51,7 +62,16 @@ impl ResponseError for MnmlHttpError {
.same_site(SameSite::Strict)
.max_age(-1) // 1 week aligns with db set
.finish())
- .json(RpcErrorResponse { err: self.to_string() }),
+ .json(JsonError { err: self.to_string() }),
+
+ MnmlHttpError::AccountNameTaken => HttpResponse::BadRequest()
+ .json(JsonError { err: self.to_string() }),
+
+ MnmlHttpError::PasswordUnacceptable => HttpResponse::BadRequest()
+ .json(JsonError { err: self.to_string() }),
+
+ MnmlHttpError::InvalidCode => HttpResponse::BadRequest()
+ .json(JsonError { err: self.to_string() }),
}
}
}
diff --git a/server/src/rpc.rs b/server/src/rpc.rs
index 1f535c8d..be22a991 100644
--- a/server/src/rpc.rs
+++ b/server/src/rpc.rs
@@ -213,11 +213,6 @@ fn handle_dev_resolve(data: Vec) -> Result {
Ok(RpcResult::DevResolutions(dev_resolve(msg.params.a, msg.params.b, msg.params.skill)))
}
-#[derive(Debug,Clone,Serialize,Deserialize)]
-pub struct RpcErrorResponse {
- pub err: String
-}
-
#[derive(Debug,Clone,Serialize,Deserialize)]
pub enum RpcResult {
AccountState(Account),
diff --git a/server/src/ws.rs b/server/src/ws.rs
index 2bbef5d3..faaba91d 100644
--- a/server/src/ws.rs
+++ b/server/src/ws.rs
@@ -6,9 +6,9 @@ use actix::prelude::*;
use account::{Account};
use serde_cbor::{to_vec};
-use net::{PgPool, State, MnmlHttpError};
+use net::{PgPool, State, MnmlHttpError, JsonError};
-use rpc::{receive, RpcResult, RpcErrorResponse};
+use rpc::{receive, RpcResult};
const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5);
const CLIENT_TIMEOUT: Duration = Duration::from_secs(10);
@@ -73,7 +73,7 @@ impl StreamHandler for MnmlSocket {
ctx.binary(response);
},
Err(e) => {
- let response = to_vec(&RpcErrorResponse { err: e.to_string() })
+ let response = to_vec(&JsonError { err: e.to_string() })
.expect("failed to serialize error response");
ctx.binary(response);
}