bid: add check routine

This commit is contained in:
Chris Sexton 2019-07-15 14:57:23 -04:00
parent 04239ec807
commit dd0f9efeae
2 changed files with 119 additions and 14 deletions

View File

@ -11,14 +11,13 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
"time"
) )
type Webshit struct { type Webshit struct {
db *sqlx.DB db *sqlx.DB
} }
type Weekly []string
type Story struct { type Story struct {
Title string Title string
URL string URL string
@ -32,6 +31,12 @@ type Bid struct {
Bid int Bid int
} }
type WeeklyResult struct {
User string
Won int
Lost int
}
func New(db *sqlx.DB) *Webshit { func New(db *sqlx.DB) *Webshit {
w := &Webshit{db} w := &Webshit{db}
w.setup() w.setup()
@ -45,7 +50,8 @@ func (w *Webshit) setup() {
user string, user string,
title string, title string,
url string, url string,
bid integer bid integer,
created integer
)`); err != nil { )`); err != nil {
log.Fatal().Err(err) log.Fatal().Err(err)
} }
@ -58,6 +64,75 @@ func (w *Webshit) setup() {
} }
} }
func (w *Webshit) Check() (map[string]WeeklyResult, error) {
stories, published, err := w.GetWeekly()
if err != nil {
return nil, err
}
var bids []Bid
if err = w.db.Get(&bids, `select * from webshit_bids where created < ?`,
published.Unix()); err != nil {
return nil, err
}
// Assuming no bids earlier than the weekly means there hasn't been a new weekly
if len(bids) == 0 {
return nil, nil
}
storyMap := map[string]Story{}
for _, s := range stories {
storyMap[s.Title] = s
}
wr := w.checkBids(bids, storyMap)
// Update all balance scores in a tx
if err := w.updateScores(wr); err != nil {
return nil, err
}
// Delete all those bids
if _, err = w.db.Exec(`delete from webshit_bids where created < ?`,
published.Unix()); err != nil {
return nil, err
}
// Set all balances to 100
if _, err = w.db.Exec(`update webshit_balances set balance=100`); err != nil {
return nil, err
}
return wr, nil
}
func (w *Webshit) checkBids(bids []Bid, storyMap map[string]Story) map[string]WeeklyResult {
wr := map[string]WeeklyResult{}
for _, b := range bids {
win, loss := 0, 0
if s, ok := storyMap[b.Title]; ok {
log.Info().Interface("story", s).Msg("won bid")
win = b.Bid
} else {
log.Info().Interface("story", s).Msg("lost bid")
loss = b.Bid
}
if res, ok := wr[b.User]; !ok {
wr[b.User] = WeeklyResult{
User: b.User,
Won: win,
Lost: loss,
}
} else {
res.Won = win
res.Lost = loss
wr[b.User] = res
}
}
return wr
}
// GetHeadlines will return the current possible news headlines for bidding // GetHeadlines will return the current possible news headlines for bidding
func (w *Webshit) GetHeadlines() ([]Story, error) { func (w *Webshit) GetHeadlines() ([]Story, error) {
news := hacknews.Initializer{Story: "topstories", NbPosts: 10} news := hacknews.Initializer{Story: "topstories", NbPosts: 10}
@ -80,28 +155,34 @@ func (w *Webshit) GetHeadlines() ([]Story, error) {
} }
// GetWeekly will return the headlines in the last webshit weekly report // GetWeekly will return the headlines in the last webshit weekly report
func (w *Webshit) GetWeekly() (Weekly, error) { func (w *Webshit) GetWeekly() ([]Story, *time.Time, error) {
fp := gofeed.NewParser() fp := gofeed.NewParser()
feed, err := fp.ParseURL("http://n-gate.com/hackernews/index.rss") feed, err := fp.ParseURL("http://n-gate.com/hackernews/index.rss")
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
if len(feed.Items) <= 0 { if len(feed.Items) <= 0 {
return nil, fmt.Errorf("no webshit weekly found") return nil, nil, fmt.Errorf("no webshit weekly found")
} }
published := feed.PublishedParsed
buf := bytes.NewBufferString(feed.Items[0].Description) buf := bytes.NewBufferString(feed.Items[0].Description)
doc, err := goquery.NewDocumentFromReader(buf) doc, err := goquery.NewDocumentFromReader(buf)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
var items []string var items []Story
doc.Find(".storylink").Each(func(i int, s *goquery.Selection) { doc.Find(".storylink").Each(func(i int, s *goquery.Selection) {
items = append(items, s.Find("a").Text()) story := Story{
Title: s.Find("a").Text(),
URL: s.Find("a").AttrOr("src", ""),
}
items = append(items, story)
}) })
return items, nil return items, published, nil
} }
// GetBalances returns the current balance for all known users // GetBalances returns the current balance for all known users
@ -127,9 +208,20 @@ func (w *Webshit) Bid(user string, amount int, URL string) error {
return err return err
} }
// Need a transaction here to deduct from the users balance (or create it) tx := w.db.MustBegin()
_, err = w.db.Exec(`insert into webshit_bids (user,title,url,bid) values (?,?,?,?)`, _, err = tx.Exec(`insert into webshit_bids (user,title,url,bid,created) values (?,?,?,?,?)`,
user, story.Title, story.URL, amount) user, story.Title, story.URL, amount, time.Now().Unix())
if err != nil {
tx.Rollback()
return err
}
_, err = tx.Exec(`update webshit_balances set balance=? where user=?`,
bal-amount, user)
if err != nil {
tx.Rollback()
return err
}
tx.Commit()
return err return err
} }
@ -166,3 +258,16 @@ func (w *Webshit) getStoryByURL(URL string) (Story, error) {
URL: URL, URL: URL,
}, nil }, nil
} }
func (w *Webshit) updateScores(results map[string]WeeklyResult) error {
tx := w.db.MustBegin()
for _, res := range results {
if _, err := tx.Exec(`update webshit_balances set score=score+? where user=?`,
res.Won-res.Lost, res.User); err != nil {
tx.Rollback()
return err
}
}
err := tx.Commit()
return err
}

View File

@ -17,7 +17,7 @@ func make(t *testing.T) *Webshit {
func TestWebshit_GetWeekly(t *testing.T) { func TestWebshit_GetWeekly(t *testing.T) {
w := make(t) w := make(t)
weekly, err := w.GetWeekly() weekly, _, err := w.GetWeekly()
assert.Nil(t, err) assert.Nil(t, err)
assert.NotEmpty(t, weekly) assert.NotEmpty(t, weekly)
} }