Browse Source

ckdb - useratts implemented

master
kanoi 10 years ago
parent
commit
a27bed2a83
  1. 706
      src/ckdb.c

706
src/ckdb.c

@ -49,7 +49,7 @@
#define DB_VLOCK "1" #define DB_VLOCK "1"
#define DB_VERSION "0.9.2" #define DB_VERSION "0.9.2"
#define CKDB_VERSION DB_VERSION"-0.300" #define CKDB_VERSION DB_VERSION"-0.302"
#define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL " - from %s %s() line %d"
#define WHERE_FFL_HERE __FILE__, __func__, __LINE__ #define WHERE_FFL_HERE __FILE__, __func__, __LINE__
@ -800,6 +800,8 @@ enum cmd_values {
CMD_WORKERS, CMD_WORKERS,
CMD_ALLUSERS, CMD_ALLUSERS,
CMD_HOMEPAGE, CMD_HOMEPAGE,
CMD_GETATTS,
CMD_SETATTS,
CMD_DSP, CMD_DSP,
CMD_STATS, CMD_STATS,
CMD_PPLNS, CMD_PPLNS,
@ -910,8 +912,8 @@ static char *_transfer_data(K_ITEM *item, WHERE_FFL_ARGS)
} }
mvalue = transfer->mvalue; mvalue = transfer->mvalue;
if (!mvalue) { if (!mvalue) {
/* N.B. name and svalue will terminate even if they are corrupt /* N.B. name and svalue strings will have \0 termination
* since mvalue is NULL */ * even if they are both corrupt, since mvalue is NULL */
quitfrom(1, file, func, line, quitfrom(1, file, func, line,
"Transfer '%s' '%s' has NULL mvalue", "Transfer '%s' '%s' has NULL mvalue",
transfer->name, transfer->svalue); transfer->name, transfer->svalue);
@ -973,17 +975,15 @@ typedef struct users {
#define SALTSIZHEX 32 #define SALTSIZHEX 32
#define SALTSIZBIN 16 #define SALTSIZBIN 16
static K_TREE *users_root; static K_TREE *users_root;
static K_TREE *userid_root; static K_TREE *userid_root;
static K_LIST *users_free; static K_LIST *users_free;
static K_STORE *users_store; static K_STORE *users_store;
/* TODO:
// USERATTS // USERATTS
typedef struct useratts { typedef struct useratts {
int64_t userid; int64_t userid;
char attname[TXT_BIG+1]; char attname[TXT_SML+1];
char status[TXT_BIG+1]; char status[TXT_BIG+1];
char attstr[TXT_BIG+1]; char attstr[TXT_BIG+1];
char attstr2[TXT_BIG+1]; char attstr2[TXT_BIG+1];
@ -998,12 +998,11 @@ typedef struct useratts {
#define LIMIT_USERATTS 0 #define LIMIT_USERATTS 0
#define INIT_USERATTS(_item) INIT_GENERIC(_item, useratts) #define INIT_USERATTS(_item) INIT_GENERIC(_item, useratts)
#define DATA_USERATTS(_var, _item) DATA_GENERIC(_var, _item, useratts, true) #define DATA_USERATTS(_var, _item) DATA_GENERIC(_var, _item, useratts, true)
#define DATA_USERATTS_NULL(_var, _item) DATA_GENERIC(_var, _item, useratts, true) #define DATA_USERATTS_NULL(_var, _item) DATA_GENERIC(_var, _item, useratts, false)
static K_TREE *useratts_root; static K_TREE *useratts_root;
static K_LIST *useratts_free; static K_LIST *useratts_free;
static K_STORE *useratts_store; static K_STORE *useratts_store;
*/
// WORKERS // WORKERS
typedef struct workers { typedef struct workers {
@ -1401,6 +1400,7 @@ static K_STORE *auths_store;
// POOLSTATS poolstats.id.json={...} // POOLSTATS poolstats.id.json={...}
// Store every > 9.5m? // Store every > 9.5m?
// TODO: redo like userstats, but every 10min
#define STATS_PER (9.5*60.0) #define STATS_PER (9.5*60.0)
typedef struct poolstats { typedef struct poolstats {
@ -2664,6 +2664,7 @@ static K_ITEM *find_userid(int64_t userid)
return find_in_ktree(userid_root, &look, cmp_userid, ctx); return find_in_ktree(userid_root, &look, cmp_userid, ctx);
} }
// TODO: endian?
static void make_salt(USERS *users) static void make_salt(USERS *users)
{ {
long int r1, r2, r3, r4; long int r1, r2, r3, r4;
@ -3119,6 +3120,357 @@ void users_reload()
PQfinish(conn); PQfinish(conn);
} }
// default tree order by userid asc,attname asc,expirydate desc
static cmp_t cmp_useratts(K_ITEM *a, K_ITEM *b)
{
USERATTS *ua, *ub;
DATA_USERATTS(ua, a);
DATA_USERATTS(ub, b);
cmp_t c = CMP_BIGINT(ua->userid, ub->userid);
if (c == 0) {
c = CMP_STR(ua->attname, ub->attname);
if (c == 0)
c = CMP_TV(ub->expirydate, ua->expirydate);
}
return c;
}
// Must be R or W locked before call
static K_ITEM *find_useratts(int64_t userid, char *attname)
{
USERATTS useratts;
K_TREE_CTX ctx[1];
K_ITEM look;
useratts.userid = userid;
STRNCPY(useratts.attname, attname);
useratts.expirydate.tv_sec = default_expiry.tv_sec;
useratts.expirydate.tv_usec = default_expiry.tv_usec;
INIT_USERATTS(&look);
look.data = (void *)(&useratts);
return find_in_ktree(useratts_root, &look, cmp_useratts, ctx);
}
static bool useratts_item_add(PGconn *conn, K_ITEM *ua_item, tv_t *cd, bool begun)
{
ExecStatusType rescode;
bool conned = false;
K_TREE_CTX ctx[1];
PGresult *res;
K_ITEM *old_item;
USERATTS *old_useratts, *useratts;
char *upd, *ins;
bool ok = false;
char *params[9 + HISTORYDATECOUNT];
int n, par;
LOGDEBUG("%s(): add", __func__);
DATA_USERATTS(useratts, ua_item);
K_RLOCK(useratts_free);
old_item = find_useratts(useratts->userid, useratts->attname);
K_RUNLOCK(useratts_free);
DATA_USERATTS_NULL(old_useratts, old_item);
/* N.B. the values of the old ua_item record, if it exists,
* are completely ignored i.e. you must provide all values required */
if (!conn) {
conn = dbconnect();
conned = true;
}
if (!begun) {
// Beginning of a write txn
res = PQexec(conn, "Begin", CKPQ_WRITE);
rescode = PQresultStatus(res);
if (!PGOK(rescode)) {
PGLOGERR("Begin", rescode, conn);
goto unparam;
}
PQclear(res);
}
if (old_item) {
upd = "update useratts set expirydate=$1 where userid=$2 and "
"attname=$3 and expirydate=$4";
par = 0;
params[par++] = tv_to_buf(cd, NULL, 0);
params[par++] = bigint_to_buf(old_useratts->userid, NULL, 0);
params[par++] = str_to_buf(old_useratts->attname, NULL, 0);
params[par++] = tv_to_buf((tv_t *)&default_expiry, NULL, 0);
PARCHKVAL(par, 4, params);
res = PQexecParams(conn, upd, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE);
rescode = PQresultStatus(res);
if (!PGOK(rescode)) {
PGLOGERR("Update", rescode, conn);
goto unparam;
}
for (n = 0; n < par; n++)
free(params[n]);
}
par = 0;
params[par++] = bigint_to_buf(useratts->userid, NULL, 0);
params[par++] = str_to_buf(useratts->attname, NULL, 0);
params[par++] = str_to_buf(useratts->status, NULL, 0);
params[par++] = str_to_buf(useratts->attstr, NULL, 0);
params[par++] = str_to_buf(useratts->attstr2, NULL, 0);
params[par++] = bigint_to_buf(useratts->attnum, NULL, 0);
params[par++] = bigint_to_buf(useratts->attnum2, NULL, 0);
params[par++] = tv_to_buf(&(useratts->attdate), NULL, 0);
params[par++] = tv_to_buf(&(useratts->attdate2), NULL, 0);
HISTORYDATEPARAMS(params, par, useratts);
PARCHK(par, params);
ins = "insert into useratts "
"(userid,attname,status,attstr,attstr2,attnum,attnum2,"
"attdate,attdate2"
HISTORYDATECONTROL ") values (" PQPARAM14 ")";
res = PQexecParams(conn, ins, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE);
rescode = PQresultStatus(res);
if (!begun) {
PQclear(res);
if (!PGOK(rescode)) {
PGLOGERR("Insert", rescode, conn);
res = PQexec(conn, "Rollback", CKPQ_WRITE);
goto unparam;
}
res = PQexec(conn, "Commit", CKPQ_WRITE);
ok = true;
} else {
if (PGOK(rescode))
ok = true;
}
unparam:
PQclear(res);
if (conned)
PQfinish(conn);
for (n = 0; n < par; n++)
free(params[n]);
K_WLOCK(useratts_free);
if (ok) {
if (old_item) {
useratts_root = remove_from_ktree(useratts_root, old_item, cmp_useratts, ctx);
copy_tv(&(old_useratts->expirydate), cd);
useratts_root = add_to_ktree(useratts_root, old_item, cmp_useratts);
}
useratts_root = add_to_ktree(useratts_root, ua_item, cmp_useratts);
k_add_head(useratts_store, ua_item);
}
K_WUNLOCK(useratts_free);
return ok;
}
static __maybe_unused K_ITEM *useratts_add(PGconn *conn, char *username, char *attname,
char *status, char *attstr, char *attstr2,
char *attnum, char *attnum2, char *attdate,
char *attdate2, char *by, char *code,
char *inet, tv_t *cd, K_TREE *trf_root,
bool begun)
{
K_ITEM *item, *u_item;
USERATTS *row;
USERS *users;
bool ok = false;
LOGDEBUG("%s(): add", __func__);
K_WLOCK(useratts_free);
item = k_unlink_head(useratts_free);
K_WUNLOCK(useratts_free);
DATA_USERATTS(row, item);
K_RLOCK(users_free);
u_item = find_users(username);
K_RUNLOCK(users_free);
if (!u_item)
goto unitem;
DATA_USERS(users, u_item);
row->userid = users->userid;
STRNCPY(row->attname, attname);
if (status == NULL)
row->status[0] = '\0';
else
STRNCPY(row->status, status);
if (attstr == NULL)
row->attstr[0] = '\0';
else
STRNCPY(row->attstr, attstr);
if (attstr2 == NULL)
row->attstr2[0] = '\0';
else
STRNCPY(row->attstr2, attstr2);
if (attnum == NULL || attnum[0] == '\0')
row->attnum = 0;
else
TXT_TO_BIGINT("attnum", attnum, row->attnum);
if (attnum2 == NULL || attnum2[0] == '\0')
row->attnum2 = 0;
else
TXT_TO_BIGINT("attnum2", attnum2, row->attnum2);
if (attdate == NULL || attdate[0] == '\0')
row->attdate.tv_sec = row->attdate.tv_usec = 0L;
else
TXT_TO_TV("attdate", attdate, row->attdate);
if (attdate2 == NULL || attdate2[0] == '\0')
row->attdate2.tv_sec = row->attdate2.tv_usec = 0L;
else
TXT_TO_TV("attdate2", attdate2, row->attdate2);
HISTORYDATEINIT(row, cd, by, code, inet);
HISTORYDATETRANSFER(trf_root, row);
ok = useratts_item_add(conn, item, cd, begun);
unitem:
K_WLOCK(useratts_free);
if (!ok)
k_add_head(useratts_free, item);
K_WUNLOCK(useratts_free);
if (ok)
return item;
else
return NULL;
}
static bool useratts_fill(PGconn *conn)
{
ExecStatusType rescode;
PGresult *res;
K_ITEM *item;
int n, i;
USERATTS *row;
char *field;
char *sel;
int fields = 9;
bool ok;
LOGDEBUG("%s(): select", __func__);
sel = "select "
"userid,attname,status,attstr,attstr2,attnum,attnum2"
",attdate,attdate2"
HISTORYDATECONTROL
" from useratts";
res = PQexec(conn, sel, CKPQ_READ);
rescode = PQresultStatus(res);
if (!PGOK(rescode)) {
PGLOGERR("Select", rescode, conn);
PQclear(res);
return false;
}
n = PQnfields(res);
if (n != (fields + HISTORYDATECOUNT)) {
LOGERR("%s(): Invalid field count - should be %d, but is %d",
__func__, fields + HISTORYDATECOUNT, n);
PQclear(res);
return false;
}
n = PQntuples(res);
LOGDEBUG("%s(): tree build count %d", __func__, n);
ok = true;
K_WLOCK(useratts_free);
for (i = 0; i < n; i++) {
item = k_unlink_head(useratts_free);
DATA_USERATTS(row, item);
if (everyone_die) {
ok = false;
break;
}
PQ_GET_FLD(res, i, "userid", field, ok);
if (!ok)
break;
TXT_TO_BIGINT("userid", field, row->userid);
PQ_GET_FLD(res, i, "attname", field, ok);
if (!ok)
break;
TXT_TO_STR("attname", field, row->attname);
PQ_GET_FLD(res, i, "status", field, ok);
if (!ok)
break;
TXT_TO_STR("status", field, row->status);
PQ_GET_FLD(res, i, "attstr", field, ok);
if (!ok)
break;
TXT_TO_STR("attstr", field, row->attstr);
PQ_GET_FLD(res, i, "attstr2", field, ok);
if (!ok)
break;
TXT_TO_STR("attstr2", field, row->attstr2);
PQ_GET_FLD(res, i, "attnum", field, ok);
if (!ok)
break;
TXT_TO_BIGINT("attnum", field, row->attnum);
PQ_GET_FLD(res, i, "attnum2", field, ok);
if (!ok)
break;
TXT_TO_BIGINT("attnum2", field, row->attnum2);
PQ_GET_FLD(res, i, "attdate", field, ok);
if (!ok)
break;
TXT_TO_TV("attdate", field, row->attdate);
PQ_GET_FLD(res, i, "attdate2", field, ok);
if (!ok)
break;
TXT_TO_TV("attdate2", field, row->attdate2);
HISTORYDATEFLDS(res, i, row, ok);
if (!ok)
break;
useratts_root = add_to_ktree(useratts_root, item, cmp_useratts);
k_add_head(useratts_store, item);
}
if (!ok)
k_add_head(useratts_free, item);
K_WUNLOCK(useratts_free);
PQclear(res);
if (ok) {
LOGDEBUG("%s(): built", __func__);
LOGWARNING("%s(): loaded %d useratts records", __func__, n);
}
return ok;
}
void useratts_reload()
{
PGconn *conn = dbconnect();
K_WLOCK(useratts_free);
useratts_root = free_ktree(useratts_root, NULL);
k_list_transfer_to_head(useratts_store, useratts_free);
K_WUNLOCK(useratts_free);
useratts_fill(conn);
PQfinish(conn);
}
// order by userid asc,workername asc,expirydate desc // order by userid asc,workername asc,expirydate desc
static cmp_t cmp_workers(K_ITEM *a, K_ITEM *b) static cmp_t cmp_workers(K_ITEM *a, K_ITEM *b)
{ {
@ -7674,6 +8026,8 @@ static bool getdata2()
if (!(ok = sharesummary_fill(conn)) || everyone_die) if (!(ok = sharesummary_fill(conn)) || everyone_die)
goto sukamudai; goto sukamudai;
if (!confirm_sharesummary) { if (!confirm_sharesummary) {
if (!(ok = useratts_fill(conn)) || everyone_die)
goto sukamudai;
if (!(ok = poolstats_fill(conn)) || everyone_die) if (!(ok = poolstats_fill(conn)) || everyone_die)
goto sukamudai; goto sukamudai;
ok = userstats_fill(conn); ok = userstats_fill(conn);
@ -7865,6 +8219,11 @@ static void alloc_storage()
users_root = new_ktree(); users_root = new_ktree();
userid_root = new_ktree(); userid_root = new_ktree();
useratts_free = k_new_list("Useratts", sizeof(USERATTS),
ALLOC_USERATTS, LIMIT_USERATTS, true);
useratts_store = k_new_store(useratts_free);
useratts_root = new_ktree();
workers_free = k_new_list("Workers", sizeof(WORKERS), workers_free = k_new_list("Workers", sizeof(WORKERS),
ALLOC_WORKERS, LIMIT_WORKERS, true); ALLOC_WORKERS, LIMIT_WORKERS, true);
workers_store = k_new_store(workers_free); workers_store = k_new_store(workers_free);
@ -8234,7 +8593,7 @@ static char *cmd_userset(PGconn *conn, char *cmd, char *id,
struckout: struckout:
if (reason) { if (reason) {
snprintf(reply, siz, "ERR.%s", reason); snprintf(reply, siz, "ERR.%s", reason);
LOGERR("%s.%s", id, reply); LOGERR("%s.%s.%s", cmd, id, reply);
return strdup(reply); return strdup(reply);
} }
snprintf(reply, siz, "ok.%s", answer); snprintf(reply, siz, "ok.%s", answer);
@ -9902,6 +10261,304 @@ static char *cmd_homepage(__maybe_unused PGconn *conn, char *cmd, char *id,
return buf; return buf;
} }
static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
tv_t *now, __maybe_unused char *by,
__maybe_unused char *code, __maybe_unused char *inet,
__maybe_unused tv_t *notcd, K_TREE *trf_root)
{
K_ITEM *i_username, *i_attlist, *u_item, *ua_item;
char reply[1024] = "";
size_t siz = sizeof(reply);
char tmp[1024];
USERATTS *useratts;
USERS *users;
char *reason = NULL;
char *answer = NULL;
char *ptr, *comma, *dot;
size_t len, off;
bool first;
LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
i_username = require_name(trf_root, "username", 3, (char *)userpatt, reply, siz);
if (!i_username) {
reason = "Missing username";
goto nuts;
}
K_RLOCK(users_free);
u_item = find_users(transfer_data(i_username));
K_RUNLOCK(users_free);
if (!u_item) {
reason = "Unknown user";
goto nuts;
} else {
DATA_USERS(users, u_item);
i_attlist = require_name(trf_root, "attlist", 1, NULL, reply, siz);
if (!i_attlist) {
reason = "Missing attlist";
goto nuts;
}
APPEND_REALLOC_INIT(answer, off, len);
ptr = strdup(transfer_data(i_attlist));
first = true;
while (ptr && *ptr) {
comma = strchr(ptr, ',');
if (comma)
*(comma++) = '\0';
dot = strchr(ptr, '.');
if (!dot) {
free(answer);
reason = "Missing element";
goto nuts;
}
*(dot++) = '\0';
K_RLOCK(useratts_free);
ua_item = find_useratts(users->userid, ptr);
K_RUNLOCK(useratts_free);
/* web code must check the existance of the attname
* in the reply since it will be missing if it doesn't
* exist in the DB */
if (ua_item) {
char num_buf[BIGINT_BUFSIZ];
char ctv_buf[CDATE_BUFSIZ];
char *ans;
DATA_USERATTS(useratts, ua_item);
if (strcmp(dot, "str") == 0) {
ans = useratts->attstr;
} else if (strcmp(dot, "str2") == 0) {
ans = useratts->attstr2;
} else if (strcmp(dot, "num") == 0) {
bigint_to_buf(useratts->attnum,
num_buf,
sizeof(num_buf));
ans = num_buf;
} else if (strcmp(dot, "num2") == 0) {
bigint_to_buf(useratts->attnum2,
num_buf,
sizeof(num_buf));
ans = num_buf;
} else if (strcmp(dot, "date") == 0) {
ctv_to_buf(&(useratts->attdate),
ctv_buf,
sizeof(num_buf));
ans = ctv_buf;
} else if (strcmp(dot, "dateexp") == 0) {
// Y/N if date is before now (not expired)
if (tv_newer(&(useratts->attdate), now))
ans = TRUE_STR;
else
ans = FALSE_STR;
} else if (strcmp(dot, "date2") == 0) {
ctv_to_buf(&(useratts->attdate2),
ctv_buf,
sizeof(num_buf));
ans = ctv_buf;
} else if (strcmp(dot, "date2exp") == 0) {
// Y/N if date2 is before now (not expired)
if (tv_newer(&(useratts->attdate2), now))
ans = TRUE_STR;
else
ans = FALSE_STR;
} else {
free(answer);
reason = "Unknown element";
goto nuts;
}
snprintf(tmp, sizeof(tmp), "%s%s.%s=%s",
first ? EMPTY : FLDSEPSTR,
ptr, dot, ans);
APPEND_REALLOC(answer, off, len, tmp);
first = false;
}
ptr = comma;
}
}
nuts:
if (reason) {
snprintf(reply, siz, "ERR.%s", reason);
LOGERR("%s.%s.%s", cmd, id, reply);
return strdup(reply);
}
snprintf(reply, siz, "ok.%s", answer);
LOGDEBUG("%s.%s", id, answer);
free(answer);
return strdup(reply);
}
static void att_to_date(tv_t *date, char *data, tv_t *now)
{
int add;
if (strncasecmp(data, "now+", 4) == 0) {
add = atoi(data+4);
copy_tv(date, now);
date->tv_sec += add;
} else if (strcasecmp(data, "now") == 0) {
copy_tv(date, now);
} else {
txt_to_ctv("date", data, date, sizeof(*date));
}
}
static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
tv_t *now, char *by, char *code, char *inet,
__maybe_unused tv_t *notcd, K_TREE *trf_root)
{
ExecStatusType rescode;
PGresult *res;
bool conned = false;
K_ITEM *i_username, *t_item, *u_item, *ua_item = NULL;
K_TREE_CTX ctx[1];
char reply[1024] = "";
size_t siz = sizeof(reply);
TRANSFER *transfer;
USERATTS *useratts;
USERS *users;
char attname[sizeof(useratts->attname)*2];
char *reason = NULL;
char *dot, *data;
bool begun = false;
LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
i_username = require_name(trf_root, "username", 3, (char *)userpatt, reply, siz);
if (!i_username) {
reason = "Missing user";
goto bats;
}
K_RLOCK(users_free);
u_item = find_users(transfer_data(i_username));
K_RUNLOCK(users_free);
if (!u_item) {
reason = "Unknown user";
goto bats;
} else {
DATA_USERS(users, u_item);
/* format is: ua_attname.element=value
* i.e. eash starts with the constant "ua_"
* transfer will sort them so that any of the same attname
* will be next to each other
* thus can combine multiple elements for the same attname
* into one single useratts record (as is mandatory) */
t_item = first_in_ktree(trf_root, ctx);
while (t_item) {
DATA_TRANSFER(transfer, t_item);
if (strncmp(transfer->name, "ua_", 3) == 0) {
data = transfer_data(t_item);
STRNCPY(attname, transfer->name + 3);
dot = strchr(attname, '.');
if (!dot) {
reason = "Missing element";
goto bats;
}
*(dot++) = '\0';
// If we already had a different one, save it to the DB
if (ua_item && strcmp(useratts->attname, attname) != 0) {
if (conn == NULL) {
conn = dbconnect();
conned = true;
}
if (!begun) {
// Beginning of a write txn
res = PQexec(conn, "Begin", CKPQ_WRITE);
rescode = PQresultStatus(res);
PQclear(res);
if (!PGOK(rescode)) {
PGLOGERR("Begin", rescode, conn);
reason = "DBERR";
goto bats;
}
begun = true;
}
if (useratts_item_add(conn, ua_item, now, begun))
ua_item = NULL;
else {
res = PQexec(conn, "Rollback", CKPQ_WRITE);
PQclear(res);
reason = "DBERR";
goto bats;
}
}
if (!ua_item) {
K_RLOCK(useratts_free);
ua_item = k_unlink_head(useratts_free);
K_RUNLOCK(useratts_free);
DATA_USERATTS(useratts, ua_item);
bzero(useratts, sizeof(*useratts));
useratts->userid = users->userid;
STRNCPY(useratts->attname, attname);
HISTORYDATEINIT(useratts, now, by, code, inet);
HISTORYDATETRANSFER(trf_root, useratts);
}
if (strcmp(dot, "str") == 0) {
STRNCPY(useratts->attstr, data);
} else if (strcmp(dot, "str2") == 0) {
STRNCPY(useratts->attstr2, data);
} else if (strcmp(dot, "num") == 0) {
TXT_TO_BIGINT("num", data, useratts->attnum);
} else if (strcmp(dot, "num2") == 0) {
TXT_TO_BIGINT("num2", data, useratts->attnum2);
} else if (strcmp(dot, "date") == 0) {
att_to_date(&(useratts->attdate), data, now);
} else if (strcmp(dot, "date2") == 0) {
att_to_date(&(useratts->attdate2), data, now);
} else {
reason = "Unknown element";
goto bats;
}
}
t_item = next_in_ktree(ctx);
}
if (ua_item) {
if (conn == NULL) {
conn = dbconnect();
conned = true;
}
if (!begun) {
// Beginning of a write txn
res = PQexec(conn, "Begin", CKPQ_WRITE);
rescode = PQresultStatus(res);
PQclear(res);
if (!PGOK(rescode)) {
PGLOGERR("Begin", rescode, conn);
reason = "DBERR";
goto bats;
}
begun = true;
}
if (!useratts_item_add(conn, ua_item, now, begun)) {
res = PQexec(conn, "Rollback", CKPQ_WRITE);
PQclear(res);
reason = "DBERR";
goto bats;
}
res = PQexec(conn, "Commit", CKPQ_WRITE);
PQclear(res);
}
}
bats:
if (conned)
PQfinish(conn);
if (reason) {
if (ua_item) {
K_WLOCK(useratts_free);
k_add_head(useratts_free, ua_item);
K_WUNLOCK(useratts_free);
}
snprintf(reply, siz, "ERR.%s", reason);
LOGERR("%s.%s.%s", cmd, id, reply);
return strdup(reply);
}
snprintf(reply, siz, "ok.set");
LOGDEBUG("%s.%s", id, reply);
return strdup(reply);
}
// order by userid asc // order by userid asc
static cmp_t cmp_mu(K_ITEM *a, K_ITEM *b) static cmp_t cmp_mu(K_ITEM *a, K_ITEM *b)
{ {
@ -10394,7 +11051,7 @@ static char *cmd_stats(__maybe_unused PGconn *conn, char *cmd, char *id,
return buf; return buf;
} }
// TODO: limit access // TODO: limit access by having seperate sockets for each
#define ACCESS_POOL "p" #define ACCESS_POOL "p"
#define ACCESS_SYSTEM "s" #define ACCESS_SYSTEM "s"
#define ACCESS_WEB "w" #define ACCESS_WEB "w"
@ -10484,6 +11141,8 @@ static struct CMDS {
{ CMD_WORKERS, "workers", false, false, cmd_workers, ACCESS_WEB }, { CMD_WORKERS, "workers", false, false, cmd_workers, ACCESS_WEB },
{ CMD_ALLUSERS, "allusers", false, false, cmd_allusers, ACCESS_WEB }, { CMD_ALLUSERS, "allusers", false, false, cmd_allusers, ACCESS_WEB },
{ CMD_HOMEPAGE, "homepage", false, false, cmd_homepage, ACCESS_WEB }, { CMD_HOMEPAGE, "homepage", false, false, cmd_homepage, ACCESS_WEB },
{ CMD_GETATTS, "getatts", false, false, cmd_getatts, ACCESS_WEB },
{ CMD_SETATTS, "setatts", false, false, cmd_setatts, ACCESS_WEB },
{ CMD_DSP, "dsp", false, false, cmd_dsp, ACCESS_SYSTEM }, { CMD_DSP, "dsp", false, false, cmd_dsp, ACCESS_SYSTEM },
{ CMD_STATS, "stats", true, false, cmd_stats, ACCESS_SYSTEM }, { CMD_STATS, "stats", true, false, cmd_stats, ACCESS_SYSTEM },
{ CMD_PPLNS, "pplns", false, false, cmd_pplns, ACCESS_SYSTEM }, { CMD_PPLNS, "pplns", false, false, cmd_pplns, ACCESS_SYSTEM },
@ -11152,6 +11811,7 @@ static void *socketer(__maybe_unused void *arg)
char *last_newpass = NULL, *reply_newpass = NULL; char *last_newpass = NULL, *reply_newpass = NULL;
char *last_userset = NULL, *reply_userset = NULL; char *last_userset = NULL, *reply_userset = NULL;
char *last_newid = NULL, *reply_newid = NULL; char *last_newid = NULL, *reply_newid = NULL;
char *last_setatts = NULL, *reply_setatts = NULL;
char *last_web = NULL, *reply_web = NULL; char *last_web = NULL, *reply_web = NULL;
char *reply_last, duptype[CMD_SIZ+1]; char *reply_last, duptype[CMD_SIZ+1];
enum cmd_values cmdnum; enum cmd_values cmdnum;
@ -11213,10 +11873,12 @@ static void *socketer(__maybe_unused void *arg)
* message is sent within the same second and thus * message is sent within the same second and thus
* will effectively reduce the processing load for * will effectively reduce the processing load for
* sequential duplicates * sequential duplicates
* adduser duplicates are handled by the DB code * As per the 'if' list below,
* auth, chkpass, adduser, newpass, newid - * remember individual last messages and replies and
* remember individual last message and reply and repeat * repeat the reply without reprocessing the message
* the reply without reprocessing the message * The rest are remembered in the same buffer 'web'
* so a duplicate will not be seen if another 'web'
* command arrived between two duplicate commands
*/ */
dup = false; dup = false;
// These are ordered approximately most likely first // These are ordered approximately most likely first
@ -11236,7 +11898,13 @@ static void *socketer(__maybe_unused void *arg)
reply_last = reply_newid; reply_last = reply_newid;
dup = true; dup = true;
} else if (last_addrauth && strcmp(last_addrauth, buf) == 0) { } else if (last_addrauth && strcmp(last_addrauth, buf) == 0) {
reply_last = reply_auth; reply_last = reply_addrauth;
dup = true;
} else if (last_userset && strcmp(last_userset, buf) == 0) {
reply_last = reply_userset;
dup = true;
} else if (last_setatts && strcmp(last_setatts, buf) == 0) {
reply_last = reply_setatts;
dup = true; dup = true;
} else if (last_web && strcmp(last_web, buf) == 0) { } else if (last_web && strcmp(last_web, buf) == 0) {
reply_last = reply_web; reply_last = reply_web;
@ -11324,6 +11992,8 @@ static void *socketer(__maybe_unused void *arg)
case CMD_ADDUSER: case CMD_ADDUSER:
case CMD_NEWPASS: case CMD_NEWPASS:
case CMD_USERSET: case CMD_USERSET:
case CMD_GETATTS:
case CMD_SETATTS:
case CMD_BLOCKLIST: case CMD_BLOCKLIST:
case CMD_NEWID: case CMD_NEWID:
case CMD_STATS: case CMD_STATS:
@ -11360,6 +12030,10 @@ static void *socketer(__maybe_unused void *arg)
case CMD_NEWID: case CMD_NEWID:
STORELASTREPLY(newid); STORELASTREPLY(newid);
break; break;
case CMD_SETATTS:
STORELASTREPLY(setatts);
break;
// The rest
default: default:
free(rep); free(rep);
} }
@ -11554,6 +12228,8 @@ static bool reload_line(PGconn *conn, char *filename, uint64_t count, char *buf)
case CMD_WORKERS: case CMD_WORKERS:
case CMD_ALLUSERS: case CMD_ALLUSERS:
case CMD_HOMEPAGE: case CMD_HOMEPAGE:
case CMD_GETATTS:
case CMD_SETATTS:
case CMD_DSP: case CMD_DSP:
case CMD_STATS: case CMD_STATS:
case CMD_PPLNS: case CMD_PPLNS:

Loading…
Cancel
Save