Пример #1
0
// Update retrieves VTC 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)
}
Пример #2
0
// Update retrieves VTC 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)
}
Пример #3
0
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
}
Пример #4
0
func getNewRedditPosts(feedUrl, source string) ([]*models.Post, error) {
	conn := models.CloneConnection()
	defer conn.Close()

	// get the feed
	feed, err := rss.Fetch(feedUrl)
	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:      source,
				Url:         item.Link,
				UniqueId:    item.ID,
				PublishedAt: item.Date,
			}

			posts = append(posts, post)
		}
	}

	return posts, nil
}
Пример #5
0
// Update retrieves any new stores on the vertcoin subreddit.
func (r *Reddit) Update() error {
	conn := models.CloneConnection()
	defer conn.Close()

	vertcoinPosts, err := getNewRedditPosts("http://www.reddit.com/r/vertcoin/.rss", "/r/vertcoin")
	if err != nil {
		return err
	}

	if err := savePosts(vertcoinPosts, conn); err != nil {
		return err
	}

	vertcoinMiningPosts, err := getNewRedditPosts("http://www.reddit.com/r/vertcoinmining/.rss", "/r/vertcoinmining")
	if err != nil {
		return err
	}

	if err := savePosts(vertcoinMiningPosts, conn); err != nil {
		return err
	}

	vertmarketPosts, err := getNewRedditPosts("http://www.reddit.com/r/vertmarket/.rss", "/r/vertmarket")
	if err != nil {
		return err
	}

	return savePosts(vertmarketPosts, conn)
}
Пример #6
0
// 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
}
Пример #7
0
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
}
Пример #8
0
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)
	})
}
Пример #9
0
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?")
	})
}
Пример #10
0
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)
		})
	})
}
Пример #11
0
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)
	}

	homeWriter := func(useBtc bool, 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 ""
		}
		allAverages, err := addLatestPricesToAverages(conn, averages)
		if err != nil {
			webError(err, res)
			return ""
		}

		var graphAverages, graphValueType string
		if useBtc {
			graphValueType = "BTC"
			graphAverages = parseAverages(allAverages, true)
		} else {
			graphValueType = "USD"
			graphAverages = parseAverages(allAverages, false)
		}

		// get the forum posts
		forum, err := models.GetLatestPosts(conn, "forum", 8)
		if err != nil {
			webError(err, res)
			return ""
		}

		// /r/vertcoin posts
		redditVertcoin, err := models.GetLatestPosts(conn, "/r/vertcoin", 8)
		if err != nil {
			webError(err, res)
			return ""
		}

		// /r/vertmarket posts
		redditVertmarket, err := models.GetLatestPosts(conn, "/r/vertmarket", 8)
		if err != nil {
			webError(err, res)
			return ""
		}

		// /r/vertmining posts
		redditVertcoinMining, err := models.GetLatestPosts(conn, "/r/vertcoinmining", 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{}{
			"redditVertcoin":       redditVertcoin,
			"redditVertmarket":     redditVertmarket,
			"redditVertcoinMining": redditVertcoinMining,
			"forum":                forum,
			"averages":             graphAverages,
			"graphValueType":       graphValueType,
			"showBtcLink":          !useBtc,
			"showUsdLink":          useBtc,
		}

		return mainView.Render(generateTplVars(price, network), valueMap)
	}

	m.Get("/", func(res http.ResponseWriter) string {
		return homeWriter(false, res)
	})

	m.Get("/:graphValue", func(params martini.Params, res http.ResponseWriter) string {
		var useBtc bool
		if params["graphValue"] == "usd" {
			useBtc = false
		} else {
			useBtc = true
		}

		return homeWriter(useBtc, res)
	})

	// 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(errors.New("Error getting latest price"), 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(errors.New("Error getting latest network snapshot"), res)
			return ""
		}

		if network.GeneratedAt.Unix() < twoHoursAgo {
			webError(errors.New("The latest network snapshot is old"), res)
			return ""
		}

		return "ok"
	})

	log.Printf("listening on port 4000")
	http.ListenAndServe(":4000", m)

	return nil
}
Пример #12
0
// IndexAction is the function invoked by the index command.
func IndexAction() error {
	conn := models.CloneConnection()
	defer conn.Close()
	return models.Index(conn)
}