diff --git a/pool/base.php b/pool/base.php index 4a64a75e..5b24c4ab 100644 --- a/pool/base.php +++ b/pool/base.php @@ -63,8 +63,9 @@ function howlongago($sec) return $des; } # -function howmanyhrs($sec) +function howmanyhrs($tot) { + $sec = round($tot); if ($sec < 60) $des = $sec.'s'; else @@ -89,6 +90,11 @@ function btcfmt($amt) return number_format($amt, 8); } # +function utcd($when) +{ + return gmdate('Y-m-d H:i:s+00', round($when)); +} +# global $sipre; # max of uint64 is ~1.845x10^19, 'Z' is above that (10^21) # max of uint256 is ~1.158x10^77, which is well above 'Y' (10^24) diff --git a/pool/db.php b/pool/db.php index cd9d347c..6c85e9cd 100644 --- a/pool/db.php +++ b/pool/db.php @@ -270,6 +270,18 @@ function getMPayouts($user) return repDecode($rep); } # +function getShifts($user) +{ + if ($user == false) + showIndex(); + $flds = array('username' => $user); + $msg = msgEncode('shifts', 'shift', $flds, $user); + $rep = sendsockreply('getShifts', $msg); + if (!$rep) + dbdown(); + return repDecode($rep); +} +# function getBlocks($user) { if ($user == false) diff --git a/pool/page_blocks.php b/pool/page_blocks.php index 4040ed5b..7d8a35e8 100644 --- a/pool/page_blocks.php +++ b/pool/page_blocks.php @@ -184,7 +184,7 @@ function doblocks($data, $user) if ($user !== null) $pg .= "".htmlspecialchars($ans['workername:'.$i]).''; $pg .= "".btcfmt($ans['reward:'.$i]).''; - $pg .= "".gmdate('Y-m-d H:i:s+00', $ans['firstcreatedate:'.$i]).''; + $pg .= "".utcd($ans['firstcreatedate:'.$i]).''; $pg .= "".$stat.''; $pg .= "$stara$acc"; $pg .= "$bpct"; diff --git a/pool/page_shifts.php b/pool/page_shifts.php new file mode 100644 index 00000000..0704bf02 --- /dev/null +++ b/pool/page_shifts.php @@ -0,0 +1,62 @@ +\n"; + $pg .= ""; + $pg .= "Shift"; + $pg .= "Start"; + $pg .= "Elapsed"; + $pg .= "Your Diff"; + $pg .= "Avg Hs"; + $pg .= "Shares"; + $pg .= "Avg Share"; + $pg .= "\n"; + if ($ans['STATUS'] != 'ok') + $pg = '

Shifts

'.$pg; + else + { + $count = $ans['rows']; + $pg = '

Last '.($count+1).' Shifts

'.$pg; + for ($i = 0; $i < $count; $i++) + { + if (($i % 2) == 0) + $row = 'even'; + else + $row = 'odd'; + + $pg .= ""; + $shif = preg_replace(array('/^.* to /','/^.*fin: /'), '', $ans['shift:'.$i]); + $pg .= "$shif"; + $start = $ans['start:'.$i]; + $pg .= ''.utcd($start).''; + $nd = $ans['end:'.$i]; + $elapsed = $nd - $start; + $pg .= ''.howmanyhrs($elapsed).''; + $diffacc = $ans['diffacc:'.$i]; + $pg .= ''.difffmt($diffacc).''; + $hr = $diffacc * pow(2,32) / $elapsed; + $pg .= ''.dsprate($hr).''; + $shareacc = $ans['shareacc:'.$i]; + $pg .= ''.difffmt($shareacc).''; + if ($shareacc > 0) + $avgsh = $diffacc / $shareacc; + else + $avgsh = 0; + $pg .= ''.number_format($avgsh, 2).''; + $pg .= "\n"; + } + } + $pg .= "\n"; + + return $pg; +} +# +function show_shifts($info, $page, $menu, $name, $user) +{ + gopage($info, NULL, 'doshifts', $page, $menu, $name, $user); +} +# +?> diff --git a/pool/prime.php b/pool/prime.php index 56973cda..ced6f53d 100644 --- a/pool/prime.php +++ b/pool/prime.php @@ -73,6 +73,7 @@ function check() 'User Settings' => 'userset' ), 'Workers' => array( + 'Shifts ' => 'shifts', 'Workers ' => 'workers', 'Management' => 'workmgt', ), diff --git a/src/ckdb.c b/src/ckdb.c index 2c8d44c3..8ad9a05e 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -2665,6 +2665,7 @@ static void *socketer(__maybe_unused void *arg) case CMD_PPLNS2: case CMD_PAYOUTS: case CMD_MPAYOUTS: + case CMD_SHIFTS: case CMD_DSP: case CMD_BLOCKSTATUS: if (!startup_complete) { @@ -2885,6 +2886,7 @@ static bool reload_line(PGconn *conn, char *filename, uint64_t count, char *buf) case CMD_PPLNS2: case CMD_PAYOUTS: case CMD_MPAYOUTS: + case CMD_SHIFTS: case CMD_USERSTATUS: case CMD_MARKS: LOGERR("%s() Message line %"PRIu64" '%s' - invalid - ignored", diff --git a/src/ckdb.h b/src/ckdb.h index 35de904e..a0646a2d 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -52,7 +52,7 @@ #define DB_VLOCK "1" #define DB_VERSION "1.0.0" -#define CKDB_VERSION DB_VERSION"-1.010" +#define CKDB_VERSION DB_VERSION"-1.011" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -343,6 +343,7 @@ enum cmd_values { CMD_PPLNS2, CMD_PAYOUTS, CMD_MPAYOUTS, + CMD_SHIFTS, CMD_USERSTATUS, CMD_MARKS, CMD_END @@ -1719,6 +1720,7 @@ extern int32_t _coinbase1height(char *coinbase1, WHERE_FFL_ARGS); extern cmp_t _cmp_height(char *coinbase1a, char *coinbase1b, WHERE_FFL_ARGS); extern cmp_t cmp_workinfo_height(K_ITEM *a, K_ITEM *b); extern K_ITEM *find_workinfo(int64_t workinfoid, K_TREE_CTX *ctx); +extern K_ITEM *next_workinfo(int64_t workinfoid, K_TREE_CTX *ctx); extern bool workinfo_age(PGconn *conn, int64_t workinfoid, char *poolinstance, char *by, char *code, char *inet, tv_t *cd, tv_t *ss_first, tv_t *ss_last, int64_t *ss_count, diff --git a/src/ckdb_cmd.c b/src/ckdb_cmd.c index 31659147..303be5cd 100644 --- a/src/ckdb_cmd.c +++ b/src/ckdb_cmd.c @@ -4372,7 +4372,7 @@ static char *cmd_mpayouts(__maybe_unused PGconn *conn, char *cmd, char *id, po_item = prev_in_ktree(ctx); DATA_PAYOUTS_NULL(payouts, po_item); } - K_RUNLOCK(miningpayouts_free); + K_RUNLOCK(payouts_free); snprintf(tmp, sizeof(tmp), "rows=%d%cflds=%s%c", rows, FLDSEP, @@ -4387,6 +4387,176 @@ static char *cmd_mpayouts(__maybe_unused PGconn *conn, char *cmd, char *id, return buf; } +static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id, + __maybe_unused tv_t *now, __maybe_unused char *by, + __maybe_unused char *code, __maybe_unused char *inet, + __maybe_unused tv_t *notcd, + __maybe_unused K_TREE *trf_root) +{ + K_ITEM *i_username, *u_item, ms_look, *wm_item, *ms_item, *wi_item; + K_TREE_CTX wm_ctx[1], ms_ctx[1]; + WORKMARKERS *wm; + WORKINFO *wi; + MARKERSUMMARY markersummary, *ms, ms_add; + USERS *users; + char reply[1024] = ""; + char tmp[1024]; + size_t siz = sizeof(reply); + char *buf; + size_t len, off; + tv_t marker_end = { 0L, 0L }; + int rows; + + LOGDEBUG("%s(): cmd '%s'", __func__, cmd); + + i_username = require_name(trf_root, "username", 3, (char *)userpatt, reply, siz); + if (!i_username) + return strdup(reply); + + K_RLOCK(users_free); + u_item = find_users(transfer_data(i_username)); + K_RUNLOCK(users_free); + if (!u_item) + return strdup("bad"); + DATA_USERS(users, u_item); + + APPEND_REALLOC_INIT(buf, off, len); + APPEND_REALLOC(buf, off, len, "ok."); + INIT_MARKERSUMMARY(&ms_look); + ms_look.data = (void *)(&markersummary); + rows = 0; + K_RLOCK(workmarkers_free); + wm_item = last_in_ktree(workmarkers_workinfoid_root, wm_ctx); + DATA_WORKMARKERS_NULL(wm, wm_item); + /* TODO: allow to see details of a single payoutid + * if it has multiple items (percent payout user) */ + while (rows < 98 && wm_item) { + if (CURRENT(&(wm->expirydate)) && WMPROCESSED(wm->status)) { + K_RUNLOCK(workmarkers_free); + + bzero(&ms_add, sizeof(ms_add)); + + markersummary.markerid = wm->markerid; + markersummary.userid = users->userid; + markersummary.workername = EMPTY; + K_RLOCK(markersummary_free); + ms_item = find_after_in_ktree(markersummary_root, &ms_look, + cmp_markersummary, ms_ctx); + DATA_MARKERSUMMARY_NULL(ms, ms_item); + while (ms_item && ms->markerid == wm->markerid && + ms->userid == users->userid) { + ms_add.diffacc += ms->diffacc; + ms_add.diffrej += ms->diffrej; + ms_add.shareacc += ms->shareacc; + ms_add.sharerej += ms->sharerej; + + ms_item = next_in_ktree(ms_ctx); + DATA_MARKERSUMMARY_NULL(ms, ms_item); + } + K_RUNLOCK(markersummary_free); + + if (marker_end.tv_sec == 0L) { + wi_item = next_workinfo(wm->workinfoidend, NULL); + if (!wi_item) { + /* There's no workinfo after this shift + * Unexpected ... estimate last wid+30s */ + wi_item = find_workinfo(wm->workinfoidend, NULL); + if (!wi_item) { + // Nothing is currently locked + LOGERR("%s() workmarker %"PRId64"/%s." + " missing widend %"PRId64, + __func__, wm->markerid, + wm->description, + wm->workinfoidend); + snprintf(reply, siz, "data error 1"); + return strdup(reply); + } + DATA_WORKINFO(wi, wi_item); + copy_tv(&marker_end, &(wi->createdate)); + marker_end.tv_sec += 30; + } else { + DATA_WORKINFO(wi, wi_item); + copy_tv(&marker_end, &(wi->createdate)); + } + } + + wi_item = find_workinfo(wm->workinfoidstart, NULL); + if (!wi_item) { + // Nothing is currently locked + LOGERR("%s() workmarker %"PRId64"/%s. missing " + "widstart %"PRId64, + __func__, wm->markerid, wm->description, + wm->workinfoidstart); + snprintf(reply, siz, "data error 2"); + return strdup(reply); + } + DATA_WORKINFO(wi, wi_item); + + bigint_to_buf(wm->markerid, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "markerid:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + str_to_buf(wm->description, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "shift:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + ftv_to_buf(&(wi->createdate), reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "start:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + ftv_to_buf(&marker_end, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "end:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + double_to_buf(ms_add.diffacc, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "diffacc:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + double_to_buf(ms_add.diffrej, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "diffrej:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + double_to_buf(ms_add.shareacc, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "shareacc:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + double_to_buf(ms_add.sharerej, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "sharerej:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + rows++; + + // Setup for next shift + copy_tv(&marker_end, &(wi->createdate)); + + K_RLOCK(workmarkers_free); + } + wm_item = prev_in_ktree(wm_ctx); + DATA_WORKMARKERS_NULL(wm, wm_item); + } + K_RUNLOCK(workmarkers_free); + + snprintf(tmp, sizeof(tmp), "rows=%d%cflds=%s%c", + rows, FLDSEP, + "markerid,shift,start,end,diffacc,diffrej,shareacc,sharerej", + FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + snprintf(tmp, sizeof(tmp), "arn=%s%carp=%s", "Shifts", FLDSEP, ""); + APPEND_REALLOC(buf, off, len, tmp); + + LOGDEBUG("%s.ok.%s", id, transfer_data(i_username)); + return buf; +} + static char *cmd_dsp(__maybe_unused PGconn *conn, __maybe_unused char *cmd, char *id, __maybe_unused tv_t *now, __maybe_unused char *by, __maybe_unused char *code, @@ -5049,6 +5219,7 @@ struct CMDS ckdb_cmds[] = { { CMD_PPLNS2, "pplns2", false, false, cmd_pplns2, ACCESS_SYSTEM ACCESS_WEB }, { CMD_PAYOUTS, "payouts", false, false, cmd_payouts, ACCESS_SYSTEM }, { CMD_MPAYOUTS, "mpayouts", false, false, cmd_mpayouts, ACCESS_SYSTEM ACCESS_WEB }, + { CMD_SHIFTS, "shifts", false, false, cmd_shifts, ACCESS_SYSTEM ACCESS_WEB }, { CMD_USERSTATUS,"userstatus", false, false, cmd_userstatus, ACCESS_SYSTEM ACCESS_WEB }, { CMD_MARKS, "marks", false, false, cmd_marks, ACCESS_SYSTEM }, { CMD_END, NULL, false, false, NULL, NULL } diff --git a/src/ckdb_data.c b/src/ckdb_data.c index 96649aa8..1cf72429 100644 --- a/src/ckdb_data.c +++ b/src/ckdb_data.c @@ -1569,6 +1569,34 @@ K_ITEM *find_workinfo(int64_t workinfoid, K_TREE_CTX *ctx) return item; } +K_ITEM *next_workinfo(int64_t workinfoid, K_TREE_CTX *ctx) +{ + WORKINFO workinfo, *wi; + K_TREE_CTX ctx0[1]; + K_ITEM look, *item; + + if (ctx == NULL) + ctx = ctx0; + + workinfo.workinfoid = workinfoid; + workinfo.expirydate.tv_sec = default_expiry.tv_sec; + workinfo.expirydate.tv_usec = default_expiry.tv_usec; + + INIT_WORKINFO(&look); + look.data = (void *)(&workinfo); + K_RLOCK(workinfo_free); + item = find_after_in_ktree(workinfo_root, &look, cmp_workinfo, ctx); + if (item) { + DATA_WORKINFO(wi, item); + while (item && !CURRENT(&(wi->expirydate))) { + item = next_in_ktree(ctx); + DATA_WORKINFO_NULL(wi, item); + } + } + K_RUNLOCK(workinfo_free); + return item; +} + bool workinfo_age(PGconn *conn, int64_t workinfoid, char *poolinstance, char *by, char *code, char *inet, tv_t *cd, tv_t *ss_first, tv_t *ss_last, int64_t *ss_count,