data access interface
This commit is contained in:
parent
d0fe80e3cf
commit
2fb97cc2b6
@ -61,6 +61,7 @@ impl<P: ServerPacket + std::fmt::Debug, E: std::fmt::Debug> Client<P, E> {
|
||||
|
||||
// TODO: this may need to pad to 8 bytes for bb cipher
|
||||
fn send(&mut self, pkt: &dyn PSOPacket) {
|
||||
println!("[send] {:?}", pkt);
|
||||
let buf = pkt.as_bytes();
|
||||
let mut cbuf = self.cipher_out.encrypt(&buf).unwrap();
|
||||
self.send_buffer.append(&mut cbuf);
|
||||
@ -90,6 +91,7 @@ impl<P: ServerPacket + std::fmt::Debug, E: std::fmt::Debug> Client<P, E> {
|
||||
|
||||
match pkt {
|
||||
Ok(pkt) => {
|
||||
println!("[recv] {:?}", pkt);
|
||||
let response = self.state.handle(&pkt);
|
||||
for r in response {
|
||||
self.send(&*r);
|
||||
@ -98,7 +100,7 @@ impl<P: ServerPacket + std::fmt::Debug, E: std::fmt::Debug> Client<P, E> {
|
||||
Err(err) => {
|
||||
match err {
|
||||
PacketNetworkError::ClientDisconnected => self.running = false,
|
||||
_ => println!("error recv-ing packet with {:?}: {:?}", self.socket, err),
|
||||
_ => {} //println!("error recv-ing packet with {:?}: {:?}", self.socket, err),
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -3,11 +3,6 @@ use std::net;
|
||||
use rand::{Rng, RngCore};
|
||||
use bcrypt::{DEFAULT_COST, hash, verify};
|
||||
|
||||
use diesel::r2d2;
|
||||
use diesel::prelude::*;
|
||||
use diesel::pg::PgConnection;
|
||||
use elseware::schema::*;
|
||||
|
||||
use libpso::packet::login::*;
|
||||
use libpso::{PacketParseError, PSOPacket};
|
||||
use libpso::crypto::{CipherError, PSOCipher, NullCipher};
|
||||
@ -21,11 +16,11 @@ use elseware::common::client::Client;
|
||||
use elseware::common::serverstate::{ServerPacket, ServerState, OnConnect};
|
||||
use elseware::common::util::array_to_utf8;
|
||||
|
||||
use crate::dataaccess::DataAccess;
|
||||
use crate::login::{SharedLoginState, get_login_status};
|
||||
use crate::models::UserAccount;
|
||||
|
||||
pub const CHARACTER_PORT: u16 = 12001;
|
||||
type ConnectionPool = r2d2::Pool<r2d2::ConnectionManager<PgConnection>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CharacterError {
|
||||
@ -47,13 +42,13 @@ impl ServerPacket for CharacterPacket {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CharacterServerState {
|
||||
shared_state: SharedLoginState,
|
||||
pub struct CharacterServerState<DA: DataAccess> {
|
||||
shared_state: SharedLoginState<DA>,
|
||||
user: Option<UserAccount>,
|
||||
}
|
||||
|
||||
impl CharacterServerState {
|
||||
fn new(shared_state: SharedLoginState) -> CharacterServerState {
|
||||
impl<DA: DataAccess> CharacterServerState<DA> {
|
||||
fn new(shared_state: SharedLoginState<DA>) -> CharacterServerState<DA> {
|
||||
CharacterServerState {
|
||||
shared_state: shared_state,
|
||||
user: None,
|
||||
@ -61,7 +56,7 @@ impl CharacterServerState {
|
||||
}
|
||||
|
||||
fn validate_login(&mut self, pkt: &Login) -> Box<PktVec> {
|
||||
match get_login_status(&self.shared_state.connection_pool, pkt) {
|
||||
match get_login_status(&self.shared_state.data_access, pkt) {
|
||||
Ok(user) => {
|
||||
let mut response = LoginResponse::by_status(AccountStatus::Ok, pkt.security_data);
|
||||
response.guildcard = user.guildcard.map_or(0, |gc| gc) as u32;
|
||||
@ -80,7 +75,7 @@ impl CharacterServerState {
|
||||
}
|
||||
}
|
||||
|
||||
impl ServerState for CharacterServerState {
|
||||
impl<DA: DataAccess> ServerState for CharacterServerState<DA> {
|
||||
type Packet = CharacterPacket;
|
||||
type PacketError = CharacterError;
|
||||
|
||||
@ -107,7 +102,6 @@ impl ServerState for CharacterServerState {
|
||||
CharacterPacket::RequestSettings(_req) => {
|
||||
self.get_settings()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -116,7 +110,7 @@ impl ServerState for CharacterServerState {
|
||||
|
||||
|
||||
|
||||
pub fn new_client(socket: mio::tcp::TcpStream, shared_state: SharedLoginState) {
|
||||
pub fn new_client<DA: DataAccess + 'static>(socket: mio::tcp::TcpStream, shared_state: SharedLoginState<DA>) {
|
||||
let state = CharacterServerState::new(shared_state);
|
||||
let client = Client::new(socket, Box::new(state));
|
||||
client.io_loop();
|
||||
|
48
src/login/dataaccess.rs
Normal file
48
src/login/dataaccess.rs
Normal file
@ -0,0 +1,48 @@
|
||||
use diesel::r2d2;
|
||||
use diesel::prelude::*;
|
||||
use diesel::pg::PgConnection;
|
||||
|
||||
use crate::models::*;
|
||||
|
||||
type ConnectionPool = r2d2::Pool<r2d2::ConnectionManager<PgConnection>>;
|
||||
|
||||
pub trait DataAccess {
|
||||
fn get_user_by_id(&self, id: u32) -> Option<UserAccount> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn get_user_by_name(&self, username: String) -> Option<UserAccount> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DBAccess {
|
||||
connection_pool: ConnectionPool,
|
||||
}
|
||||
|
||||
impl DBAccess {
|
||||
pub fn new(pool: ConnectionPool) -> DBAccess {
|
||||
DBAccess {
|
||||
connection_pool: pool,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl DataAccess for DBAccess {
|
||||
fn get_user_by_name(&self, name: String) -> Option<UserAccount> {
|
||||
use elseware::schema::user_accounts::dsl::{user_accounts, username};
|
||||
self.connection_pool.get()
|
||||
.map(|conn| {
|
||||
user_accounts.filter(username.eq(name)).load::<UserAccount>(&conn)
|
||||
.map(|mut user| user.pop()).unwrap_or(None)
|
||||
})
|
||||
.unwrap_or(None)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*impl DataAccess for DatabaseAccess {
|
||||
}*/
|
||||
|
@ -1,13 +1,10 @@
|
||||
// TODO: rename this module to auth
|
||||
|
||||
use std::net;
|
||||
|
||||
use rand::{Rng, RngCore};
|
||||
use bcrypt::{DEFAULT_COST, hash, verify};
|
||||
|
||||
use diesel::r2d2;
|
||||
use diesel::prelude::*;
|
||||
use diesel::pg::PgConnection;
|
||||
use elseware::schema::*;
|
||||
|
||||
use libpso::packet::login::*;
|
||||
use libpso::{PacketParseError, PSOPacket};
|
||||
use libpso::crypto::{CipherError, PSOCipher, NullCipher};
|
||||
@ -16,15 +13,16 @@ use libpso::crypto::bb::PSOBBCipher;
|
||||
use elseware::pktvec;
|
||||
use elseware::common::pktvec::PktVec;
|
||||
use elseware::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY};
|
||||
use elseware::common::network::{PacketNetworkError};
|
||||
//use elseware::common::network::{PacketNetworkError};
|
||||
use elseware::common::client::Client;
|
||||
use elseware::common::serverstate::{ServerPacket, ServerState, OnConnect};
|
||||
use elseware::common::util::array_to_utf8;
|
||||
|
||||
use crate::dataaccess::DataAccess;
|
||||
use crate::models::UserAccount;
|
||||
|
||||
pub const LOGIN_PORT: u16 = 12000;
|
||||
type ConnectionPool = r2d2::Pool<r2d2::ConnectionManager<PgConnection>>;
|
||||
//type ConnectionPool = r2d2::Pool<r2d2::ConnectionManager<PgConnection>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LoginError {
|
||||
@ -46,78 +44,45 @@ impl ServerPacket for LoginPacket {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SharedLoginState {
|
||||
pub connection_pool: ConnectionPool,
|
||||
pub struct SharedLoginState<DA: DataAccess> {
|
||||
pub data_access: DA,
|
||||
}
|
||||
|
||||
impl SharedLoginState {
|
||||
pub fn new(pool: ConnectionPool) -> SharedLoginState {
|
||||
impl<DA: DataAccess> SharedLoginState<DA> {
|
||||
pub fn new(data_access: DA) -> SharedLoginState<DA> {
|
||||
SharedLoginState {
|
||||
connection_pool: pool,
|
||||
data_access: data_access,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct LoginServerState {
|
||||
pub shared_state: SharedLoginState,
|
||||
pub struct LoginServerState<DA: DataAccess> {
|
||||
pub shared_state: SharedLoginState<DA>,
|
||||
}
|
||||
|
||||
pub fn get_login_status(connection_pool: &ConnectionPool, pkt: &Login) -> Result<UserAccount, AccountStatus> {
|
||||
use elseware::schema::user_accounts::dsl::{user_accounts, username};
|
||||
connection_pool.get()
|
||||
.map_err(|_err| AccountStatus::Error)
|
||||
.and_then(|conn| {
|
||||
array_to_utf8(pkt.username)
|
||||
.map(|username_str| {
|
||||
(conn, username_str)
|
||||
})
|
||||
.map_err(|err| {
|
||||
println!("utf err: {:?}", err);
|
||||
AccountStatus::Error
|
||||
})
|
||||
})
|
||||
.and_then(|(conn, username_str)| {
|
||||
user_accounts.filter(username.eq(username_str)).load::<UserAccount>(&conn)
|
||||
.map_err(|err| {
|
||||
println!("sql err: {:?}", err);
|
||||
AccountStatus::Error
|
||||
})
|
||||
})
|
||||
.and_then(|mut result| {
|
||||
result.pop().ok_or(AccountStatus::InvalidUser)
|
||||
})
|
||||
.and_then(|user| {
|
||||
array_to_utf8(pkt.password)
|
||||
.map(|password| {
|
||||
(user, password)
|
||||
})
|
||||
.map_err(|_err| AccountStatus::Error)
|
||||
})
|
||||
.and_then(|(user, password)| {
|
||||
bcrypt::verify(password, user.password.as_str())
|
||||
.map_err(|err| {
|
||||
println!("bcrypt err: {:?}", err);
|
||||
AccountStatus::Error
|
||||
})
|
||||
.and_then(|correct_password| {
|
||||
match correct_password {
|
||||
true => Ok(user),
|
||||
false => Err(AccountStatus::InvalidPassword),
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
pub fn get_login_status(data_access: &dyn DataAccess, pkt: &Login) -> Result<UserAccount, AccountStatus> {
|
||||
let username = array_to_utf8(pkt.username).map_err(|_err| AccountStatus::Error)?;
|
||||
let password = array_to_utf8(pkt.password).map_err(|_err| AccountStatus::Error)?;
|
||||
let user = data_access.get_user_by_name(username).ok_or(AccountStatus::InvalidUser)?;
|
||||
let verified = bcrypt::verify(password, user.password.as_str()).map_err(|_err| AccountStatus::Error)?;
|
||||
match verified {
|
||||
true => Ok(user),
|
||||
false => Err(AccountStatus::InvalidPassword)
|
||||
}
|
||||
}
|
||||
|
||||
impl LoginServerState {
|
||||
fn new(shared_state: SharedLoginState) -> LoginServerState {
|
||||
|
||||
impl<DA: DataAccess> LoginServerState<DA> {
|
||||
fn new(shared_state: SharedLoginState<DA>) -> LoginServerState<DA> {
|
||||
LoginServerState {
|
||||
shared_state: shared_state,
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_login(&mut self, pkt: &Login) -> Box<PktVec> {
|
||||
match get_login_status(&self.shared_state.connection_pool, pkt) {
|
||||
match get_login_status(&self.shared_state.data_access, pkt) {
|
||||
Ok(_user) => {
|
||||
let response = LoginResponse::by_status(AccountStatus::Ok, pkt.security_data);
|
||||
let ip = net::Ipv4Addr::new(127,0,0,1);
|
||||
@ -131,7 +96,7 @@ impl LoginServerState {
|
||||
}
|
||||
}
|
||||
|
||||
impl ServerState for LoginServerState {
|
||||
impl<DA: DataAccess> ServerState for LoginServerState<DA> {
|
||||
type Packet = LoginPacket;
|
||||
type PacketError = LoginError;
|
||||
|
||||
@ -150,7 +115,6 @@ impl ServerState for LoginServerState {
|
||||
}
|
||||
|
||||
fn handle(&mut self, pkt: &LoginPacket) -> Box<dyn Iterator<Item = Box<dyn PSOPacket>>> {
|
||||
println!("[login: recv] {:?}", pkt);
|
||||
match pkt {
|
||||
LoginPacket::Login(login) => {
|
||||
self.validate_login(login)
|
||||
@ -160,9 +124,7 @@ impl ServerState for LoginServerState {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
pub fn new_client(socket: mio::tcp::TcpStream, shared_state: SharedLoginState) {
|
||||
pub fn new_client<DA: DataAccess + 'static>(socket: mio::tcp::TcpStream, shared_state: SharedLoginState<DA>) {
|
||||
let state = LoginServerState::new(shared_state);
|
||||
let client = Client::new(socket, Box::new(state));
|
||||
client.io_loop();
|
||||
|
@ -1,9 +1,12 @@
|
||||
#![feature(const_generics)]
|
||||
|
||||
mod login;
|
||||
mod character;
|
||||
mod dataaccess;
|
||||
mod models;
|
||||
|
||||
use std::net::{SocketAddr, Ipv4Addr};
|
||||
use std::net;
|
||||
//use std::net;
|
||||
use std::thread;
|
||||
use std::env;
|
||||
|
||||
@ -12,28 +15,50 @@ use mio::{Events, Poll, Token, Ready, PollOpt};
|
||||
use dotenv::dotenv;
|
||||
|
||||
use diesel::r2d2;
|
||||
use diesel::prelude::*;
|
||||
//use diesel::prelude::*;
|
||||
use diesel::pg::PgConnection;
|
||||
|
||||
use models::{NewUser, UserAccount};
|
||||
//use models::{NewUser, UserAccount, UserSettings, NewUserSettings};
|
||||
use dataaccess::DBAccess;
|
||||
|
||||
fn main() {
|
||||
dotenv().ok();
|
||||
let database_url = env::var("DATABASE_URL").unwrap();
|
||||
|
||||
/*if let Some(arg) = env::args().nth(1) {
|
||||
if arg == "dbstuff" {
|
||||
let conn = PgConnection::establish(&database_url).unwrap();
|
||||
|
||||
use elseware::schema::user_accounts::dsl::*;
|
||||
use elseware::schema::user_settings::dsl::*;
|
||||
|
||||
let u = NewUser::new("hi".to_string(), "qwer".to_string());
|
||||
diesel::insert_into(user_accounts).values(&u).execute(&conn).unwrap();
|
||||
let u = NewUser::new("hi2".to_string(), "qwer".to_string());
|
||||
let user: UserAccount = diesel::insert_into(user_accounts).values(&u).get_result(&conn).unwrap();
|
||||
|
||||
let mut s = models::EUserSettings(libpso::character::settings::UserSettings::default());
|
||||
s.0.blocked_users[5] = 99;
|
||||
s.0.blocked_users[6] = 123;
|
||||
|
||||
diesel::insert_into(user_settings).values(& NewUserSettings {
|
||||
user_id: user.id,
|
||||
settings: s,
|
||||
}).execute(&conn).unwrap();
|
||||
|
||||
let us = user_settings.load::<UserSettings>(&conn).unwrap();
|
||||
for u in us {
|
||||
println!("{:?}", u.settings.0.blocked_users[4]);
|
||||
println!("{:?}", u.settings.0.blocked_users[5]);
|
||||
println!("{:?}", u.settings.0.blocked_users[6]);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
//let database_url = env::var("DATABASE_URL").unwrap();
|
||||
//let conn = PgConnection::establish(&database_url).unwrap();
|
||||
|
||||
//use elseware::schema::user_accounts::dsl::*;
|
||||
//use elseware::schema::user_accounts::table;
|
||||
|
||||
/*let u = NewUser::new("hi".to_string(), "qwer".to_string());
|
||||
diesel::insert_into(user_accounts).values(&u).execute(&conn).unwrap();
|
||||
let u = NewUser::new("hi2".to_string(), "qwer".to_string());
|
||||
diesel::insert_into(user_accounts).values(&u).execute(&conn).unwrap();*/
|
||||
|
||||
println!("[login+character] starting server");
|
||||
|
||||
let database_url = env::var("DATABASE_URL").unwrap();
|
||||
let connection_manager = r2d2::ConnectionManager::<PgConnection>::new(database_url);
|
||||
let connection_pool = r2d2::Pool::builder()
|
||||
.build(connection_manager).unwrap();
|
||||
@ -41,7 +66,7 @@ fn main() {
|
||||
let login_listener = TcpListener::bind(&SocketAddr::from((Ipv4Addr::new(0,0,0,0), login::LOGIN_PORT))).unwrap();
|
||||
let character_listener = TcpListener::bind(&SocketAddr::from((Ipv4Addr::new(0,0,0,0), character::CHARACTER_PORT))).unwrap();
|
||||
|
||||
let login_shared_state = login::SharedLoginState::new(connection_pool);
|
||||
let login_shared_state = login::SharedLoginState::new(DBAccess::new(connection_pool));
|
||||
|
||||
let poll = Poll::new().unwrap();
|
||||
poll.register(&login_listener, Token(0), Ready::readable(), PollOpt::edge()).unwrap();
|
||||
|
@ -1,8 +0,0 @@
|
||||
#![feature(async_await)]
|
||||
|
||||
mod common;
|
||||
//mod patch;
|
||||
|
||||
fn main() {
|
||||
// something or other?
|
||||
}
|
@ -9,6 +9,7 @@ use std::path::{Path, PathBuf, Components};
|
||||
use std::convert::AsRef;
|
||||
use rand::{Rng, RngCore};
|
||||
use crc::{crc32, Hasher32};
|
||||
use mio::tcp::TcpStream;
|
||||
use libpso::{PacketParseError, PSOPacket};
|
||||
use libpso::packet::patch::*;
|
||||
use libpso::crypto::pc::PSOPCCipher;
|
||||
@ -348,7 +349,7 @@ impl Iterator for SendFileIterator {
|
||||
|
||||
fn new_client(socket: net::TcpStream, patch_file_tree: PatchFileTree, patch_file_lookup: HashMap<u32, PatchFile>) {
|
||||
let state = PatchServerState::new(patch_file_tree, patch_file_lookup);
|
||||
let client = Client::new(socket, Box::new(state));
|
||||
let client = Client::new(TcpStream::from_stream(socket).unwrap(), Box::new(state));
|
||||
client.io_loop();
|
||||
}
|
||||
|
||||
@ -357,8 +358,6 @@ fn new_client(socket: net::TcpStream, patch_file_tree: PatchFileTree, patch_file
|
||||
fn main() {
|
||||
println!("[patch] starting server");
|
||||
|
||||
let listener = TcpListener::bind(&SocketAddr::from((Ipv4Addr::new(0,0,0,0), PATCH_PORT))).unwrap();
|
||||
|
||||
let (patch_file_tree, patch_file_lookup) = generate_patch_tree("patchfiles/");
|
||||
println!("[patch] files to patch:");
|
||||
let mut indent = 0;
|
||||
@ -379,6 +378,8 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let listener = TcpListener::bind(&SocketAddr::from((Ipv4Addr::new(0,0,0,0), PATCH_PORT))).unwrap();
|
||||
|
||||
println!("[patch] waiting for connections");
|
||||
while let Ok((socket, addr)) = listener.accept() {
|
||||
let local_patch_file_tree = patch_file_tree.clone();
|
||||
|
Loading…
x
Reference in New Issue
Block a user