// Update retrieves WDC netork information from a blockchain api. func (n *Network) Update() error { hashRate, err := getHashRate() if err != nil { return err } diff, err := getDifficulty() if err != nil { return err } mined, err := getMined() if err != nil { return err } blockCount, err := getBlockCount() if err != nil { return err } conn := models.CloneConnection() defer conn.Close() network := &models.Network{ HashRate: hashRate, Difficulty: diff, Mined: mined, BlockCount: blockCount, GeneratedAt: time.Now().UTC(), } return network.Insert(conn) }
func (f *Forum) Update() error { conn := models.CloneConnection() defer conn.Close() discussionPosts, err := getNewTopicsFromForum("3-worldcoin-discussion") if err != nil { return err } for _, post := range discussionPosts { if err := post.Insert(conn); err != nil { return err } } promotionPosts, err := getNewTopicsFromForum("4-promotion-of-worldcoin") if err != nil { return err } for _, post := range promotionPosts { if err := post.Insert(conn); err != nil { return err } } return nil }
func getNewRedditPosts() ([]*models.Post, error) { conn := models.CloneConnection() defer conn.Close() // get the feed feed, err := rss.Fetch(subredditUrl) if err != nil { return []*models.Post{}, err } // iterate the feed and save the new items posts := make([]*models.Post, 0) for _, item := range feed.Items { exists, err := models.PostExists(conn, item.ID) if err != nil { return []*models.Post{}, err } if !exists { post := &models.Post{ Title: item.Title, Source: "reddit", Url: item.Link, UniqueId: item.ID, PublishedAt: item.Date, } posts = append(posts, post) } } return posts, nil }
// Update retrieves WDC buy prices in both USD and BTC and saves // the prices to the database. func (c *CoinPrice) Update() error { usd, err := coinbaseQuote() if err != nil { return err } cryptsyBtc, err := cryptsyQuote() if err != nil { return err } conn := models.CloneConnection() defer conn.Close() price := &models.Price{ UsdPerBtc: usd, Cryptsy: &models.ExchangePrice{Btc: cryptsyBtc, Usd: usd * cryptsyBtc}, GeneratedAt: time.Now().UTC().Truncate(time.Minute), } if err := price.SetPercentChange(conn); err != nil { return err } return price.Insert(conn) }
// getNewTopicsFromForum takes in a forum url name and returns up to 5 of the latest topics not saved in // the database. func getNewTopicsFromForum(forumSuffix string) ([]*models.Post, error) { url := forumBaseUrl if strings.Contains(forumBaseUrl, "%s") { url = fmt.Sprintf(forumBaseUrl, forumSuffix) } conn := models.CloneConnection() defer conn.Close() doc, err := goquery.NewDocument(url) if err != nil { return []*models.Post{}, err } // find all of the topics posts := make([]*models.Post, 0) found := 0 doc.Find("tr[itemtype='http://schema.org/Article']").Each(func(i int, s *goquery.Selection) { // we don't want any that are pinned pinned := s.Find("span:contains('Pinned')") if pinned.Size() == 0 { found++ if found < 5 { title := s.Find("span[itemprop='name']").Text() url, _ := s.Find("a[itemprop='url']").Attr("href") // stop now if we have already saved the topic exists, err := models.PostExists(conn, url) if err != nil || exists { return } publishedAt, err := getDateFromPost(url) if err != nil { return } post := &models.Post{ Title: title, Source: "forum", Url: url, UniqueId: url, PublishedAt: publishedAt, } posts = append(posts, post) } } }) return posts, nil }
func PricingRollupAction() error { conn := models.CloneConnection() defer conn.Close() // get all prices from the last 10 minutes baseTime := time.Now().UTC().Truncate(time.Minute * 10) beginning := baseTime.Add(time.Minute * -10) end := baseTime.Add(time.Minute*-1 + time.Second*59) _, err := models.GenerateAverage(conn, beginning, end) return err }
func (s *postSuite) TestUpdatingReddit(c *C) { conn := models.CloneConnection() defer conn.Close() replaceUrl(s.redditServer2.URL, &subredditUrl, func() { r := &Reddit{} r.Update() var results []*models.Post conn.DB.C("posts").Find(bson.M{}).All(&results) c.Check(len(results), Equals, 2) }) }
func (s *postSuite) TestGettingReditPosts(c *C) { conn := models.CloneConnection() defer conn.Close() replaceUrl(s.redditServer1.URL, &subredditUrl, func() { p1 := &models.Post{Title: "test title", Url: "test url", Source: "reddit", UniqueId: "http://www.reddit.com/r/worldcoin/comments/1uj486/whats_a_better_name_than_scharmbeck/"} p1.Insert(conn) posts, _ := getNewRedditPosts() c.Check(len(posts), Equals, 1) c.Check(posts[0].Title, Equals, "two worldcoins?") }) }
func (s *coinPriceSuite) TestSavingPrices(c *C) { replaceUrl(s.coinBaseServer.URL, &coinbaseUrl, func() { replaceUrl(s.cryptsyServer.URL, &cryptsyUrl, func() { conn := models.CloneConnection() defer conn.Close() coinPrice := &CoinPrice{} coinPrice.Update() var saved models.Price conn.DB.C("prices").Find(bson.M{}).One(&saved) c.Check(saved.UsdPerBtc, Equals, 676.58046) c.Check(saved.Cryptsy.Btc, Equals, 0.00053275) }) }) }
// Update retrieves any new stores on the worldcoin subreddit. func (r *Reddit) Update() error { conn := models.CloneConnection() defer conn.Close() posts, err := getNewRedditPosts() if err != nil { return err } for _, post := range posts { if err := post.Insert(conn); err != nil { return err } } return nil }
func ServeAction() error { m := martini.Classic() m.Use(martini.Static("resources/public")) mainView, err := mustache.ParseFile("resources/views/main.html.mustache") if err != nil { panic(err) } m.Get("/", func(res http.ResponseWriter) string { conn := models.CloneConnection() defer conn.Close() // get the latest pricing data price, err := models.GetLatestPrice(conn) if err != nil { webError(err, res) return "" } // get data for the graph averages, err := models.GetAverages(conn, 24) if err != nil { webError(err, res) return "" } parsedAverages := parseAverages(averages) // get the forum posts forum, err := models.GetLatestPosts(conn, "forum", 8) if err != nil { webError(err, res) return "" } // get reddit posts reddit, err := models.GetLatestPosts(conn, "reddit", 8) if err != nil { webError(err, res) return "" } // get the mining information network, err := models.GetLatestNetworkSnapshot(conn) if err != nil { webError(err, res) return "" } // generate the HTML valueMap := map[string]interface{}{"reddit": reddit, "forum": forum, "averages": parsedAverages} return mainView.Render(generateTplVars(price, network), valueMap) }) // returns basic information about the state of the service. If any hardcoded checks fail // the message is returned with a 500 status. We can then use pingdom or another service // to alert when data integrity may be off. m.Get("/health", func(res http.ResponseWriter) string { conn := models.CloneConnection() defer conn.Close() twoHoursAgo := time.Now().Add(time.Hour * -2).Unix() // make sure the price has been updated in the last 2 hours price, err := models.GetLatestPrice(conn) if err != nil { webError(err, res) return "" } if price.GeneratedAt.Unix() < twoHoursAgo { webError(errors.New("The latest price is old"), res) return "" } // make sure the network has been updated in the last two hours network, err := models.GetLatestNetworkSnapshot(conn) if err != nil { webError(err, res) return "" } if network.GeneratedAt.Unix() < twoHoursAgo { webError(errors.New("The latest network snapshot is old"), res) return "" } return "ok" }) m.Run() return nil }
// IndexAction is the function invoked by the index command. func IndexAction() error { conn := models.CloneConnection() defer conn.Close() return models.Index(conn) }