Author: baufo
Date: Sun Mar 23 16:56:14 2008
New Revision: 25023
URL: http://svn.gna.org/viewcvs/wesnoth?rev=25023&view=rev
Log:
Porting the user data storage to SQLite
Added:
branches/mp_registration/src/server/sqlite.cpp
branches/mp_registration/src/server/sqlite.hpp
Modified:
branches/mp_registration/src/Makefile.am
branches/mp_registration/src/server/user_handler.cpp
branches/mp_registration/src/server/user_handler.hpp
Modified: branches/mp_registration/src/Makefile.am
URL:
http://svn.gna.org/viewcvs/wesnoth/branches/mp_registration/src/Makefile.am?rev=25023&r1=25022&r2=25023&view=diff
==============================================================================
--- branches/mp_registration/src/Makefile.am (original)
+++ branches/mp_registration/src/Makefile.am Sun Mar 23 16:56:14 2008
@@ -156,6 +156,7 @@
server/proxy.cpp \
server/server.cpp \
server/simple_wml.cpp \
+ server/sqlite.cpp \
server/user_handler.cpp \
network.cpp \
network_worker.cpp \
@@ -247,6 +248,7 @@
server/input_stream.hpp \
server/proxy.hpp \
server/metrics.hpp \
+ server/sqlite.hpp \
server/user_handler.hpp \
editor/editor_undo.hpp \
editor/map_manip.hpp \
Added: branches/mp_registration/src/server/sqlite.cpp
URL:
http://svn.gna.org/viewcvs/wesnoth/branches/mp_registration/src/server/sqlite.cpp?rev=25023&view=auto
==============================================================================
--- branches/mp_registration/src/server/sqlite.cpp (added)
+++ branches/mp_registration/src/server/sqlite.cpp Sun Mar 23 16:56:14 2008
@@ -1,0 +1,46 @@
+#include "sqlite.hpp"
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <cstdlib>
+#include <iostream>
+
+sqlite_database::sqlite_database(const std::string& filename) {
+ int result_code = sqlite3_open(filename.c_str(), &database_);
+ if(result_code != SQLITE_OK){
+ //! @todo Do any actual error handling
+ std::cerr << "Error opening database " << filename << std::endl;
+ sqlite3_close(database_);
+ }
+ std::cout << "Opened database " << filename << std::endl;
+}
+
+sqlite_database::~sqlite_database() {
+ sqlite3_close(database_);
+}
+
+int sqlite_database::exec(const std::string& query, std::vector<std::string>*
data) {
+ int result_code;
+
+ char** result;
+ int num_rows, num_cols;
+ char* errmsg;
+
+ result_code = sqlite3_get_table(database_, query.c_str(), &result,
&num_rows, &num_cols, &errmsg);
+
+ if(result_code == SQLITE_OK) {
+ if(data) {
+ for(int i=0; i < num_cols * num_rows; ++i) {
+ //The first row would be the titles of the columnes which we
ignore
+ data->push_back(result[num_cols+i]);
+ }
+ }
+ } else {
+ std::cerr << errmsg << std::endl;
+ }
+
+ sqlite3_free_table(result);
+
+ return result_code;
+}
Added: branches/mp_registration/src/server/sqlite.hpp
URL:
http://svn.gna.org/viewcvs/wesnoth/branches/mp_registration/src/server/sqlite.hpp?rev=25023&view=auto
==============================================================================
--- branches/mp_registration/src/server/sqlite.hpp (added)
+++ branches/mp_registration/src/server/sqlite.hpp Sun Mar 23 16:56:14 2008
@@ -1,0 +1,20 @@
+#ifndef SQLITE_HPP_INCLUDED
+#define SQLITE_HPP_INCLUDED
+
+#include "../global.hpp"
+
+#include <sqlite3.h>
+
+#include <vector>
+#include <string>
+
+class sqlite_database {
+ public:
+ sqlite_database(const std::string& filename);
+ ~sqlite_database();
+ int exec(const std::string& query, std::vector<std::string>* data
=NULL);
+ private:
+ sqlite3* database_;
+};
+
+#endif
Modified: branches/mp_registration/src/server/user_handler.cpp
URL:
http://svn.gna.org/viewcvs/wesnoth/branches/mp_registration/src/server/user_handler.cpp?rev=25023&r1=25022&r2=25023&view=diff
==============================================================================
--- branches/mp_registration/src/server/user_handler.cpp (original)
+++ branches/mp_registration/src/server/user_handler.cpp Sun Mar 23 16:56:14
2008
@@ -12,13 +12,16 @@
#include <iostream>
#include <sstream>
#include <vector>
+#include <string>
user_handler::user_handler(const std::string& users_file) :
users_file_(users_file),
- cfg_(read_config())
+ cfg_(read_config()),
+ user_data_(users_file_ + ".db")
{
load_config();
+ load_users();
clean_up();
}
@@ -69,7 +72,7 @@
#ifndef NO_MAIL
if(mail()) {
- config& mail = *(cfg_.child("mail"));
+ config& mail = *(cfg_.child("email"));
mail["from_address"] = mail["from_address"].empty() ? "[EMAIL
PROTECTED]" : mail["from_address"];
mail["mail_server"] = mail["mail_server"].empty() ? "127.0.0.1" :
mail["mail_server"];
@@ -93,16 +96,38 @@
}
#endif //NO_MAIL
-
- //Check if we already have users and
- //if we don't create a child for them
- if(cfg_.child("users")) {
- users_ = cfg_.child("users");
- } else {
- users_ = &(cfg_.add_child("users"));
- }
-
- std::cout << cfg_ << std::endl;
+}
+
+void user_handler::load_users() {
+ //Create the table with the user details
+ //If it already exists this will just fail
+ user_data_.exec("create table users ("
+ "name text primary key,"
+ "password text,"
+ "email text,"
+ "realname text,"
+ "registration_date text,"
+ "last_login text"
+ ")");
+
+ std::vector<std::string> data;
+ user_data_.exec("select * from users", &data);
+
+ assert(data.size() % (uh::MAX_VALUE + 1) == 0);
+
+ int i = 0;
+ while(i < data.size()) {
+ std::string* u = new std::string[uh::MAX_VALUE];
+ users_.insert(std::pair<std::string,std::string*>(data[i++], u));
+
+ u[uh::PASSWORD] = data[i+uh::PASSWORD];
+ u[uh::EMAIL] = data[i+uh::EMAIL];
+ u[uh::REALNAME] = data[i+uh::REALNAME];
+ u[uh::REGISTRATION_DATE] = data[i+uh::REGISTRATION_DATE];
+ u[uh::LAST_LOGIN] = data[i+uh::LAST_LOGIN];
+
+ i += uh::MAX_VALUE;
+ }
}
void user_handler::save_config() {
@@ -124,7 +149,7 @@
return false;
}
- config& mail = *(cfg_.child("mail"));
+ config& mail = *(cfg_.child("email"));
jwsmtp::mailer m(to_address, mail["from_address"].c_str(), subject,
message,
mail["mail_server"].c_str(), mail_port_, false);
@@ -132,10 +157,6 @@
m.username(mail["mail_user"]);
m.password( mail["mail_password"]);
}
- //! @todo Sending the mail in a new thread
- //! (as suggested on http://johnwiggins.net/jwsmtp/)
- //! might be a very good idea.
- //! To bad I am not familiar with boost::thread
m.send();
@@ -172,17 +193,13 @@
//Thus a day has 60 * 60 * 24 = 86400 seconds
time_t limit = username_expiration_limit_ * 86400;
- const config::child_map& user_childs = users_->all_children();
- for(config::child_map::const_iterator i = user_childs.begin(); i !=
user_childs.end(); ++i) {
- const config& user = *(users_->child(i->first));
- time_t last_login = lexical_cast_default<time_t>(user["last_login"]);
+ for(std::map<std::string,std::string*>::const_iterator i = users_.begin();
i != users_.end(); ++i) {
+ time_t last_login =
lexical_cast_default<time_t>(i->second[uh::LAST_LOGIN]);
if((now - last_login) > limit) {
std::cout << "User '" << i->first << "' exceeds expiration date: ";
remove_user(i->first);
}
}
-
- save_config();
}
void user_handler::add_user(const std::string& name,
@@ -202,30 +219,35 @@
//Check if the given email is not yet registered
if(!mail.empty()) {
- const config::child_map& user_childs = users_->all_children();
- for(config::child_map::const_iterator i = user_childs.begin(); i !=
user_childs.end(); ++i) {
- if((*(users_->child(i->first)))["mail"] == mail) {
+ for(std::map<std::string,std::string*>::const_iterator i =
users_.begin(); i != users_.end(); ++i) {
+ if(i->second[uh::EMAIL] == mail) {
throw error("Could not add new user. The email address '" +
mail + "' is already in use.");
}
}
}
- config& user = users_->add_child(name);
- user["mail"] = mail;
- user["password"] = password;
+ users_.insert(std::pair<std::string,std::string*>(name,NULL));
+ users_[name] = new std::string[uh::MAX_VALUE];
+
+ for(std::map<std::string,std::string*>::iterator a = users_.begin(); a!=
users_.end(); ++a) {
+ std::cout << a->first << std::endl;
+ std::cout << a->second << std::endl;
+ }
std::string now = lexical_cast_default<std::string>(time(NULL));
- user["registration_date"] = now;
- user["last_login"] = now;
-
- //! @todo To save performance it we should of course not save
- //! the whole config everytime something changes
- save_config();
-
- std::cout << "Created new user '" << name << "'\n";
+
+ users_[name][uh::PASSWORD] = password;
+ users_[name][uh::EMAIL] = mail;
+ users_[name][uh::REGISTRATION_DATE] = now;
+ users_[name][uh::LAST_LOGIN] = now;
+
+ user_data_.exec("insert into users
(name,password,email,realname,registration_date,last_login) values ('" +
+ name + "','" + password + "','" + mail + "','','" + now + "','" +
now + "')");
//I don't think we need to send the user details via email,
//we don't require any account activation anyways.
+
+ std::cout << "Created new user '" << name << "'\n";
}
@@ -237,19 +259,19 @@
throw error("Could not send password reminder. No user with the name
'" + name + "' exists.");
}
- config& user = *(users_->child(name));
-
- if(user["mail"].empty()) {
+ std::string* u = users_[name];
+
+ if(u[uh::EMAIL].empty()) {
throw error("Could not send password reminder. The email address of
the user '" + name + "' is empty.");
}
std::stringstream msg;
msg << "Hello " << name << ",\n\n" <<
- "Your password is '" << user["password"] << "'.\n\n" <<
+ "Your password is '" << u[uh::PASSWORD] << "'.\n\n" <<
"Have fun playing at Wesnoth!";
//If sending does not return true warn that no message was sent.
- if(!(send_mail(user["mail"].c_str(), "Wesnoth Multiplayer Server Password
Reminder", msg.str().c_str()))) {
+ if(!(send_mail(u[uh::EMAIL].c_str(), "Wesnoth Multiplayer Server Password
Reminder", msg.str().c_str()))) {
throw error("Could not send password reminder. There was an error
sending the reminder email.");
}
return;
@@ -261,17 +283,7 @@
}
void user_handler::user_logged_in(const std::string& name) {
- if(!user_exists(name)) {
- //No exception here because this function is called by the server, not
by users
- return;
- }
-
- config& user = *(users_->child(name));
- user["last_login"] = lexical_cast_default<std::string>(time(NULL));
-
- //! @todo To save performance it we should of course not save
- //! the whole config everytime something changes
- save_config();
+ set_user_attribute(name, "last_login",
lexical_cast_default<std::string>(time(NULL)));
//Should we keep track of the IPs used for logging into this account?
}
@@ -282,11 +294,9 @@
throw error("Could not remove user. No user with the name '" + name +
"' exists.");
}
- users_->remove_child(name, 0);
-
- //! @todo To save performance it we should of course not save
- //! the whole config everytime something changes
- save_config();
+ users_.erase(users_.find(name));
+
+ user_data_.exec("delete from users where name='" + name + "'");
std::cout << "Removed user '" << name << "'\n";
}
@@ -297,8 +307,8 @@
return false;
}
- config& user = *(users_->child(name));
- return (user["password"] == password);
+ std::string* u = users_[name];
+ return (u[uh::PASSWORD] == password);
}
void user_handler::set_user_attribute(const std::string& name,
@@ -310,16 +320,25 @@
"'. No user with the name with this name exists.");
}
- config& user = *(users_->child(name));
- user[attribute] = value;
-
- //! @todo To save performance it we should of course not save
- //! the whole config everytime something changes
- save_config();
+ std::string* u = users_[name];
+
+ if(attribute == "password") {
+ u[uh::PASSWORD] = value;
+ } else if(attribute == "email") {
+ u[uh::EMAIL] = value;
+ } else if(attribute == "realname") {
+ u[uh::REALNAME] = value;
+ } else if(attribute == "last_login") {
+ u[uh::LAST_LOGIN] = value;
+ } else {
+ std::cerr << "Call of set_user_attribute() with unknown attribute '"
<< attribute << "'.\n";
+ }
+
+ user_data_.exec("update users set " + attribute + "='" + value + "' where
name='" + name + "'");
}
bool user_handler::user_exists(const std::string& name) {
- return ((users_->child(name)));
+ return (users_[name]);
}
bool user_handler::mail() {
@@ -330,12 +349,12 @@
return false;
#endif
- return (cfg_.child("mail"));
+ return (cfg_.child("email"));
}
void user_handler::set_mail(const std::string& user, const std::string& mail) {
check_mail(mail);
- set_user_attribute(user, "mail", mail);
+ set_user_attribute(user, "email", mail);
}
void user_handler::set_password(const std::string& user, const std::string&
password) {
@@ -344,6 +363,7 @@
}
void user_handler::set_realname(const std::string& user, const std::string&
realname) {
+ //Should we perform any check (e.g. max size)?
set_user_attribute(user, "realname", realname);
}
@@ -367,21 +387,21 @@
throw error("No user with the name '" + name + "' exists.");
}
- config& user = *(users_->child(name));
+ std::string* u = users_[name];
char registration_date[99];
char last_login[99];
- const time_t& reg_t =
lexical_cast_default<time_t>(user["registration_date"]);
- const time_t& last_t = lexical_cast_default<time_t>(user["last_login"]);
+ const time_t& reg_t =
lexical_cast_default<time_t>(u[uh::REGISTRATION_DATE]);
+ const time_t& last_t = lexical_cast_default<time_t>(u[uh::LAST_LOGIN]);
strftime(registration_date, 99, "%c", localtime(®_t));
strftime(last_login, 99, "%c", localtime(&last_t));
std::stringstream res;
res << "Username: " << name << "\n"
- << (user["realname"].empty() ? "" : "Real name: " +
user["realname"] + "\n")
- << (user["mail"].empty() ? "" : "Email: " + user["mail"] + "\n")
+ << (u[uh::REALNAME].empty() ? "" : "Real name: " + u[uh::REALNAME]
+ "\n")
+ << (u[uh::EMAIL].empty() ? "" : "Email: " + u[uh::EMAIL] + "\n")
<< "Registration date: " << registration_date << "\n"
<< "Last login: " << last_login;
Modified: branches/mp_registration/src/server/user_handler.hpp
URL:
http://svn.gna.org/viewcvs/wesnoth/branches/mp_registration/src/server/user_handler.hpp?rev=25023&r1=25022&r2=25023&view=diff
==============================================================================
--- branches/mp_registration/src/server/user_handler.hpp (original)
+++ branches/mp_registration/src/server/user_handler.hpp Sun Mar 23 16:56:14
2008
@@ -9,6 +9,26 @@
#include <jwsmtp/jwsmtp.h>
#endif
+#include "sqlite.hpp"
+
+
+#include <vector>
+#include <string>
+#include <map>
+
+namespace uh {
+
+ enum {
+ PASSWORD = 0,
+ EMAIL,
+ REALNAME,
+ REGISTRATION_DATE,
+ LAST_LOGIN,
+ MAX_VALUE
+ };
+
+}
+
class user_handler {
public:
user_handler(const std::string& users_file);
@@ -16,6 +36,7 @@
config read_config() const;
void load_config();
+ void load_users();
void save_config();
void clean_up();
@@ -74,7 +95,10 @@
unsigned short username_expiration_limit_;
config cfg_;
- config* users_;
+
+ sqlite_database user_data_;
+
+ std::map<std::string,std::string*> users_;
};
#endif
_______________________________________________
Wesnoth-commits mailing list
[email protected]
https://mail.gna.org/listinfo/wesnoth-commits