// Update retrieves BTB 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)
}
Example #2
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
}
Example #3
0
// Update retrieves any new stores on the bitbar subreddit.
func (r *Reddit) Update() error {
	conn := models.CloneConnection()
	defer conn.Close()

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

	return savePosts(bitbarPosts, conn)
}
Example #4
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
}
Example #5
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)
	})
}
Example #6
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?")
	})
}
Example #7
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)
		})
	})
}
Example #8
0
// Update retrieves BTB 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
	}

	blockReward, err := getBlockReward()
	if err != nil {
		return err
	}

	conn := models.CloneConnection()
	defer conn.Close()

	network := &models.Network{
		HashRate:          hashRate,
		Difficulty:        diff,
		Mined:             mined,
		BlockCount:        blockCount,
		LatestBlockReward: blockReward,
		GeneratedAt:       time.Now().UTC(),
	}
	return network.Insert(conn)
}
Example #9
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
		redditBitBar, err := models.GetLatestPosts(conn, "/r/bitbar", 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{}{
			"redditBitBar":   redditBitBar,
			"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 4001")
	http.ListenAndServe(":4001", m)

	return nil
}
Example #10
0
// IndexAction is the function invoked by the index command.
func IndexAction() error {
	conn := models.CloneConnection()
	defer conn.Close()
	return models.Index(conn)
}