Logo Search packages:      
Sourcecode: papaya version File versions  Download package

PostgresQuery.cpp

#include <stdint.h>
#include <unistd.h>
#include "libpq++.h"

#include "mudclient.h"
#include "PluginHandler.h"
#include "TriggerHandler.h"
#include "TurfProtocol.h"
#include "version.h"
#include "Message.h"
#include "PostgresQuery.h"

extern PluginHandler * phandler;
extern TriggerHandler * thandler;

static PostgresQuery * postgres = NULL;
static List * plist = NULL;

#define MAJOR "0"
#define MINOR "2"

extern "C" char * plugin_query_name() {
  return "PostgresQuery";
}

extern "C" char * plugin_query_description() {
  return "Stores lots of stats about characters in postgres.";
}

extern "C" char * plugin_query_major() {
  return MAJOR;
}

extern "C" char * plugin_query_minor() {
  return MINOR;
}


extern "C" void plugin_init() {
  postgres = new PostgresQuery();
}

extern "C" void plugin_cleanup() {
  if (postgres)
    delete postgres;
}

PostgresQuery::PostgresQuery() {
  connection = NULL;
  username = strdup("none");
  plist = new List();

  init_regex();
  init_triggers();

  version = 0.1;
  name = strdup("Postgres database module.");
  phandler->registerPlugin(this, VERSION);
}

PostgresQuery::~PostgresQuery() {
  if (connection)
    delete connection;

  if (username)
    free(username);

  if (plist)
    delete plist;

  free(name);
  name = NULL;

  cleanup_regex();
  cleanup_triggers();

  phandler->unregisterPlugin(this);
}

/**
 * Sends a query to the postgres server.
 *
 * Return 0 on failure, 1 on success.
 */

int PostgresQuery::sendQuery(char * query) {

  int res;

  if (!checkConnection())
    return 0;

  res = connection->Exec(query);
  switch (res) {
  case PGRES_EMPTY_QUERY:
  case PGRES_BAD_RESPONSE:
  case PGRES_NONFATAL_ERROR:
  case PGRES_FATAL_ERROR:
  case PGRES_COPY_OUT:
  case PGRES_COPY_IN:
    return 0;

  case PGRES_TUPLES_OK:
  case PGRES_COMMAND_OK:
    return 1;
  }

  return 0;
}

int PostgresQuery::checkConnection() {

  if (!connection)
    if (!connect())
      return 0;

  if (connection->Status() == CONNECTION_BAD)
    if (!connect())
      return 0;

  return 1;
}

int PostgresQuery::connect() {

  if (connection)
    delete connection;

  connection = new PgDatabase(DB_NAME);
  if (connection->Status() == CONNECTION_BAD) {
    delete connection;
    connection = NULL;
    return 0;
  }

  return 1;
}

void postgresquery_callback(Connection * c, char * buf, void * data) {
  postgres->callback(c, buf, data);
}

void postgresquery_groupcallback(Connection * c, char * buf, void * data) {
  postgres->groupCallback(c, buf, data);
}

/**
 * Called with the name of the Turf character.
 */

void postgres_name_callback(Connection * c, char * buf, void * data) {

  char * name;

  if (!buf)
    return;

  if (strlen(buf) < 4)
    return;

  ListElement * ele = plist->findEntry(c);
  if (!ele)
    ele = plist->newEntry(c, NULL);

  name = (char *)ele->getData();
  if (name)
    free(name);

  name = strdup(buf+1);
  ele->setData(name);  


  printf("Set name to %s.\n", name);
}

int postgresquery_stat_gain(regex_t * regexp, char * buf, void * data, Connection * c, Trigger *) {
  regmatch_t match[10];
  char query[1024];

  time_t t;
  time(&t);

  printf("In stat gain.\n");

  if (regexec(regexp, buf, 10, match, 0) == REG_NOMATCH)
    return 0;
  
  int hp_gain;
  int mana_gain;
  int mv_gain;
  int prac_gain;

  postgres->getInt(buf, match, &hp_gain, 1);
  postgres->getInt(buf, match, &mana_gain, 3);
  postgres->getInt(buf, match, &mv_gain, 5);
  postgres->getInt(buf, match, &prac_gain, 7);

  sprintf(query, "insert into gain values ('%s', abstime(%ld), %d, %d, %d, %d);",
        postgres->getUsername(c), t, hp_gain, mana_gain, mv_gain, prac_gain);



  if (!postgres->sendQuery(query)) {
    printf("PostgresQuery: could not execute query %s.\n", query);
    return 0;
  }
 // h/h, m/m, v/v

  return 0;

}

int postgresquery_stat_gain_no_prac(regex_t * regexp, char * buf, void * data, Connection * c, Trigger *) {
  regmatch_t match[10];
  char query[1024];

  time_t t;
  time(&t);

  printf("In stat gain no prac.\n");

  if (regexec(regexp, buf, 10, match, 0) == REG_NOMATCH) {
    printf("no match.\n");
    return 0;
  }  

  int hp_gain;
  int mana_gain;
  int mv_gain;

  printf("buf: %s\n", buf);

  postgres->getInt(buf, match, &hp_gain, 1);
  postgres->getInt(buf, match, &mana_gain, 3);
  postgres->getInt(buf, match, &mv_gain, 5);

  sprintf(query, "insert into gain values ('%s', abstime(%ld), %d, %d, %d, %d);",
        postgres->getUsername(c), t, hp_gain, mana_gain, mv_gain, 0);

  if (!postgres->sendQuery(query)) {
    printf("PostgresQuery: could not execute query %s.\n", query);
    return 0;
  }
 // h/h, m/m, v/v

  return 0;

}

int postgresquery_stat_loss(regex_t * regexp, char * buf, void * data, Connection * c, Trigger *) {
  regmatch_t match[10];
  char query[1024];
  time_t t;
  time(&t);

  printf("In stat loss no prac.\n");

  if (regexec(regexp, buf, 7, match, 0) == REG_NOMATCH)
    return 0;

  int hp_loss;
  int mana_loss;
  int mv_loss;

  postgres->getInt(buf, match, &hp_loss, 1);
  postgres->getInt(buf, match, &mana_loss, 3);
  postgres->getInt(buf, match, &mv_loss, 5);

  hp_loss *= -1;
  mana_loss *= -1;
  mv_loss *= -1;

  sprintf(query, "insert into gain values ('%s', abstime(%ld), %d, %d, %d, %d);",
        postgres->getUsername(c), t, hp_loss, mana_loss, mv_loss, 0);

  if (!postgres->sendQuery(query)) {
    printf("PostgresQuery: could not execute query %s.\n", query);
    return 0;
  }

  return 0;

}

int postgresquery_stat_loss_prac(regex_t * regexp, char * buf, void * data, Connection *, Trigger *) {
  time_t t;
  time(&t);
  return 0;

}

int postgresquery_check_score(regex_t * regexp, char * buf, void * data, Connection * c, Trigger *) {
  // Try and find the TurfProtocol object.
  void * handle = phandler->findPlugin("TurfProtocol");
  if (!handle) {
    new Message("PostgresQuery: Error", "TurfProtocol is not loaded.  This plugin does not work without it.", NULL);
    return;
  }
  
  if (!findTurf(handle, (void **)&tp)) {
    new Message("PostgresQuery: Error", "TurfProtocol is not loaded.  This plugin does not work without it.", NULL);
    return;    printf("papaya.turf_protocol_add: TurfProtocol not loaded.\n");
  }
  
  if (!tp) {
    new Message("PostgresQuery: Error", "TurfProtocol is not loaded.  This plugin does not work without it.", NULL);
    return;    printf("papaya.turf_protocol_add: TurfProtocol not loaded.\n");
  }
  

  time_t * t = (time_t *)malloc(sizeof(time_t));;
  
  time(t);

  TurfProtocol * tp = NULL;
  
  tp->addCommand(c, "score", postgresquery_callback, (void *)t);
  return 0;
}

/**
 * Requests the name of the character from Turf.
 */

int postgres_connected(regex_t * regexp, char * buf, void * data, Connection * c, Trigger *) {
  printf("Requsting name.\n");
  //  turf->addCommand(c, "c15 d", postgres_name_callback, NULL);

  time_t * t = (time_t *)malloc(sizeof(time_t));
  time(t);
  turf->addCommand(c, "score", postgresquery_callback, (void *)t);
  return 0;
}

void PostgresQuery::groupCallback(Connection * c, char * buf, void * data) {

  regmatch_t match[3];
  char query[1024];

  time_t * ti = (time_t *)data;
  time_t t = *ti;

  if (!buf)
    return;

  if (regexec(&class_regex, buf, 3, match, 0) != REG_NOMATCH) {
    char cla[1024];
    char name[1024];

    int length = match[1].rm_eo - match[1].rm_so;
    memcpy(cla, buf + match[1].rm_so, length);
    cla[length] = '\0';

    length = match[2].rm_eo - match[2].rm_so;
    memcpy(name, buf + match[2].rm_so, length);
    name[length] = '\0';

    if (!strcmp(name, getUsername(c))) {
      sprintf(query, "insert into %s values ('%s', abstime(%ld), '%s');",
            CLASS_TABLE, getUsername(c), t, cla);
      sendQuery(query);
    }
  }
}

void PostgresQuery::callback(Connection * c, char * buf, void * data) {

  regmatch_t match[6];

  time_t * ti = (time_t *)data;
  time_t t = *ti;

  if (!buf) {
    time_t * t2 = (time_t *)malloc(sizeof(time_t));;
    *t2 = *ti;

    turf->addCommand(c, "group", postgresquery_groupcallback, (void *)t2);
    return;
  }

  if (regexec(&name_regex, buf, 2, match, 0) != REG_NOMATCH) {
    name_match(buf, match);
    return;
  }

  if (regexec(&str_regex, buf, 4, match, 0) != REG_NOMATCH) {
    /* Match */
    stat_match(buf, "str", match, t, c);
    return;
  }

  if (regexec(&int_regex, buf, 5, match, 0) != REG_NOMATCH) {
    /* Match */
    stat_match(buf, "int", match, t, c);
    hp_match(buf, match, t, c);
    return;
  }

  if (regexec(&wis_regex, buf, 5, match, 0) != REG_NOMATCH) {
    /* Match */
    stat_match(buf, "wis", match, t, c);
    mana_match(buf, match, t, c);
    return;
  }

  if (regexec(&dex_regex, buf, 5, match, 0) != REG_NOMATCH) {
    /* Match */
    stat_match(buf, "dex", match, t, c);
    moves_match(buf, match, t, c);
    return;
  }

  if (regexec(&con_regex, buf, 3, match, 0) != REG_NOMATCH) {
    /* Match */
    stat_match(buf, "con", match, t, c);
    return;
  }

  if (regexec(&weight_regex, buf, 3, match, 0) != REG_NOMATCH) {
    /* Match */
    weight_match(buf, match, t, c);
  }

  if (regexec(&exp_regex, buf, 3, match, 0) != REG_NOMATCH) {
    /* Match */
    exp_match(buf, match, t, c);
  }

  if (regexec(&gold_regex, buf, 2, match, 0) != REG_NOMATCH) {
    /* Match */
    gold_match(buf, match, t, c);
  }

  if (regexec(&waypoint_regex, buf, 3, match, 0) != REG_NOMATCH) {
    /* Match */
    waypoint_match(buf, match, t, c);
  }

}

char * PostgresQuery::getUsername(Connection * c) {

  ListElement * ele = plist->findEntry(c);
  if (!ele)
    return username;

  if (!ele->getData())
    return username;

  return (char *)ele->getData();
}

void PostgresQuery::weight_match(char * input, regmatch_t * match, unsigned long t, Connection * c) {
  int current = 0;
  int max = 0;
  char query[1024];

  getInts(input, match, &current, &max);

  sprintf(query, "insert into %s values ('%s', asbtime(%ld), %d, %d);",
        WEIGHT_TABLE, getUsername(c), t, current, max);

  if (!sendQuery(query)) {
    printf("PostgresQuery: could not execute query %s.\n", query);
    return;
  }
}

void PostgresQuery::exp_match(char * input, regmatch_t * match, unsigned long t, Connection * c) {
  int exp = 0;
  int pracs = 0;
  char query[1024];

  getInts(input, match, &exp, &pracs);

  sprintf(query, "insert into %s values ('%s', abstime(%ld), %d);",
        EXP_TABLE, getUsername(c), t, exp);

  if (!sendQuery(query)) {
    printf("PostgresQuery: could not execute query %s.\n", query);
    return;
  }

  sprintf(query, "insert into %s values ('%s', abstime(%ld), %d);",
        PRAC_TABLE, getUsername(c), t, pracs);

  if (!sendQuery(query)) {
    printf("PostgresQuery: could not execute query %s.\n", query);
    return;
  }

}

void PostgresQuery::gold_match(char * input, regmatch_t * match, unsigned long t, Connection * c) {
  int gold = 0;
  char query[1024];

  getInts(input, match, &gold, NULL);

  sprintf(query, "insert into %s values ('%s', abstime(%ld), %d);",
        GOLD_TABLE, getUsername(c), t, gold);

  if (!sendQuery(query)) {
    printf("PostgresQuery: could not execute query %s.\n", query);
    return;
  }
}

void PostgresQuery::waypoint_match(char * input, regmatch_t * match, unsigned long t, Connection * c) {

  int number = 0;
  int score = 0;
  char query[1024];

  getInts(input, match, &number, &score);

  sprintf(query, "insert into %s values ('%s', abstime(%ld), %d, %d);",
        WAYPOINT_TABLE, getUsername(c), t, number, score);

  if (!sendQuery(query)) {
    printf("PostgresQuery: could not execute query %s.\n", query);
    return;
  }
}

void PostgresQuery::hp_match(char * input, regmatch_t * match, unsigned long t, Connection * c) {

  int current, max;
  char query[1024];

  getInts2(input, match, &current, &max);

  sprintf(query, "insert into %s values ('%s', abstime(%ld), %d, %d);",
        HP_TABLE, getUsername(c), t, current, max);

  if (!sendQuery(query)) {
    printf("PostgresQuery: could not execute query %s.\n", query);
    return;
  }
}

void PostgresQuery::mana_match(char * input, regmatch_t * match, unsigned long t, Connection * c) {

  int current, max;
  char query[1024];

  getInts2(input, match, &current, &max);

  sprintf(query, "insert into %s values ('%s', abstime(%ld), %d, %d);",
        MANA_TABLE, getUsername(c), t, current, max);

  if (!sendQuery(query)) {
    printf("PostgresQuery: could not execute query %s.\n", query);
    return;
  }
}

void PostgresQuery::moves_match(char * input, regmatch_t * match, unsigned long t, Connection * c) {

  int current, max;
  char query[1024];

  getInts2(input, match, &current, &max);

  sprintf(query, "insert into %s values ('%s', abstime(%ld), %d, %d);",
        MOVES_TABLE, getUsername(c), t, current, max);

  if (!sendQuery(query)) {
    printf("PostgresQuery: could not execute query %s.\n", query);
    return;
  }
}

void PostgresQuery::stat_match(char * input, char * stat, regmatch_t * match, unsigned long t, Connection * c) {

  int enhanced;
  int natural;
  char query[1024];

  getInts(input, match, &enhanced, &natural);

  sprintf(query, "insert into %s values ('%s', abstime(%ld), %d, %d, '%s');",
        STAT_TABLE, getUsername(c), t, enhanced, natural, stat);

  if (!sendQuery(query)) {
    printf("PostgresQuery: could not execute query %s.\n", query);
    return;
  }

  if (!strcmp(stat, "str")) {
    int length;
    char buf[1024];

    length = match[3].rm_eo - match[3].rm_so;
    memcpy(buf, input + match[3].rm_so, length);
    buf[length] = 0;

    sprintf(query, "insert into %s values ('%s', abstime(%ld), '%s');",
          RACE_TABLE, getUsername(c), t, buf);
    
    if (!sendQuery(query)) {
    printf("PostgresQuery: could not execute query %s.\n", query);
    return;
    }
  }

}

void PostgresQuery::name_match(char * buf, regmatch_t * match) {
  int length;
  char out[1024];

  length = match[1].rm_eo - match[1].rm_so;
  memcpy(out, buf + match[1].rm_so, length);
  out[length] = '\0';

  if (username)
    free(username);
  username = strdup(out);
}

void PostgresQuery::getInt(char * input, regmatch_t * match, int * dest, int index) {
  int length;
  char buf[1024];

  if (!dest)
    return;

  length = match[index].rm_eo - match[index].rm_so;
  memcpy(buf, input + match[index].rm_so, length);
  buf[length] = 0;

  *dest = atoi(buf);
}

void PostgresQuery::getInts2(char * input, regmatch_t * match, int * first, int * second) {
  int length;
  char buf[1024];

  if (first) {
    length = match[3].rm_eo - match[3].rm_so;
    memcpy(buf, input + match[3].rm_so, length);
    buf[length] = '\0';
    
    *first = atoi(buf);
  }

  if (second) {
    length = match[4].rm_eo - match[4].rm_so;
    memcpy(buf, input + match[4].rm_so, length);
    buf[length] = '\0';
    
    *second = atoi(buf);
  }
}

void PostgresQuery::getInts(char * input, regmatch_t * match, int * first, int * second) {
  int length;
  char buf[1024];

  if (first) {
    length = match[1].rm_eo - match[1].rm_so;
    memcpy(buf, input + match[1].rm_so, length);
    buf[length] = '\0';
    
    *first = atoi(buf);
  }

  if (second) {
    length = match[2].rm_eo - match[2].rm_so;
    memcpy(buf, input + match[2].rm_so, length);
    buf[length] = '\0';
    
    *second = atoi(buf);
  }
}

void PostgresQuery::cleanup_regex() {
  regfree(&str_regex);
  regfree(&int_regex);
  regfree(&wis_regex);
  regfree(&dex_regex);
  regfree(&con_regex);
  regfree(&name_regex);
  regfree(&weight_regex);
  regfree(&exp_regex);
  regfree(&gold_regex);
  regfree(&waypoint_regex);
  regfree(&class_regex);
}

void PostgresQuery::init_triggers() {

  exp_gain = new Trigger("You receive .* experience points.", postgresquery_check_score, NULL, false, NULL);
  waypoint_gain = new Trigger("You found a waypoint! You gain .* experience points!", postgresquery_check_score, NULL, false, NULL);
  quest_gain = new Trigger("Congratulations you completed the quest.", postgresquery_check_score, NULL, false, NULL);

  flee_loss = new Trigger("You flee from combat!", postgresquery_check_score, NULL, false, NULL);
  flee_fail_loss = new Trigger("You failed to flee!", postgresquery_check_score, NULL, false, NULL);
  recall_loss = new Trigger("You recall from combat!  You lose .* exps.", postgresquery_check_score, NULL, false, NULL);
  recall_fail_loss = new Trigger("You failed!  You lose .* exps.", postgresquery_check_score, NULL, false, NULL);
  death_loss = new Trigger("You have been KILLED!!", postgresquery_check_score, NULL, false, NULL);

  //You raise a level!!  Your gain is: 12/112 hp, 6/154 m, 6/160 mv 4/4 prac.

  stat_gain = new Trigger(".*Your gain is: .*([0-9]+).*/.*([0-9]+).* hp, .*([0-9]+).*/.*([0-9]+).* m, .*([0-9]+).*/.*([0-9]+).* mv .*([0-9]+).*/.*([0-9]+).* prac.", postgresquery_stat_gain, NULL, false, NULL);
  stat_loss = new Trigger("You lose: .*([0-9]+).*/.*([0-9]+).* hp, .*([0-9]+).*/.*([0-9]+).* m, .*([0-9]+).*/.*([0-9]+).* mv.", postgresquery_stat_loss, NULL, false, NULL);

  stat_gain_no_prac = new Trigger("You gain: .*([0-9]+).*/.*([0-9]+).* hp, .*([0-9]+).*/.*([0-9]+).* m, .*([0-9]+).*/.*([0-9]+).* mv.", postgresquery_stat_gain_no_prac, NULL, false, NULL);

  // What does this look like?
  //  energy_drain_loss 

  reconnected = new Trigger(".*You have reconnected.", postgres_connected, NULL, false, NULL);
  connected = new Trigger("Welcome to Turf.  Have a pleasant stay.", postgres_connected, NULL, false, NULL);


  thandler->addTrigger(exp_gain);
  thandler->addTrigger(waypoint_gain);
  thandler->addTrigger(quest_gain);

  thandler->addTrigger(flee_loss);
  thandler->addTrigger(flee_fail_loss);
  thandler->addTrigger(recall_loss);
  thandler->addTrigger(recall_fail_loss);
  //  thandler->addTrigger(energy_drain_loss);
  thandler->addTrigger(death_loss);

  thandler->addTrigger(stat_gain);
  thandler->addTrigger(stat_loss);
  thandler->addTrigger(stat_gain_no_prac);

  thandler->addTrigger(reconnected);
  thandler->addTrigger(connected);

}

void PostgresQuery::cleanup_triggers() {
  delete exp_gain;
  delete waypoint_gain;
  delete quest_gain;

  delete flee_loss;
  delete flee_fail_loss;
  delete recall_loss;
  delete recall_fail_loss;
  //  delete energy_drain_loss;
  delete death_loss;

  delete stat_gain;
  delete stat_loss;
  delete stat_gain_no_prac;

  delete reconnected;
  delete connected;
}

void PostgresQuery::init_regex() {

  regcomp(&str_regex, "^Str:[ ]+([0-9]+) \\(([0-9]+)\\).*You are a [0-9]+ year old ([^ ]+).*", REG_ICASE|REG_EXTENDED);
  regcomp(&int_regex, "^Int:[ ]+([0-9]+) \\(([0-9]+)\\).*You have [^p]+p([0-9]+)/([0-9]+).* hits.", REG_ICASE|REG_EXTENDED);
  regcomp(&wis_regex, "^Wis:[ ]+([0-9]+) \\(([0-9]+)\\).*You have [^p]+p([0-9]+)/([0-9]+).* mana.", REG_ICASE|REG_EXTENDED);
  regcomp(&dex_regex, "^Dex:[ ]+([0-9]+) \\(([0-9]+)\\).*You have [^p]+p([0-9]+)/([0-9]+).* moves.", REG_ICASE|REG_EXTENDED);
  regcomp(&con_regex, "^Con:[ ]+([0-9]+) \\(([0-9]+)\\).*", REG_ICASE|REG_EXTENDED);

  regcomp(&name_regex, "You are ([a-zA-Z]+).*, level .*", REG_ICASE|REG_EXTENDED);

  regcomp(&weight_regex, "^You are carrying .*([0-9]+).*/.*([0-9]+).* kg.", REG_ICASE|REG_EXTENDED);
  regcomp(&exp_regex, "^Exp:[ ]+([0-9]+)[ ]+You have ([0-9]+) practice[s]*.", REG_ICASE|REG_EXTENDED);
  regcomp(&gold_regex, "^Gold: [ ]+([0-9]+).*", REG_ICASE|REG_EXTENDED);
  regcomp(&waypoint_regex, "^Waypoints:[ ]+([0-9]+)[ ]+Waypoint Exp:[ ]+([0-9]+)", REG_ICASE|REG_EXTENDED);

  regcomp(&class_regex, "^\\[[ ]*[0-9]+ ([^ ]+)[ ]*\\] ([^ ]+)[ ]+.*", REG_ICASE|REG_EXTENDED);

//[ 56 Warrior] Mango           690/ 690 hp  248/ 248 mana  379/ 379 mv 56241 xp
  /*
    You are Mango Fruit, level 56.
    Str:   25 (22)     You are a 1907 year old giant (7562 hours and 34 minutes).
    Int:   15 (15)     You have 690/690 hits.
    Wis:   18 (18)     You have 185/248 mana.
    Dex:   22 (12)     You have 411/411 moves.
    Con:   22 (20)     You are carrying 60/62 items.
    You are carrying 512/1000000 kg.
    Exp:     56263     You have 2 practices.
    Gold:     2401     You have wimpy set to 100 hits.
    AC:       -246     You are invincible!
    Align:    -172     You are mean.
    Hitroll:    21     Damroll:    19.
    Mage   :     3     Templar:     3     
    Thief  :     1     Warrior:    34     
    Psychic:     1     Autoexit: yes.  Autoloot: yes.  Autosac: no.
    Waypoints:  15     Waypoint Exp:       150
    Page pausing set to 2000 lines of text.
  */

}

void PostgresQuery::onEvent(Event * e, Connection * c) {
  if (e->getType() == EvDisconnect) {
    ListElement * ele = plist->findEntry(c);
    if (ele)
      plist->deleteEntry(ele);
  }
}

Generated by  Doxygen 1.6.0   Back to index