allow stats to be returned from chat requests, and chats to be returned from submitting work

This commit is contained in:
cryptonote-social 2021-01-10 18:48:39 -08:00
parent 02a96cc890
commit 7be039d4f9
4 changed files with 71 additions and 32 deletions

View File

@ -82,22 +82,24 @@ func ChatSent(id int64) {
}
}
func ChatsReceived(chats []client.ChatResult, chatToken int64, fetchedToken int64) {
if len(chats) == 0 && chatToken == fetchedToken {
// ChatsReceived should be called by whenever the server returns a GetChatsResult. tokenSent should
// be set to the value of NextToken that was used in the request to the server that produced the
// GetChatsResult response.
func ChatsReceived(cr *client.GetChatsResult, tokenSent int64) {
if len(cr.Chats) == 0 && cr.NextToken == tokenSent {
return
}
mutex.Lock()
defer mutex.Unlock()
if nextToken != fetchedToken {
if nextToken != tokenSent {
// Another chat request must have succeeded before this one.
crylog.Warn("chats updated since this fetch, discarding:", chats)
crylog.Warn("chats updated since this fetch, discarding:", cr.Chats)
return
}
//crylog.Info("New chats received:", len(chats), chatToken, fetchedToken)
for i := range chats {
receivedQueue = append(receivedQueue, &chats[i])
for i := range cr.Chats {
receivedQueue = append(receivedQueue, &cr.Chats[i])
}
nextToken = chatToken
nextToken = cr.NextToken
}
func HasChats() bool {

View File

@ -514,7 +514,7 @@ func RequestRecentStatsUpdate() {
// dispatch loop inactive so there are no stats to update
return
}
go pokeJobDispatcher(UPDATE_STATS_POKE) // own gorouting so as not to block
go pokeJobDispatcher(UPDATE_STATS_POKE) // spawn goroutine so as not to block
}
func GetMiningState() *GetMiningStateResponse {
@ -636,8 +636,8 @@ func printStats(isMining bool) {
func GetChats() {
nt := chat.NextToken()
//crylog.Info("Getting chats:", nt)
resp, err := cl.GetChats(nt)
// we also request stats to be returned if they are more than a minute stale
resp, err := cl.GetChats(nt, (stats.SecondsOld() >= 60))
if err != nil {
crylog.Error("Failed to retrieve chats:", nt, err)
return
@ -649,7 +649,11 @@ func GetChats() {
cl.Close()
return
}
chat.ChatsReceived(cr.Chats, cr.NextToken, nt)
chat.ChatsReceived(cr, nt)
if cr.StatsResult != nil {
crylog.Info("Got stats:", cr.StatsResult)
stats.RefreshPoolStats2(cr.StatsResult)
}
}
func goMine(job client.MultiClientJob, thread int) {
@ -685,7 +689,11 @@ func goMine(job client.MultiClientJob, thread int) {
}
chats := chat.GetChatsToSend(int64(diffTarget))
//crylog.Info("sending chatmsgs:", chats)
resp, err := cl.SubmitWork(fnonce, jobid, chats)
nt := chat.NextToken()
// Note there's a rare potential bug here if nt == 0, since a 0 token for this RPC
// indicates "don't fetch chats" for backwards compatibility with older clients. Should
// this case even occur though, it will be resolved by the chat polling loop anyway.
resp, err := cl.SubmitWork(fnonce, jobid, chats, nt)
if err != nil {
crylog.Warn("Submit work client failure:", jobid, err)
cl.Close()
@ -713,13 +721,16 @@ func goMine(job client.MultiClientJob, thread int) {
return
}
if swr.PoolMargin > 0.0 {
stats.RefreshPoolStats2(swr)
tmp := &swr.StatsResult
stats.RefreshPoolStats2(tmp)
} else {
// This shouldn't ever happen if the server is behaving appropriately.
crylog.Warn("Didn't get pool stats in response:", resp.Result)
updatePoolStats(true)
}
if resp.ChatToken != chat.NextToken() {
go GetChats()
if swr.ChatsResult != nil {
crylog.Info("Got chats:", swr.ChatsResult)
chat.ChatsReceived(swr.ChatsResult, nt)
}
}(fnonce, job.JobID)
}

View File

@ -55,6 +55,19 @@ func Init() {
}
}
func SecondsOld() int {
mutex.Lock()
defer mutex.Unlock()
return secondsOld()
}
func secondsOld() int {
if lastPoolUpdateTime.IsZero() {
return -1
}
return int(time.Now().Sub(lastPoolUpdateTime).Seconds())
}
// Call whenever we're at at a point where recent hashrate calculation would be accurate,
// e.g. after all worker threads have been tallied.
func RecentStatsNowAccurate() {
@ -154,15 +167,11 @@ func GetSnapshot(isMining bool) (s *Snapshot, secondsSinceReset float64, seconds
r.Accumulated = accumulated
r.TimeToReward = timeToReward
}
if lastPoolUpdateTime.IsZero() {
r.SecondsOld = -1.0
} else {
r.SecondsOld = int(time.Now().Sub(lastPoolUpdateTime).Seconds())
}
r.SecondsOld = secondsOld()
return r, time.Now().Sub(recentStatsResetTime).Seconds(), elapsedRecent
}
func RefreshPoolStats2(swr *client.SubmitWorkResult) {
func RefreshPoolStats2(swr *client.StatsResult) {
diff := float64(swr.NetworkDifficulty)
hr := float64(swr.PPROPHashrate)
var ttreward string

View File

@ -63,9 +63,7 @@ type MultiClientJob struct {
ConnNonce uint32 `json:"nonce"`
}
type SubmitWorkResult struct {
Status string `json:"status"`
type StatsResult struct {
Progress float64 // progress of this user
LifetimeHashes int64 // hashes from this user over its lifetime
Paid float64 // Total crypto paid to this user over its lifetime.
@ -85,6 +83,16 @@ type SubmitWorkResult struct {
PoolFee float64
}
type SubmitWorkResult struct {
Status string `json:"status"`
StatsResult
// ChatsResult is for returning new chats in the response, but only if explicitly requested by
// setting a non-zero chat_token in the request. Will be nil if chats were not requested or if
// there are no new chats.
ChatsResult *GetChatsResult
}
type ChatResult struct {
Username string // user sending the chat
Message string // the chat message
@ -95,6 +103,11 @@ type ChatResult struct {
type GetChatsResult struct {
Chats []ChatResult
NextToken int64
// StatsResult is for also returning updated stats, but only if explicitly requested by setting
// update_stats to true in the request. This can be used to avoid having to make another round
// trip to also update stats.
StatsResult *StatsResult
}
type Response struct {
@ -293,7 +306,8 @@ func (cl *Client) submitRequest(submitRequest interface{}, expectedResponseID ui
return response, nil
}
func (cl *Client) GetChats(chatToken int64) (*Response, error) {
// If updateStats is true, then get_chats will also return the lastest user stats.
func (cl *Client) GetChats(chatToken int64, updateStats bool) (*Response, error) {
chatRequest := &struct {
ID uint64 `json:"id"`
Method string `json:"method"`
@ -302,8 +316,9 @@ func (cl *Client) GetChats(chatToken int64) (*Response, error) {
ID: GET_CHATS_JSON_ID,
Method: "get_chats",
Params: &struct {
ChatToken int64 `json:"chat_token"`
}{chatToken},
ChatToken int64 `json:"chat_token"`
UpdateStats bool `json:"update_stats"` // if true, then return update stats results too
}{chatToken, updateStats},
}
return cl.submitRequest(chatRequest, GET_CHATS_JSON_ID)
@ -314,8 +329,9 @@ type ChatToSend struct {
Message string
}
// if error is returned then client will be closed and put in not-alive state
func (cl *Client) SubmitWork(nonce string, jobid string, chats []ChatToSend) (*Response, error) {
// If chatToken is non-zero then submit_work will return new chats, if there are any. If error is
// returned by this method, then client will be closed and put in not-alive state.
func (cl *Client) SubmitWork(nonce string, jobid string, chats []ChatToSend, chatToken int64) (*Response, error) {
submitRequest := &struct {
ID uint64 `json:"id"`
Method string `json:"method"`
@ -329,8 +345,9 @@ func (cl *Client) SubmitWork(nonce string, jobid string, chats []ChatToSend) (*R
Nonce string `json:"nonce"`
Result string `json:"result"`
Chats []ChatToSend `json:"chats"`
}{"696969", jobid, nonce, "", chats},
Chats []ChatToSend `json:"chats"`
ChatToken int64 `json:"chat_token"` // if non-zero, then return any new chats too
}{"696969", jobid, nonce, "", chats, chatToken},
}
return cl.submitRequest(submitRequest, SUBMIT_WORK_JSON_ID)
}