// vi:ts=4:sts=4:sw=4:noet:tw=72
package modules
import (
"encoding/json"
"flag"
"fmt"
"html"
"io/ioutil"
"net/http"
"net/url"
"regexp"
"strings"
"time"
"git.dnix.de/an/flokatilib/util"
"git.dnix.de/an/xlog"
)
const (
API_URL = "https://robertsspaceindustries.com/api"
API_METHOD = "/stats/getCrowdfundStats"
QUERY_CIT_URL = "https://robertsspaceindustries.com/citizens/"
QUERY_ORG_URL = "https://robertsspaceindustries.com/orgs/"
RE_CIT_NAME = `
\s*
\s*(.*)\s*
\s*
`
RE_CIT_RECORD = `
\s*UEE Citizen Record\s*#(.*)`
RE_CIT_HANDLE = `
\s*Handle name\s*(.*)\s*
`
RE_CIT_ORG = `
(.*)`
RE_CIT_SID = `Spectrum Identification \(SID\)\s*
([A-Z0-9]*)`
RE_CIT_RANK = `Organization rank\s*
(.*)`
RE_ORG_NAME = `
(.*) ?/ ?`
RE_ORG_COUNT = `(.*) member`
RE_ORG_MODEL = `(.*)`
RE_ORG_FOCUS = `\s*- \s*\s*\s*
\s*- \s*\s*\s*
\s*
`
RE_ORG_COMM = `(.*)`
FANS_INT = 1000
FLEET_INT = 1000
FUNDS_INT = 50000
)
var (
fans = 0
fleet = 0
funds = 0
targetChannel = flag.String("sc_target_channel", "", "Default channel for stats output")
)
func init() {
MsgFuncs["sc"] = scHandleMessage
RunFuncs["sc"] = scScrapeLoop
}
func scHandleMessage(m *Message) {
tok := strings.Split(m.Text, " ")
if len(tok) < 1 {
return
}
switch tok[0] {
case "!scstats":
showScStats(m.Channel)
case "!sccit":
if len(tok) > 1 {
showCitizen(tok[1], m.Channel)
}
case "!scorg":
if len(tok) > 1 {
showOrganization(tok[1], m.Channel)
}
default:
}
}
func scScrapeLoop() {
for {
scScraper()
time.Sleep(1 * time.Minute)
}
}
func scScraper() {
var data interface{}
xlog.Info("Scraping SC stats")
resp, err := http.PostForm(API_URL+API_METHOD,
url.Values{"fans": {"true"}, "fleet": {"true"}, "funds": {"true"}})
if err != nil {
xlog.Info("Error: %v", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
xlog.Info("Error: %v", err)
return
}
err = json.Unmarshal(body, &data)
if err != nil {
xlog.Info("Error: %v", err)
return
}
stats := data.(map[string]interface{})["data"].(map[string]interface{})
//fmt.Println(stats["fans"].(type))
curFans := util.ToInt(stats["fans"])
curFleet := util.ToInt(stats["fleet"])
curFunds := util.ToInt(stats["funds"]) / 100
nextFans := ((fans / FANS_INT) * FANS_INT) + FANS_INT
nextFleet := ((fleet / FLEET_INT) * FLEET_INT) + FLEET_INT
nextFunds := ((funds / FUNDS_INT) * FUNDS_INT) + FUNDS_INT
if curFans >= nextFans {
SayCh <- *targetChannel + "\n[SC] Star Citizens: " + util.NumberToString(curFans, '.')
}
if curFleet >= nextFleet {
SayCh <- *targetChannel + "\n[SC] The UEE Fleet: " + util.NumberToString(curFleet, '.')
}
if curFunds >= nextFunds {
SayCh <- *targetChannel + "\n[SC] Funds raised: " + util.NumberToString(curFunds, '.')
}
fans = curFans
fleet = curFleet
funds = curFunds
}
func showScStats(channel string) {
SayCh <- channel + "\n**SC User and Funding Stats**"
SayCh <- fmt.Sprintf("%s\nFans: %s", channel, util.NumberToString(fans, '.'))
SayCh <- fmt.Sprintf("%s\nFleet: %s", channel, util.NumberToString(fleet, '.'))
SayCh <- fmt.Sprintf("%s*\nFunds: $ %s", channel, util.NumberToString(funds, '.'))
}
func showCitizen(handle, channel string) {
resp, err := http.Get(QUERY_CIT_URL + handle)
if err != nil {
xlog.Info("Error: %v", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
xlog.Info("Error: %v", err)
return
}
reName := regexp.MustCompile(RE_CIT_NAME)
reRecord := regexp.MustCompile(RE_CIT_RECORD)
reHandle := regexp.MustCompile(RE_CIT_HANDLE)
reOrg := regexp.MustCompile(RE_CIT_ORG)
reSid := regexp.MustCompile(RE_CIT_SID)
reRank := regexp.MustCompile(RE_CIT_RANK)
name := reName.FindStringSubmatch(string(body))
record := reRecord.FindStringSubmatch(string(body))
handle_ := reHandle.FindStringSubmatch(string(body))
org := reOrg.FindStringSubmatch(string(body))
sid := reSid.FindStringSubmatch(string(body))
rank := reRank.FindStringSubmatch(string(body))
if len(name) > 1 {
SayCh <- channel + "\n**Citizen Info**"
SayCh <- channel + "\nName: " + html.UnescapeString(string(name[1])) + " [" + string(handle_[1]) + "]"
SayCh <- channel + "\nURL: " + QUERY_CIT_URL + string(handle_[1])
SayCh <- channel + "\nUEE #: " + string(record[1])
if len(org) > 1 {
SayCh <- channel + "\nOrganization: " + html.UnescapeString(string(org[1])) + " [" + string(sid[1]) + "]"
SayCh <- channel + "\nRank: " + html.UnescapeString(string(rank[1]))
} else {
SayCh <- channel + "\nOrganization: "
}
} else {
SayCh <- channel + "\n***No Such Citizen***"
}
}
func showOrganization(handle, channel string) {
resp, err := http.Get(QUERY_ORG_URL + handle)
if err != nil {
xlog.Info("Error: %v", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
xlog.Info("Error: %v", err)
return
}
reName := regexp.MustCompile(RE_ORG_NAME)
reCount := regexp.MustCompile(RE_ORG_COUNT)
reModel := regexp.MustCompile(RE_ORG_MODEL)
reFocus := regexp.MustCompile(RE_ORG_FOCUS)
reComm := regexp.MustCompile(RE_ORG_COMM)
name := reName.FindStringSubmatch(string(body))
count := reCount.FindStringSubmatch(string(body))
model := reModel.FindStringSubmatch(string(body))
focus := reFocus.FindStringSubmatch(string(body))
comm := reComm.FindStringSubmatch(string(body))
if len(name) > 1 {
SayCh <- channel + "\n**Organization Info**"
SayCh <- channel + "\nName: " + string(name[1]) + " [" + strings.ToUpper(handle) + "]"
SayCh <- channel + "\nURL: " + QUERY_ORG_URL + strings.ToUpper(handle)
SayCh <- channel + "\nMembers: " + string(count[1])
SayCh <- channel + "\nModel: " + string(model[1])
SayCh <- channel + "\nCommitment: " + string(comm[1])
SayCh <- channel + "\nFocus: " + string(focus[1]) + ", " + string(focus[2])
} else {
SayCh <- channel + "\n***No Such Organization***"
}
}