From f9959eb9e0b2761b3a1ca98181e50f5dd7f781ae Mon Sep 17 00:00:00 2001 From: Sean Hinchee Date: Sun, 28 Oct 2018 19:26:26 +0000 Subject: [PATCH] add Remove handler, add bullshit, fix config files (need refactoring badly), update help text --- mux.go | 6 +- x/mux/commits.go | 113 +++++++++++++++++++++------------- x/mux/config.go | 143 ++++++++++++++++++++++++++++++++++++++++++-- x/mux/fortunes.go | 19 +++++- x/mux/misc/bullshit | 59 ++++++++++++++++++ x/mux/remind.go | 74 +++-------------------- 6 files changed, 297 insertions(+), 117 deletions(-) create mode 100755 x/mux/misc/bullshit diff --git a/mux.go b/mux.go index ddb072bb6d7e87e59d5e7ff9b0c03cc043f3b2ef..64ded040299ac2acbb6c1c54ce2fb104f323cffa 100644 --- a/mux.go +++ b/mux.go @@ -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) } diff --git a/x/mux/commits.go b/x/mux/commits.go index 602a361fe8e02daaf56b0b5ea63d94da38c83e16..1525b69e4196f88eda96759fe54c135271041742 100644 --- a/x/mux/commits.go +++ b/x/mux/commits.go @@ -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, "user") { 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, "user") { 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:])] } } diff --git a/x/mux/config.go b/x/mux/config.go index 3e1092747e7221d5eae283fabf085c4df9b492a1..12e37e6423cb4184d2cca89818cbed911cb35a95 100644 --- a/x/mux/config.go +++ b/x/mux/config.go @@ -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) + } } diff --git a/x/mux/fortunes.go b/x/mux/fortunes.go index 4a2bd0cd580b7bc91f63db82d02789e98fab241a..38afd4c8a2133606a7ce26533a8c79d20885ab2b 100644 --- a/x/mux/fortunes.go +++ b/x/mux/fortunes.go @@ -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 +} diff --git a/x/mux/misc/bullshit b/x/mux/misc/bullshit new file mode 100755 index 0000000000000000000000000000000000000000..f9b0c0f6af1bc2853a3ea0c1c96df9d76f9fd0ba --- /dev/null +++ b/x/mux/misc/bullshit @@ -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 + diff --git a/x/mux/remind.go b/x/mux/remind.go index 78e7bac7b51789496427c0be176f6a639ef458a8..b701211651888d8db0042b963803f36f7b7536b4 100644 --- a/x/mux/remind.go +++ b/x/mux/remind.go @@ -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() } }