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) { // ChatsReceived should be called by whenever the server returns a GetChatsResult. tokenSent should
if len(chats) == 0 && chatToken == fetchedToken { // 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 return
} }
mutex.Lock() mutex.Lock()
defer mutex.Unlock() defer mutex.Unlock()
if nextToken != fetchedToken { if nextToken != tokenSent {
// Another chat request must have succeeded before this one. // 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 return
} }
//crylog.Info("New chats received:", len(chats), chatToken, fetchedToken) for i := range cr.Chats {
for i := range chats { receivedQueue = append(receivedQueue, &cr.Chats[i])
receivedQueue = append(receivedQueue, &chats[i])
} }
nextToken = chatToken nextToken = cr.NextToken
} }
func HasChats() bool { func HasChats() bool {

View File

@ -514,7 +514,7 @@ func RequestRecentStatsUpdate() {
// dispatch loop inactive so there are no stats to update // dispatch loop inactive so there are no stats to update
return 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 { func GetMiningState() *GetMiningStateResponse {
@ -636,8 +636,8 @@ func printStats(isMining bool) {
func GetChats() { func GetChats() {
nt := chat.NextToken() nt := chat.NextToken()
//crylog.Info("Getting chats:", nt) // we also request stats to be returned if they are more than a minute stale
resp, err := cl.GetChats(nt) resp, err := cl.GetChats(nt, (stats.SecondsOld() >= 60))
if err != nil { if err != nil {
crylog.Error("Failed to retrieve chats:", nt, err) crylog.Error("Failed to retrieve chats:", nt, err)
return return
@ -649,7 +649,11 @@ func GetChats() {
cl.Close() cl.Close()
return 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) { func goMine(job client.MultiClientJob, thread int) {
@ -685,7 +689,11 @@ func goMine(job client.MultiClientJob, thread int) {
} }
chats := chat.GetChatsToSend(int64(diffTarget)) chats := chat.GetChatsToSend(int64(diffTarget))
//crylog.Info("sending chatmsgs:", chats) //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 { if err != nil {
crylog.Warn("Submit work client failure:", jobid, err) crylog.Warn("Submit work client failure:", jobid, err)
cl.Close() cl.Close()
@ -713,13 +721,16 @@ func goMine(job client.MultiClientJob, thread int) {
return return
} }
if swr.PoolMargin > 0.0 { if swr.PoolMargin > 0.0 {
stats.RefreshPoolStats2(swr) tmp := &swr.StatsResult
stats.RefreshPoolStats2(tmp)
} else { } else {
// This shouldn't ever happen if the server is behaving appropriately.
crylog.Warn("Didn't get pool stats in response:", resp.Result) crylog.Warn("Didn't get pool stats in response:", resp.Result)
updatePoolStats(true) updatePoolStats(true)
} }
if resp.ChatToken != chat.NextToken() { if swr.ChatsResult != nil {
go GetChats() crylog.Info("Got chats:", swr.ChatsResult)
chat.ChatsReceived(swr.ChatsResult, nt)
} }
}(fnonce, job.JobID) }(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, // Call whenever we're at at a point where recent hashrate calculation would be accurate,
// e.g. after all worker threads have been tallied. // e.g. after all worker threads have been tallied.
func RecentStatsNowAccurate() { func RecentStatsNowAccurate() {
@ -154,15 +167,11 @@ func GetSnapshot(isMining bool) (s *Snapshot, secondsSinceReset float64, seconds
r.Accumulated = accumulated r.Accumulated = accumulated
r.TimeToReward = timeToReward r.TimeToReward = timeToReward
} }
if lastPoolUpdateTime.IsZero() { r.SecondsOld = secondsOld()
r.SecondsOld = -1.0
} else {
r.SecondsOld = int(time.Now().Sub(lastPoolUpdateTime).Seconds())
}
return r, time.Now().Sub(recentStatsResetTime).Seconds(), elapsedRecent return r, time.Now().Sub(recentStatsResetTime).Seconds(), elapsedRecent
} }
func RefreshPoolStats2(swr *client.SubmitWorkResult) { func RefreshPoolStats2(swr *client.StatsResult) {
diff := float64(swr.NetworkDifficulty) diff := float64(swr.NetworkDifficulty)
hr := float64(swr.PPROPHashrate) hr := float64(swr.PPROPHashrate)
var ttreward string var ttreward string

View File

@ -63,9 +63,7 @@ type MultiClientJob struct {
ConnNonce uint32 `json:"nonce"` ConnNonce uint32 `json:"nonce"`
} }
type SubmitWorkResult struct { type StatsResult struct {
Status string `json:"status"`
Progress float64 // progress of this user Progress float64 // progress of this user
LifetimeHashes int64 // hashes from this user over its lifetime LifetimeHashes int64 // hashes from this user over its lifetime
Paid float64 // Total crypto paid to 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 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 { type ChatResult struct {
Username string // user sending the chat Username string // user sending the chat
Message string // the chat message Message string // the chat message
@ -95,6 +103,11 @@ type ChatResult struct {
type GetChatsResult struct { type GetChatsResult struct {
Chats []ChatResult Chats []ChatResult
NextToken int64 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 { type Response struct {
@ -293,7 +306,8 @@ func (cl *Client) submitRequest(submitRequest interface{}, expectedResponseID ui
return response, nil 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 { chatRequest := &struct {
ID uint64 `json:"id"` ID uint64 `json:"id"`
Method string `json:"method"` Method string `json:"method"`
@ -302,8 +316,9 @@ func (cl *Client) GetChats(chatToken int64) (*Response, error) {
ID: GET_CHATS_JSON_ID, ID: GET_CHATS_JSON_ID,
Method: "get_chats", Method: "get_chats",
Params: &struct { Params: &struct {
ChatToken int64 `json:"chat_token"` ChatToken int64 `json:"chat_token"`
}{chatToken}, UpdateStats bool `json:"update_stats"` // if true, then return update stats results too
}{chatToken, updateStats},
} }
return cl.submitRequest(chatRequest, GET_CHATS_JSON_ID) return cl.submitRequest(chatRequest, GET_CHATS_JSON_ID)
@ -314,8 +329,9 @@ type ChatToSend struct {
Message string Message string
} }
// if error is returned then client will be closed and put in not-alive state // If chatToken is non-zero then submit_work will return new chats, if there are any. If error is
func (cl *Client) SubmitWork(nonce string, jobid string, chats []ChatToSend) (*Response, error) { // 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 { submitRequest := &struct {
ID uint64 `json:"id"` ID uint64 `json:"id"`
Method string `json:"method"` Method string `json:"method"`
@ -329,8 +345,9 @@ func (cl *Client) SubmitWork(nonce string, jobid string, chats []ChatToSend) (*R
Nonce string `json:"nonce"` Nonce string `json:"nonce"`
Result string `json:"result"` Result string `json:"result"`
Chats []ChatToSend `json:"chats"` Chats []ChatToSend `json:"chats"`
}{"696969", jobid, nonce, "", 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) return cl.submitRequest(submitRequest, SUBMIT_WORK_JSON_ID)
} }