ckdb - comment getatts and setatts, and add expatts
This commit is contained in:
parent
fc7964c7ab
commit
d0bcf5ca26
218
src/ckdb.c
218
src/ckdb.c
@ -49,7 +49,7 @@
|
||||
|
||||
#define DB_VLOCK "1"
|
||||
#define DB_VERSION "0.9.2"
|
||||
#define CKDB_VERSION DB_VERSION"-0.302"
|
||||
#define CKDB_VERSION DB_VERSION"-0.303"
|
||||
|
||||
#define WHERE_FFL " - from %s %s() line %d"
|
||||
#define WHERE_FFL_HERE __FILE__, __func__, __LINE__
|
||||
@ -802,6 +802,7 @@ enum cmd_values {
|
||||
CMD_HOMEPAGE,
|
||||
CMD_GETATTS,
|
||||
CMD_SETATTS,
|
||||
CMD_EXPATTS,
|
||||
CMD_DSP,
|
||||
CMD_STATS,
|
||||
CMD_PPLNS,
|
||||
@ -3343,6 +3344,74 @@ unitem:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool useratts_item_expire(PGconn *conn, K_ITEM *ua_item, tv_t *cd)
|
||||
{
|
||||
ExecStatusType rescode;
|
||||
bool conned = false;
|
||||
K_TREE_CTX ctx[1];
|
||||
PGresult *res;
|
||||
K_ITEM *item;
|
||||
USERATTS *useratts;
|
||||
char *upd;
|
||||
bool ok = false;
|
||||
char *params[4 + HISTORYDATECOUNT];
|
||||
int n, par = 0;
|
||||
|
||||
LOGDEBUG("%s(): add", __func__);
|
||||
|
||||
DATA_USERATTS(useratts, ua_item);
|
||||
|
||||
/* This is pointless if ua_item is part of the tree, however,
|
||||
* it allows for if ua_item isn't already part of the tree */
|
||||
K_RLOCK(useratts_free);
|
||||
item = find_useratts(useratts->userid, useratts->attname);
|
||||
K_RUNLOCK(useratts_free);
|
||||
|
||||
if (item) {
|
||||
DATA_USERATTS(useratts, item);
|
||||
|
||||
if (!conn) {
|
||||
conn = dbconnect();
|
||||
conned = true;
|
||||
}
|
||||
|
||||
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(useratts->userid, NULL, 0);
|
||||
params[par++] = str_to_buf(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;
|
||||
}
|
||||
}
|
||||
ok = true;
|
||||
unparam:
|
||||
if (par) {
|
||||
PQclear(res);
|
||||
if (conned)
|
||||
PQfinish(conn);
|
||||
for (n = 0; n < par; n++)
|
||||
free(params[n]);
|
||||
}
|
||||
|
||||
K_WLOCK(useratts_free);
|
||||
if (ok && item) {
|
||||
useratts_root = remove_from_ktree(useratts_root, item, cmp_useratts, ctx);
|
||||
copy_tv(&(useratts->expirydate), cd);
|
||||
useratts_root = add_to_ktree(useratts_root, item, cmp_useratts);
|
||||
}
|
||||
K_WUNLOCK(useratts_free);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool useratts_fill(PGconn *conn)
|
||||
{
|
||||
ExecStatusType rescode;
|
||||
@ -10261,6 +10330,15 @@ static char *cmd_homepage(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Return the list of useratts for the given username=value
|
||||
* Format is attlist=attname.element,attname.element,...
|
||||
* Replies will be attname.element=value
|
||||
* The 2 date fields, date and date2, have a secondary element name
|
||||
* dateexp and date2exp
|
||||
* This will return Y or N depending upon if the date has expired as:
|
||||
* attname.dateexp=N (or Y) and attname.date2exp=N (or Y)
|
||||
* Expired means the date is <= now
|
||||
*/
|
||||
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,
|
||||
@ -10274,7 +10352,7 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
USERS *users;
|
||||
char *reason = NULL;
|
||||
char *answer = NULL;
|
||||
char *ptr, *comma, *dot;
|
||||
char *attlist = NULL, *ptr, *comma, *dot;
|
||||
size_t len, off;
|
||||
bool first;
|
||||
|
||||
@ -10302,7 +10380,7 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
}
|
||||
|
||||
APPEND_REALLOC_INIT(answer, off, len);
|
||||
ptr = strdup(transfer_data(i_attlist));
|
||||
attlist = ptr = strdup(transfer_data(i_attlist));
|
||||
first = true;
|
||||
while (ptr && *ptr) {
|
||||
comma = strchr(ptr, ',');
|
||||
@ -10310,7 +10388,6 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
*(comma++) = '\0';
|
||||
dot = strchr(ptr, '.');
|
||||
if (!dot) {
|
||||
free(answer);
|
||||
reason = "Missing element";
|
||||
goto nuts;
|
||||
}
|
||||
@ -10346,7 +10423,7 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
sizeof(num_buf));
|
||||
ans = ctv_buf;
|
||||
} else if (strcmp(dot, "dateexp") == 0) {
|
||||
// Y/N if date is before now (not expired)
|
||||
// Y/N if date is <= now (expired)
|
||||
if (tv_newer(&(useratts->attdate), now))
|
||||
ans = TRUE_STR;
|
||||
else
|
||||
@ -10357,13 +10434,12 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
sizeof(num_buf));
|
||||
ans = ctv_buf;
|
||||
} else if (strcmp(dot, "date2exp") == 0) {
|
||||
// Y/N if date2 is before now (not expired)
|
||||
// Y/N if date2 is <= now (expired)
|
||||
if (tv_newer(&(useratts->attdate2), now))
|
||||
ans = TRUE_STR;
|
||||
else
|
||||
ans = FALSE_STR;
|
||||
} else {
|
||||
free(answer);
|
||||
reason = "Unknown element";
|
||||
goto nuts;
|
||||
}
|
||||
@ -10377,7 +10453,12 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
|
||||
}
|
||||
}
|
||||
nuts:
|
||||
if (attlist)
|
||||
free(attlist);
|
||||
|
||||
if (reason) {
|
||||
if (answer)
|
||||
free(answer);
|
||||
snprintf(reply, siz, "ERR.%s", reason);
|
||||
LOGERR("%s.%s.%s", cmd, id, reply);
|
||||
return strdup(reply);
|
||||
@ -10403,6 +10484,21 @@ static void att_to_date(tv_t *date, char *data, tv_t *now)
|
||||
}
|
||||
}
|
||||
|
||||
/* Store useratts in the DB for the given username=value
|
||||
* Format is 1 or more: ua_attname.element=value
|
||||
* i.e. each starts with the constant "ua_"
|
||||
* attname cannot contain Tab . or =
|
||||
* element is per the coded list below, which also cannot contain Tab . or =
|
||||
* Any matching useratts attnames found currently in the DB are expired
|
||||
* Transfer will sort them so that any of the same attname
|
||||
* will be next to each other
|
||||
* thus will combine multiple elements for the same attname
|
||||
* into one single useratts record (as is mandatory)
|
||||
* The 2 date fields date and date2 require either epoch values sec,usec
|
||||
* (usec is optional and defaults to 0) or one of: now or now+NNN
|
||||
* now is the current epoch value and now+NNN is the epoch + NNN seconds
|
||||
* See att_to_date() above
|
||||
* */
|
||||
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)
|
||||
@ -10421,6 +10517,7 @@ static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
|
||||
char *reason = NULL;
|
||||
char *dot, *data;
|
||||
bool begun = false;
|
||||
int set = 0, db = 0;
|
||||
|
||||
LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
|
||||
|
||||
@ -10439,12 +10536,6 @@ static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
|
||||
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);
|
||||
@ -10475,9 +10566,10 @@ static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
|
||||
}
|
||||
begun = true;
|
||||
}
|
||||
if (useratts_item_add(conn, ua_item, now, begun))
|
||||
if (useratts_item_add(conn, ua_item, now, begun)) {
|
||||
ua_item = NULL;
|
||||
else {
|
||||
db++;
|
||||
} else {
|
||||
res = PQexec(conn, "Rollback", CKPQ_WRITE);
|
||||
PQclear(res);
|
||||
reason = "DBERR";
|
||||
@ -10495,18 +10587,25 @@ static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
|
||||
HISTORYDATEINIT(useratts, now, by, code, inet);
|
||||
HISTORYDATETRANSFER(trf_root, useratts);
|
||||
}
|
||||
// List of valid element names for storage
|
||||
if (strcmp(dot, "str") == 0) {
|
||||
STRNCPY(useratts->attstr, data);
|
||||
set++;
|
||||
} else if (strcmp(dot, "str2") == 0) {
|
||||
STRNCPY(useratts->attstr2, data);
|
||||
set++;
|
||||
} else if (strcmp(dot, "num") == 0) {
|
||||
TXT_TO_BIGINT("num", data, useratts->attnum);
|
||||
set++;
|
||||
} else if (strcmp(dot, "num2") == 0) {
|
||||
TXT_TO_BIGINT("num2", data, useratts->attnum2);
|
||||
set++;
|
||||
} else if (strcmp(dot, "date") == 0) {
|
||||
att_to_date(&(useratts->attdate), data, now);
|
||||
set++;
|
||||
} else if (strcmp(dot, "date2") == 0) {
|
||||
att_to_date(&(useratts->attdate2), data, now);
|
||||
set++;
|
||||
} else {
|
||||
reason = "Unknown element";
|
||||
goto bats;
|
||||
@ -10537,6 +10636,7 @@ static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
|
||||
reason = "DBERR";
|
||||
goto bats;
|
||||
}
|
||||
db++;
|
||||
res = PQexec(conn, "Commit", CKPQ_WRITE);
|
||||
PQclear(res);
|
||||
}
|
||||
@ -10554,11 +10654,94 @@ bats:
|
||||
LOGERR("%s.%s.%s", cmd, id, reply);
|
||||
return strdup(reply);
|
||||
}
|
||||
snprintf(reply, siz, "ok.set");
|
||||
snprintf(reply, siz, "ok.set %d,%d", db, set);
|
||||
LOGDEBUG("%s.%s", id, reply);
|
||||
return strdup(reply);
|
||||
}
|
||||
|
||||
/* Expire the list of useratts for the given username=value
|
||||
* Format is attlist=attname,attname,...
|
||||
* Each matching DB attname record will have it's expirydate set to now
|
||||
* thus an attempt to access it with getatts will not find it and
|
||||
* return nothing for that attname
|
||||
*/
|
||||
static char *cmd_expatts(__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);
|
||||
USERATTS *useratts;
|
||||
USERS *users;
|
||||
char *reason = NULL;
|
||||
char *attlist, *ptr, *comma;
|
||||
int db = 0, mis = 0;
|
||||
|
||||
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 rats;
|
||||
}
|
||||
|
||||
K_RLOCK(users_free);
|
||||
u_item = find_users(transfer_data(i_username));
|
||||
K_RUNLOCK(users_free);
|
||||
|
||||
if (!u_item) {
|
||||
reason = "Unknown user";
|
||||
goto rats;
|
||||
} else {
|
||||
DATA_USERS(users, u_item);
|
||||
i_attlist = require_name(trf_root, "attlist", 1, NULL, reply, siz);
|
||||
if (!i_attlist) {
|
||||
reason = "Missing attlist";
|
||||
goto rats;
|
||||
}
|
||||
|
||||
attlist = ptr = strdup(transfer_data(i_attlist));
|
||||
while (ptr && *ptr) {
|
||||
comma = strchr(ptr, ',');
|
||||
if (comma)
|
||||
*(comma++) = '\0';
|
||||
K_RLOCK(useratts_free);
|
||||
ua_item = find_useratts(users->userid, ptr);
|
||||
K_RUNLOCK(useratts_free);
|
||||
if (!ua_item)
|
||||
mis++;
|
||||
else {
|
||||
DATA_USERATTS(useratts, ua_item);
|
||||
HISTORYDATEINIT(useratts, now, by, code, inet);
|
||||
HISTORYDATETRANSFER(trf_root, useratts);
|
||||
/* Since we are expiring records, don't bother
|
||||
* with combining them all into a single
|
||||
* transaction and don't abort on error
|
||||
* Thus if an error is returned, retry would be
|
||||
* necessary, but some may also have been
|
||||
* expired successfully */
|
||||
if (!useratts_item_expire(conn, ua_item, now))
|
||||
reason = "DBERR";
|
||||
else
|
||||
db++;
|
||||
}
|
||||
ptr = comma;
|
||||
}
|
||||
free(attlist);
|
||||
}
|
||||
rats:
|
||||
if (reason) {
|
||||
snprintf(reply, siz, "ERR.%s", reason);
|
||||
LOGERR("%s.%s.%s", cmd, id, reply);
|
||||
return strdup(reply);
|
||||
}
|
||||
snprintf(reply, siz, "ok.exp %d,%d", db, mis);
|
||||
LOGDEBUG("%s.%s.%s", cmd, id, reply);
|
||||
return strdup(reply);
|
||||
}
|
||||
|
||||
// order by userid asc
|
||||
static cmp_t cmp_mu(K_ITEM *a, K_ITEM *b)
|
||||
{
|
||||
@ -11143,6 +11326,7 @@ static struct CMDS {
|
||||
{ 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_EXPATTS, "expatts", false, false, cmd_expatts, ACCESS_WEB },
|
||||
{ CMD_DSP, "dsp", false, false, cmd_dsp, ACCESS_SYSTEM },
|
||||
{ CMD_STATS, "stats", true, false, cmd_stats, ACCESS_SYSTEM },
|
||||
{ CMD_PPLNS, "pplns", false, false, cmd_pplns, ACCESS_SYSTEM },
|
||||
@ -11994,6 +12178,7 @@ static void *socketer(__maybe_unused void *arg)
|
||||
case CMD_USERSET:
|
||||
case CMD_GETATTS:
|
||||
case CMD_SETATTS:
|
||||
case CMD_EXPATTS:
|
||||
case CMD_BLOCKLIST:
|
||||
case CMD_NEWID:
|
||||
case CMD_STATS:
|
||||
@ -12230,6 +12415,7 @@ static bool reload_line(PGconn *conn, char *filename, uint64_t count, char *buf)
|
||||
case CMD_HOMEPAGE:
|
||||
case CMD_GETATTS:
|
||||
case CMD_SETATTS:
|
||||
case CMD_EXPATTS:
|
||||
case CMD_DSP:
|
||||
case CMD_STATS:
|
||||
case CMD_PPLNS:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user