M mux.go => mux.go +4 -2
@@ 18,7 18,7 @@ func init() {
// Register the build-in help command.
Router.Route("help", "Display this message.", Router.Help)
- Router.Route("fortune", "Display fortunes. Bonus files are (theo troll rsc bullshit terry rob).", Router.Fortunes)
+ Router.Route("fortune", "Display fortunes. Bonus files are (theo troll rsc terry rob ken).", Router.Fortunes)
Router.Route("add", "Subscribe to an RSS feed.", Router.Add)
@@ 44,7 44,9 @@ func init() {
Router.Route("whiskey", ":tumbler_glass:", Router.Whiskey)
- Router.Route("wine", ":wine_glass", Router.Wine)
+ Router.Route("wine", ":wine_glass:", Router.Wine)
Router.Route("remindme", "Set a reminder for a given time interval ([int][hmsd] [reminder]).", Router.RemindMe)
+
+ Router.Route("bullshit", "Print logical statements with sound grounding.", Router.Bullshit)
}
M x/mux/commits.go => x/mux/commits.go +70 -43
@@ 15,35 15,35 @@ import (
// Listen on the rss feed
func Listener() {
for {
- for p, _ := range Config.Feeds {
- //fmt.Print("Updating feed: ", Config.Feeds[p].Feed.Title, "\n")
+ for p, _ := range Feeds.Feeds {
+ //fmt.Print("Updating feed: ", Feeds.Feeds[p].Feed.Title, "\n")
// maybe only do at init step?
- str := Config.Feeds[p].Feed.UpdateURL
+ str := Feeds.Feeds[p].Feed.UpdateURL
feed, err := rss.Fetch(str)
if feed != nil {
- Config.Feeds[p].Feed = *feed
+ Feeds.Feeds[p].Feed = *feed
} else {
//fmt.Println("Got a nil pointer for feed in commits for ", str, " as ", err)
}
- //err := Config.Feeds[p].Feed.Update()
+ //err := Feeds.Feeds[p].Feed.Update()
if err != nil {
fmt.Println("Error in updating RSS feed, see: x/mux/commits.go")
fmt.Printf("%s\n\n", err)
} else {
additem := true
- for j, _ := range Config.Feeds[p].Recent {
- if Config.Feeds[p].Recent[j] == Config.Feeds[p].Feed.Items[0].Title {
- //fmt.Println("Checking Recent ", j, " against ", Config.Feeds[p].Feed.Items[0].Title)
+ for j, _ := range Feeds.Feeds[p].Recent {
+ if Feeds.Feeds[p].Recent[j] == Feeds.Feeds[p].Feed.Items[0].Title {
+ //fmt.Println("Checking Recent ", j, " against ", Feeds.Feeds[p].Feed.Items[0].Title)
additem = false
break
}
}
if additem {
// x y z → x y z 0 → y z 0
- fmt.Println("Updating: ", Config.Feeds[p].Feed.Title)
- Config.Feeds[p].Recent = append(Config.Feeds[p].Recent, Config.Feeds[p].Feed.Items[0].Title)
- Config.Feeds[p].Recent = Config.Feeds[p].Recent[1:]
+ fmt.Println("Updating: ", Feeds.Feeds[p].Feed.Title)
+ Feeds.Feeds[p].Recent = append(Feeds.Feeds[p].Recent, Feeds.Feeds[p].Feed.Items[0].Title)
+ Feeds.Feeds[p].Recent = Feeds.Feeds[p].Recent[1:]
Notify(p)
break
}
@@ 59,11 59,11 @@ func Listener() {
// Notify subscribed channels to subscribed feeds
func Notify(id int) {
resp := ".\n"
- resp += "**" + Config.Feeds[id].Feed.Title + ": **" + "\n"
- resp += Config.Feeds[id].Feed.Items[0].Date.String() + "\n\n"
+ resp += "**" + Feeds.Feeds[id].Feed.Title + ": **" + "\n"
+ resp += Feeds.Feeds[id].Feed.Items[0].Date.String() + "\n\n"
// If a 9front feed, extract the user ☺
- if strings.Contains(Config.Feeds[id].Feed.Items[0].Link, "http://code.9front.org/hg/") {
- lines := strings.Split(Config.Feeds[id].Feed.Items[0].Summary, "\n")
+ if strings.Contains(Feeds.Feeds[id].Feed.Items[0].Link, "http://code.9front.org/hg/") {
+ lines := strings.Split(Feeds.Feeds[id].Feed.Items[0].Summary, "\n")
for i, v := range lines {
if strings.Contains(v, "<th style=\"text-align:left;vertical-align:top;\">user</th>") {
line := html.UnescapeString((lines[i+1])[6:len(lines[i+1])-5])
@@ 72,23 72,23 @@ func Notify(id int) {
}
}
}
- resp += "`" + Config.Feeds[id].Feed.Items[0].Title + "`" + "\n"
- resp += "\n" + Config.Feeds[id].Feed.Items[0].Link + "\n"
- Config.Feeds[id].Feed.Items[0].Read = true
+ resp += "`" + Feeds.Feeds[id].Feed.Items[0].Title + "`" + "\n"
+ resp += "\n" + Feeds.Feeds[id].Feed.Items[0].Link + "\n"
+ Feeds.Feeds[id].Feed.Items[0].Read = true
resp += "\n"
// Loop through subbed chans and post notification message
fmt.Println("Looping through subs to notify...")
- for _, v := range Config.Subs {
+ for _, v := range Feeds.Subs {
if v.SubID == id {
Session.ChannelMessageSend(v.ChanID, resp)
}
time.Sleep(10 * time.Millisecond)
}
- fmt.Println("No new notifys for ", Config.Feeds[id].Feed.UpdateURL)
- fmt.Println(Config.Feeds[id].Feed.Items[0])
- fmt.Println(Config.Feeds[id].Feed.Items[len(Config.Feeds[id].Feed.Items)-1])
+ fmt.Println("No new notifys for ", Feeds.Feeds[id].Feed.UpdateURL)
+ fmt.Println(Feeds.Feeds[id].Feed.Items[0])
+ fmt.Println(Feeds.Feeds[id].Feed.Items[len(Feeds.Feeds[id].Feed.Items)-1])
}
@@ 99,12 99,12 @@ func (m *Mux) Last(ds *discordgo.Session, dm *discordgo.Message, ctx *Context) {
resp := ".\n"
id, _ := strconv.Atoi(ctx.Fields[len(ctx.Fields) -1])
- if id >= 0 && id < len(Config.Feeds) {
- resp += "**" + Config.Feeds[id].Feed.Title + ": **" + "\n"
- resp += Config.Feeds[id].Feed.Items[0].Date.String() + "\n\n"
+ if id >= 0 && id < len(Feeds.Feeds) {
+ resp += "**" + Feeds.Feeds[id].Feed.Title + ": **" + "\n"
+ resp += Feeds.Feeds[id].Feed.Items[0].Date.String() + "\n\n"
// If a 9front feed, extract the user ☺
- if strings.Contains(Config.Feeds[id].Feed.Items[0].Link, "http://code.9front.org/hg/") {
- lines := strings.Split(Config.Feeds[id].Feed.Items[0].Summary, "\n")
+ if strings.Contains(Feeds.Feeds[id].Feed.Items[0].Link, "http://code.9front.org/hg/") {
+ lines := strings.Split(Feeds.Feeds[id].Feed.Items[0].Summary, "\n")
for i, v := range lines {
if strings.Contains(v, "<th style=\"text-align:left;vertical-align:top;\">user</th>") {
line := html.UnescapeString((lines[i+1])[6:len(lines[i+1])-5])
@@ 113,11 113,11 @@ func (m *Mux) Last(ds *discordgo.Session, dm *discordgo.Message, ctx *Context) {
}
}
}
- resp += "`" + Config.Feeds[id].Feed.Items[0].Title + "`" + "\n"
- //resp += "\n" + Config.Feeds[id].Feed.Items[0].Summary + "\n"
- resp += "\n" + Config.Feeds[id].Feed.Items[0].Link + "\n"
- Config.Feeds[id].Feed.Items[0].Read = true
- fmt.Println("Last-ing notification: ", Config.Feeds[id].Feed.Items[0])
+ resp += "`" + Feeds.Feeds[id].Feed.Items[0].Title + "`" + "\n"
+ //resp += "\n" + Feeds.Feeds[id].Feed.Items[0].Summary + "\n"
+ resp += "\n" + Feeds.Feeds[id].Feed.Items[0].Link + "\n"
+ Feeds.Feeds[id].Feed.Items[0].Read = true
+ fmt.Println("Last-ing notification: ", Feeds.Feeds[id].Feed.Items[0])
} else {
resp += "Denied fetch. Invalid stream id, see: list command"
}
@@ 133,7 133,7 @@ func (m *Mux) Last(ds *discordgo.Session, dm *discordgo.Message, ctx *Context) {
func (m *Mux) List(ds *discordgo.Session, dm *discordgo.Message, ctx *Context) {
resp := "```\n"
- for p, v := range Config.Feeds {
+ for p, v := range Feeds.Feeds {
resp += strconv.Itoa(p) + ": " + v.Feed.Title + ", " + v.Feed.Link + "\n"
}
@@ 144,15 144,15 @@ func (m *Mux) List(ds *discordgo.Session, dm *discordgo.Message, ctx *Context) {
return
}
-// Subscribe to a feed
+// Add a given feed to be tracked within glenda
func (m *Mux) Add(ds *discordgo.Session, dm *discordgo.Message, ctx *Context) {
//http://code.9front.org/hg/plan9front/rss-log
resp := "```\n"
// URL to feed should be last item
url := ctx.Fields[len(ctx.Fields) -1]
- fmt.Println("Proposed subscribe for: ", url)
+ fmt.Println("Proposed addition for: ", url)
- for _, v := range Config.Feeds {
+ for _, v := range Feeds.Feeds {
// this is bad matching, can't have two bitbucket url's?
if strings.Contains(url, v.Feed.UpdateURL) {
//fmt.Println(url)
@@ 180,7 180,7 @@ func (m *Mux) Add(ds *discordgo.Session, dm *discordgo.Message, ctx *Context) {
tmpFeed.Feed = *feed
// Maybe make the size here a Config variable
tmpFeed.Recent = make([]string, 3)
- Config.Feeds = append(Config.Feeds, tmpFeed)
+ Feeds.Feeds = append(Feeds.Feeds, tmpFeed)
resp += "Added."
resp += "```\n"
@@ 189,16 189,43 @@ func (m *Mux) Add(ds *discordgo.Session, dm *discordgo.Message, ctx *Context) {
return
}
+// Stop tracking a given feed
+func (m *Mux) Remove(ds *discordgo.Session, dm *discordgo.Message, ctx *Context) {
+ //http://code.9front.org/hg/plan9front/rss-log
+ resp := "```\n"
+ // ID to feed should be last item
+ ID, err := strconv.Atoi(ctx.Fields[len(ctx.Fields) -1])
+ fmt.Println("Proposed removal for: ", ID)
+
+ if ID < 0 || ID > len(Feeds.Feeds) || err != nil {
+ resp += "Denied! Feed does not exist!"
+ resp += "```\n"
+ goto REND;
+ }
+
+
+
+ // Might not be thread safe
+ Feeds.Feeds = append(Feeds.Feeds[:ID], Feeds.Feeds[ID+1:]...)
+ resp += "Removed."
+
+ REND:
+ resp += "```\n"
+ ds.ChannelMessageSend(dm.ChannelID, resp)
+
+ return
+}
+
// Subscribe current channel to notifications from a given feed id
func (m *Mux) Subscribe(ds *discordgo.Session, dm *discordgo.Message, ctx *Context) {
resp := "\n"
id, _ := strconv.Atoi(ctx.Fields[len(ctx.Fields) -1])
- if id >= 0 && id < len(Config.Feeds) {
+ if id >= 0 && id < len(Feeds.Feeds) {
var sub Subscription
// Check if already subscribed
- for _, v := range Config.Subs {
+ for _, v := range Feeds.Subs {
if v.ChanID == dm.ChannelID && v.SubID == id {
resp += "Denied subscription. Already subscribed in this channel."
goto NOSUB
@@ 209,7 236,7 @@ func (m *Mux) Subscribe(ds *discordgo.Session, dm *discordgo.Message, ctx *Conte
sub.SubID = id
// Might not be thread-safe
- Config.Subs = append(Config.Subs, sub)
+ Feeds.Subs = append(Feeds.Subs, sub)
resp += "Subscribed."
NOSUB:
} else {
@@ 228,13 255,13 @@ func (m *Mux) Unsubscribe(ds *discordgo.Session, dm *discordgo.Message, ctx *Con
resp := "\n"
id, _ := strconv.Atoi(ctx.Fields[len(ctx.Fields) -1])
- if id >= 0 && id < len(Config.Feeds) {
+ if id >= 0 && id < len(Feeds.Feeds) {
// Check if subscribed
removed := false
- for i, v := range Config.Subs {
+ for i, v := range Feeds.Subs {
if v.ChanID == dm.ChannelID && v.SubID == id {
removed = true
- Config.Subs = Config.Subs[:i+copy(Config.Subs[i:], Config.Subs[i+1:])]
+ Feeds.Subs = Feeds.Subs[:i+copy(Feeds.Subs[i:], Feeds.Subs[i+1:])]
}
}
M x/mux/config.go => x/mux/config.go +138 -5
@@ 9,11 9,14 @@ import (
"strings"
"github.com/SlyMarbo/rss"
"github.com/bwmarrin/discordgo"
+ "container/list"
)
// Global variables are bad
var Config Configuration
+var Feeds Feeder
+var Rems *list.List
var Session *discordgo.Session
// Stores subscription information for channels related to RSS feeds
@@ 28,21 31,30 @@ type Feed struct {
Recent []string
}
-// Stores config for current state
-type Configuration struct {
+type Feeder struct {
Feeds []Feed
Subs []Subscription
}
+// Stores config for current state
+type Configuration struct {
+
+}
+
// Initializes current config (called once at start) just .Read()?
func (c *Configuration) Init(s *discordgo.Session) {
+ Rems = list.New()
c.Read()
Session = s
- for id, _ := range Config.Feeds {
+ for id, _ := range Feeds.Feeds {
// maybe only do at init step?
- str := Config.Feeds[id].Feed.UpdateURL
+ str := Feeds.Feeds[id].Feed.UpdateURL
feed, _ := rss.Fetch(str)
- Config.Feeds[id].Feed = *feed
+ if feed != nil {
+ Feeds.Feeds[id].Feed = *feed
+ } else {
+ fmt.Println("Failed to fetch feed: ", id)
+ }
}
go Listener()
}
@@ 76,6 88,64 @@ func (c *Configuration) Write() (rerr error) {
return
}
+// Writes the Feed config file
+func (c *Feeder) Write() (rerr error) {
+ FWRT:
+ rerr = nil
+ f, err := os.OpenFile("./cfg/feeds.cfg", os.O_RDWR, 0666)
+ defer f.Close()
+ if err != nil {
+ if strings.Contains(err.Error(), "no such file or directory") {
+ // danger: this can go infinite
+ Config.Setup()
+ goto FWRT
+ } else {
+ fmt.Println("Error opening feeds config (w), see: config.go")
+ fmt.Printf("%s\n", err)
+ rerr = err
+ }
+ } else {
+ e := json.NewEncoder(f)
+ err = e.Encode(Feeds)
+ if err != nil {
+ fmt.Println("Error writing feeds config, see: config.go")
+ fmt.Printf("%s\n", err)
+ rerr = err
+ }
+ }
+
+ return
+}
+
+// Writes the Reminders config file
+func RemindersWrite() (rerr error) {
+ RWRT:
+ rerr = nil
+ f, err := os.OpenFile("./cfg/reminders.cfg", os.O_RDWR, 0666)
+ defer f.Close()
+ if err != nil {
+ if strings.Contains(err.Error(), "no such file or directory") {
+ // danger: this can go infinite
+ Config.Setup()
+ goto RWRT
+ } else {
+ fmt.Println("Error opening reminders config (w), see: config.go")
+ fmt.Printf("%s\n", err)
+ rerr = err
+ }
+ } else {
+ e := json.NewEncoder(f)
+ err = e.Encode(*Rems)
+ if err != nil {
+ fmt.Println("Error writing reminders config, see: config.go")
+ fmt.Printf("%s\n", err)
+ rerr = err
+ }
+ }
+
+ return
+}
+
// Reads current config into memory
func (c *Configuration) Read() (rerr error) {
RD:
@@ 101,6 171,55 @@ func (c *Configuration) Read() (rerr error) {
Config.Write()
}
}
+ f.Close()
+
+ // Feeds
+ f, err = os.Open("./cfg/feeds.cfg")
+ if err != nil {
+ if strings.Contains(err.Error(), "no such file or directory") {
+ // danger: this can go infinite
+ Config.Setup()
+ goto RD
+ } else {
+ fmt.Println("Error opening feeds config (r), see: config.go")
+ fmt.Printf("%s\n", err)
+ rerr = err
+ }
+ } else {
+ d := json.NewDecoder(f)
+ err = d.Decode(&Feeds)
+ if err != nil {
+ fmt.Println("Error reading feeds config, see: config.go")
+ fmt.Printf("%s\n", err)
+ rerr = err
+ Feeds.Write()
+ }
+ }
+ f.Close()
+
+ // Reminders
+ f, err = os.Open("./cfg/reminders.cfg")
+ if err != nil {
+ if strings.Contains(err.Error(), "no such file or directory") {
+ // danger: this can go infinite
+ Config.Setup()
+ goto RD
+ } else {
+ fmt.Println("Error opening reminders config (r), see: config.go")
+ fmt.Printf("%s\n", err)
+ rerr = err
+ }
+ } else {
+ d := json.NewDecoder(f)
+ err = d.Decode(Rems)
+ if err != nil {
+ fmt.Println("Error reading reminders config, see: config.go")
+ fmt.Printf("%s\n", err)
+ rerr = err
+ RemindersWrite()
+ }
+ }
+ f.Close()
return
}
@@ 118,4 237,18 @@ func (c *Configuration) Setup() {
fmt.Println("Error in making cfg file, see: config.go")
fmt.Println(err)
}
+
+ // Feeds
+ _, err = os.Create("cfg/feeds.cfg")
+ if err != nil {
+ fmt.Println("Error in making feed cfg file, see: config.go")
+ fmt.Println(err)
+ }
+
+ // Reminders
+ _, err = os.Create("cfg/reminders.cfg")
+ if err != nil {
+ fmt.Println("Error in making reminders cfg file, see: config.go")
+ fmt.Println(err)
+ }
}
M x/mux/fortunes.go => x/mux/fortunes.go +17 -2
@@ 21,8 21,6 @@ func (m *Mux) Fortunes(ds *discordgo.Session, dm *discordgo.Message, ctx *Contex
f = "troll"
} else if strings.Contains(dm.Content, "rsc") {
f = "rsc"
- } else if strings.Contains(dm.Content, "bullshit") {
- f = "bullshit"
} else if strings.Contains(dm.Content, "terry") {
f = "terry"
} else if strings.Contains(dm.Content, "rob") {
@@ 48,3 46,20 @@ func (m *Mux) Fortunes(ds *discordgo.Session, dm *discordgo.Message, ctx *Contex
return
}
+// Display bullshit from 9front
+func (m *Mux) Bullshit(ds *discordgo.Session, dm *discordgo.Message, ctx *Context) {
+ resp := "```\n"
+
+ out, err := exec.Command("./x/mux/misc/bullshit").Output()
+ if err != nil {
+ resp += "No bullshit script found."
+ goto END
+ } else {
+ resp += string(out)
+ }
+
+ END:
+ resp += "```\n"
+ ds.ChannelMessageSend(dm.ChannelID, resp)
+ return
+}
A x/mux/misc/bullshit => x/mux/misc/bullshit +59 -0
@@ 0,0 1,59 @@
+#!/usr/bin/env rc
+# This is 9front bullshit made unix portable
+MIRROR=/usr/share/mirror/plan9front
+rfork e
+if(~ $#1 0)
+ file=$MIRROR/lib/bullshit
+if not
+ file=$1
+awk '
+function min(a, b){
+ if(a > b)
+ return b
+ else
+ return a
+}
+function suffix(){
+ if(hassuffix = (rand() < 0.2))
+ return suffixes[int(rand() * nsuffix)]
+ return ""
+}
+$2 == "*" { protocol[nprotocol++] = $1; next }
+$2 == "$" { end[nend++] = $1; next }
+$2 == "%" { suffixes[nsuffix++] = $1; next }
+$2 == "^" { start[nstart++] = $1; next }
+$2 == "|" { noend[nword] = 1 }
+{ word[nword++] = $1; next }
+END {
+ srand()
+ last = -1
+ out = 0
+ total = int(rand() * 7) + 3
+ n = int(rand() * min(total - out, 3))
+ for(i = 0; i < n; i++)
+ printf "%s ", start[int(rand() * nstart)]
+ out += n
+ hassuffix = 0
+ n = int(rand() * min(total - out, 3))
+ for(i = 0; i < n; i++)
+ printf "%s%s ", word[last = int(rand() * nword)], suffix()
+ out += n
+ if(rand() > 0.5){
+ n = int(rand() * 3)
+ for(i = 0; i < n; i++)
+ printf "%s %s", protocol[int(rand() * nprotocol)], (i != n-1) ? "over " : ""
+ out += n
+ last = -1
+ hassuffix = 0
+ }
+ n = int(rand() * min(total - out, 3))
+ if(out + n == 1 || last == -1)
+ n += 2
+ for(i = 0; i < n; i++)
+ printf "%s%s ", word[last = int(rand() * nword)], suffix()
+ if(rand() < 0.1 || (last >= 0 && noend[last]) || hassuffix)
+ printf "%s ", end[int(rand() * nend)]
+ print ""
+}
+' $file
+
M x/mux/remind.go => x/mux/remind.go +9 -65
@@ 4,11 4,8 @@ import (
"github.com/bwmarrin/discordgo"
"time"
sc "strconv"
- "container/list"
- "fmt"
- "os"
- "encoding/json"
- "strings"
+// "container/list"
+// "fmt"
)
@@ 26,74 23,21 @@ type Reminder struct {
// Reminder daemon process that gets started in main and listens on RemChan
func Reminders() {
- // TODO -- Should be a heap and more robus (fix config first)
-
- rems := list.New()
-
- RD:
- f, err := os.Open("./cfg/reminders.cfg")
-
- write := func() (rerr error) {
- e := json.NewEncoder(f)
- err = e.Encode(rems)
- if err != nil {
- fmt.Println("Error writing config, see: remind.go")
- fmt.Printf("%s\n", err)
- rerr = err
- }
- return
- }
-
- setup := func() (rerr error) {
-
- err := os.Mkdir("./cfg", 0774)
- if err != nil {
- fmt.Println("Error in making cfg dir, see: remind.go")
- fmt.Println(err)
- }
-
- _, err = os.Create("cfg/reminders.cfg")
- if err != nil {
- fmt.Println("Error in making cfg file, see: remind.go")
- fmt.Println(err)
- }
- rerr = err
- return
- }
-
- defer f.Close()
- if err != nil {
- if strings.Contains(err.Error(), "no such file or directory") {
- // danger: this can go infinite
- setup()
- goto RD
- } else {
- fmt.Println("Error opening config (r), see: remind.go")
- fmt.Printf("%s\n", err)
- }
- } else {
- d := json.NewDecoder(f)
- err = d.Decode(&rems)
- if err != nil {
- fmt.Println("Error reading config, see: remind.go")
- fmt.Printf("%s\n", err)
-
- write()
- }
- }
+ // TODO -- Should be a heap and more robust (fix config first)
+ //Rems := list.New()
// Handle reminders
for {
select {
case r := <- RemChan:
// Handle new reminder
- rems.PushBack(r)
- write()
+ Rems.PushBack(r)
+ //write()
default:
// Check for any due reminders
- for e := rems.Front(); ; e = e.Next() {
+ for e := Rems.Front(); ; e = e.Next() {
if e == nil {
break
}
@@ 102,8 46,8 @@ func Reminders() {
if time.Now().After(r.NotifyAfter) {
// If we have passed the time of desired notification
r.Session.ChannelMessageSend(r.ChannelID, r.User.Mention() + " -- " + r.Reason)
- rems.Remove(e)
- write()
+ Rems.Remove(e)
+ //write()
}
}