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(&reg_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

Reply via email to