From 5fe432b7c1d6d626699e8091005a0de788d8168a Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Tue, 20 Dec 2016 23:05:09 +0100 Subject: links --- blame.go | 26 -------------------------- duck.go | 28 ---------------------------- help.go | 29 ----------------------------- href.go | 38 +++++++++++++++++++++----------------- href_test.go | 2 +- main.go | 2 +- urban.go | 33 --------------------------------- 7 files changed, 23 insertions(+), 135 deletions(-) delete mode 100644 blame.go delete mode 100644 duck.go delete mode 100644 help.go delete mode 100644 urban.go diff --git a/blame.go b/blame.go deleted file mode 100644 index 094a45f..0000000 --- a/blame.go +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import ( - irc "github.com/fluffle/goirc/client" -) - -type Blame struct{} - -func (Blame) Handle(conn *irc.Conn, line *irc.Line) { - src := []string{ - "Author: Dimitri Sokolyuk ", - "Source: http://git.dim13.org/bot.git", - "Install: go get dim13.org/bot", - } - for _, s := range src { - conn.Notice(line.Nick, s) - } -} - -func (Blame) String() string { - return "Blame author and return link to source code" -} - -func init() { - Register("blame", &Blame{}) -} diff --git a/duck.go b/duck.go deleted file mode 100644 index 7900cc0..0000000 --- a/duck.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "strings" - - "dim13.org/duck" - irc "github.com/fluffle/goirc/client" -) - -type Duck struct{} - -func (Duck) Handle(conn *irc.Conn, line *irc.Line) { - if q := strings.SplitN(line.Text(), " ", 2); len(q) == 2 { - if a, err := duck.Abstract(q[1]); err != nil { - conn.Notice(line.Target(), err.Error()) - } else { - conn.Notice(line.Target(), a) - } - } -} - -func (Duck) String() string { - return "Perform duckduckgo instant answer search" -} - -func init() { - Register("define", &Duck{}) -} diff --git a/help.go b/help.go deleted file mode 100644 index f6cf4c5..0000000 --- a/help.go +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "fmt" - "sort" - - irc "github.com/fluffle/goirc/client" -) - -type Help struct{} - -func (Help) Handle(conn *irc.Conn, line *irc.Line) { - var msg []string - for k, v := range commands { - msg = append(msg, fmt.Sprintf("%-8s%v", k, v)) - } - sort.Sort(sort.StringSlice(msg)) - for _, s := range msg { - conn.Notice(line.Nick, s) - } -} - -func (Help) String() string { - return "This help" -} - -func init() { - Register("help", &Help{}) -} diff --git a/href.go b/href.go index 0799fad..e1a687b 100644 --- a/href.go +++ b/href.go @@ -28,7 +28,7 @@ func title(n *html.Node) (s string) { return "" } -func findTitle(uri string) (string, error) { +func getTitle(uri string) (string, error) { resp, err := http.Get(uri) if err != nil { return "", err @@ -53,26 +53,30 @@ func findTitle(uri string) (string, error) { return title(doc), nil } -func ExtractLinks(conn *irc.Conn, line *irc.Line) { - for _, v := range strings.Fields(line.Text()) { +func links(s string) (ret []string) { + for _, v := range strings.Fields(s) { switch { case strings.HasPrefix(v, "www"): v = "http://" + v fallthrough - case strings.HasPrefix(v, "http"): - go func(uri string) { - log.Println(line.Nick, uri) - t, err := findTitle(uri) - if err != nil { - log.Println(err) - } - if t != "" { - if len(t) > maxLen { - t = t[:maxLen] + "..." - } - conn.Notice(line.Target(), "Title: "+t) - } - }(v) + case strings.HasPrefix(v, "http:"), strings.HasPrefix(v, "https:"): + ret = append(ret, v) + } + } + return +} + +func Links(conn *irc.Conn, line *irc.Line) { + for _, v := range links(line.Text()) { + t, err := getTitle(v) + if err != nil { + log.Println(err) + } + if t != "" { + if len(t) > maxLen { + t = t[:maxLen] + "..." + } + conn.Notice(line.Target(), "Title: "+t) } } } diff --git a/href_test.go b/href_test.go index d884b2f..4134d47 100644 --- a/href_test.go +++ b/href_test.go @@ -26,7 +26,7 @@ func TestTitle(t *testing.T) { } for _, tc := range testCases { t.Run(tc.URL, func(t *testing.T) { - title, err := findTitle(tc.URL) + title, err := getTitle(tc.URL) if err != nil { t.Error(tc.URL, err) } diff --git a/main.go b/main.go index 84b0d6b..9dcf9d6 100644 --- a/main.go +++ b/main.go @@ -32,7 +32,7 @@ func main() { c.HandleFunc(irc.PRIVMSG, func(conn *irc.Conn, line *irc.Line) { go Dispatch(conn, line) - go ExtractLinks(conn, line) + go Links(conn, line) if line.Public() && line.Nick != conn.Me().Nick { if isFlood(line.Text()) { log.Println("flood", line.Nick) diff --git a/urban.go b/urban.go deleted file mode 100644 index 97fa4ff..0000000 --- a/urban.go +++ /dev/null @@ -1,33 +0,0 @@ -package main - -import ( - "fmt" - "strings" - - "dim13.org/urban" - irc "github.com/fluffle/goirc/client" -) - -type Urban struct{} - -func (Urban) Handle(conn *irc.Conn, line *irc.Line) { - if q := strings.SplitN(line.Text(), " ", 2); len(q) == 2 { - if u, err := urban.QueryTop(q[1]); err != nil { - conn.Notice(line.Target(), err.Error()) - } else { - if len(u.Definition) > maxLen { - u.Definition = u.Definition[:maxLen] + "..." - } - s := fmt.Sprintf("%v: %v", u.Word, u.Definition) - conn.Notice(line.Target(), s) - } - } -} - -func (Urban) String() string { - return "Perform urban dictionary search" -} - -func init() { - Register("urban", &Urban{}) -} -- cgit v1.2.3 From d3203ad6128ec64ce5422e7609b71f518bc9a01a Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Tue, 20 Dec 2016 23:11:53 +0100 Subject: Watch news --- main.go | 2 +- rss.go | 44 ++++++++++++++++++++++---------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/main.go b/main.go index 9dcf9d6..1abe5e1 100644 --- a/main.go +++ b/main.go @@ -23,7 +23,7 @@ func main() { c.HandleFunc(irc.CONNECTED, func(conn *irc.Conn, line *irc.Line) { conn.Join(*room) - ShowNews(conn, *room) + go ShowNews(conn, *room) }) c.HandleFunc(irc.KICK, func(conn *irc.Conn, line *irc.Line) { diff --git a/rss.go b/rss.go index 0a49952..1d9d9db 100644 --- a/rss.go +++ b/rss.go @@ -89,32 +89,32 @@ func (n News) String() string { return s } +func (f Feed) Watch(news chan News) { + ticker := time.NewTicker(f.Every) + defer ticker.Stop() + for t := range ticker.C { + r, err := rss.Fetch(f.URL) + if err != nil { + log.Println(f.Name, err) + return + } + last := t.Add(-f.Every) + for _, i := range r.Channel.Items { + if i.PubDate.After(last) { + news <- News{f, i} + } + } + } +} + func ShowNews(conn *irc.Conn, room string) { news := make(chan News) for _, f := range Feeds { - go func(f Feed) { - ticker := time.NewTicker(f.Every) - defer ticker.Stop() - for t := range ticker.C { - r, err := rss.Fetch(f.URL) - if err != nil { - log.Println(f.Name, err) - return - } - to := t.Add(-f.Every) - for _, i := range r.Channel.Items { - if i.PubDate.After(to) { - news <- News{f, i} - } - } - } - }(f) + go f.Watch(news) } - go func() { - for n := range news { - conn.Notice(room, n.String()) - } - }() + for n := range news { + conn.Notice(room, n.String()) + } } -- cgit v1.2.3 From 8352e63f1604786e5a37312910a78ef78cfc296d Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Tue, 20 Dec 2016 23:14:33 +0100 Subject: Watch news --- main.go | 2 +- rss.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 1abe5e1..0ca82c3 100644 --- a/main.go +++ b/main.go @@ -23,7 +23,7 @@ func main() { c.HandleFunc(irc.CONNECTED, func(conn *irc.Conn, line *irc.Line) { conn.Join(*room) - go ShowNews(conn, *room) + go WatchNews(conn, *room) }) c.HandleFunc(irc.KICK, func(conn *irc.Conn, line *irc.Line) { diff --git a/rss.go b/rss.go index 1d9d9db..f79efe7 100644 --- a/rss.go +++ b/rss.go @@ -107,7 +107,7 @@ func (f Feed) Watch(news chan News) { } } -func ShowNews(conn *irc.Conn, room string) { +func WatchNews(conn *irc.Conn, room string) { news := make(chan News) for _, f := range Feeds { -- cgit v1.2.3 From 9b70cb6996a7b9e151e23dc9e49cc8a1114391d5 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Tue, 20 Dec 2016 23:17:09 +0100 Subject: Remove help stringer --- command.go | 2 -- last.go | 4 ---- 2 files changed, 6 deletions(-) diff --git a/command.go b/command.go index 9f20c45..b098b1b 100644 --- a/command.go +++ b/command.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "log" "strings" @@ -10,7 +9,6 @@ import ( type Commander interface { irc.Handler - fmt.Stringer } const maxLen = 500 diff --git a/last.go b/last.go index 8cf12fa..aa326e4 100644 --- a/last.go +++ b/last.go @@ -23,10 +23,6 @@ func (Last) Handle(conn *irc.Conn, line *irc.Line) { }) } -func (Last) String() string { - return "Return last 10 messages" -} - func Push(line *irc.Line) { buffer.Value = line buffer = buffer.Next() -- cgit v1.2.3 From a037c25326bceabc471f679ab2203d99e248ab0e Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Tue, 20 Dec 2016 23:18:45 +0100 Subject: maxLen --- command.go | 2 -- href.go | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/command.go b/command.go index b098b1b..665d530 100644 --- a/command.go +++ b/command.go @@ -11,8 +11,6 @@ type Commander interface { irc.Handler } -const maxLen = 500 - var commands = make(map[string]Commander) func Register(cmd string, f Commander) { diff --git a/href.go b/href.go index e1a687b..918a2f2 100644 --- a/href.go +++ b/href.go @@ -13,6 +13,8 @@ import ( var errNotHTML = errors.New("not HTML content") +const maxLen = 500 + func title(n *html.Node) (s string) { if n.Type == html.ElementNode && n.Data == "title" { for c := n.FirstChild; c != nil; c = c.NextSibling { -- cgit v1.2.3 From c2eaea7276945057ac18b31d06b79a6326932b57 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Tue, 20 Dec 2016 23:50:27 +0100 Subject: cleanup main --- main.go | 84 +++++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 23 deletions(-) diff --git a/main.go b/main.go index 0ca82c3..442ef56 100644 --- a/main.go +++ b/main.go @@ -7,45 +7,83 @@ import ( irc "github.com/fluffle/goirc/client" ) -func main() { - node := flag.String("node", "irc.freenode.org:6667", "IRC Server") - room := flag.String("room", "#lor", "IRC Channel") - name := flag.String("name", "dim13", "Bots Name") - flag.Parse() - - c := irc.SimpleClient(*name) - c.EnableStateTracking() +func notify(conn *irc.Conn, target string) chan string { + c := make(chan string) + go func() { + for msg := range c { + conn.Notice(target, msg) + } + }() + return c +} - discon := make(chan struct{}) - c.HandleFunc(irc.DISCONNECTED, func(conn *irc.Conn, line *irc.Line) { - close(discon) - }) +func kicker(conn *irc.Conn, target string) chan string { + c := make(chan string) + go func() { + for nick := range c { + conn.Kick(target, nick) + } + }() + return c +} - c.HandleFunc(irc.CONNECTED, func(conn *irc.Conn, line *irc.Line) { - conn.Join(*room) - go WatchNews(conn, *room) - }) +func join(room string) irc.HandlerFunc { + return func(conn *irc.Conn, _ *irc.Line) { + conn.Join(room) + } +} - c.HandleFunc(irc.KICK, func(conn *irc.Conn, line *irc.Line) { - conn.Join(*room) - }) +func discon(c chan struct{}) irc.HandlerFunc { + return func(_ *irc.Conn, _ *irc.Line) { + close(c) + } +} - c.HandleFunc(irc.PRIVMSG, func(conn *irc.Conn, line *irc.Line) { +func privmsg(room string) irc.HandlerFunc { + return func(conn *irc.Conn, line *irc.Line) { go Dispatch(conn, line) go Links(conn, line) if line.Public() && line.Nick != conn.Me().Nick { if isFlood(line.Text()) { log.Println("flood", line.Nick) - conn.Kick(*room, line.Nick, "flood") + conn.Kick(room, line.Nick, "flood") } Push(line) } - }) + } +} + +func main() { + node := flag.String("node", "irc.freenode.org:6667", "IRC Server") + room := flag.String("room", "#lor", "IRC Channel") + name := flag.String("name", "dim13", "Bots Name") + flag.Parse() + + c := irc.SimpleClient(*name) + c.EnableStateTracking() // XXX + done := make(chan struct{}) + + // setup event handler + handler := []struct { + ev string + f irc.HandlerFunc + }{ + {irc.DISCONNECTED, discon(done)}, + {irc.CONNECTED, join(*room)}, + {irc.KICK, join(*room)}, + {irc.PRIVMSG, privmsg(*room)}, + } + for _, h := range handler { + c.HandleFunc(h.ev, h.f) + } log.Println("Connect to", *node) if err := c.ConnectTo(*node); err != nil { log.Fatal(err) } - <-discon + + go WatchNews(c, *room) + + <-done log.Println("Disconnected") } -- cgit v1.2.3 From 44b2a071555235d8e7c1d64d85541ade50527e3b Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Tue, 20 Dec 2016 23:58:49 +0100 Subject: news watcher --- main.go | 7 ++++--- rss.go | 11 ++++------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/main.go b/main.go index 442ef56..1b8ac33 100644 --- a/main.go +++ b/main.go @@ -17,11 +17,11 @@ func notify(conn *irc.Conn, target string) chan string { return c } -func kicker(conn *irc.Conn, target string) chan string { +func kicker(conn *irc.Conn, channel string) chan string { c := make(chan string) go func() { for nick := range c { - conn.Kick(target, nick) + conn.Kick(channel, nick) } }() return c @@ -82,7 +82,8 @@ func main() { log.Fatal(err) } - go WatchNews(c, *room) + n := notify(c, *room) + go watchNews(n) <-done log.Println("Disconnected") diff --git a/rss.go b/rss.go index f79efe7..741b81d 100644 --- a/rss.go +++ b/rss.go @@ -6,7 +6,6 @@ import ( "time" "dim13.org/rss" - irc "github.com/fluffle/goirc/client" ) type Feed struct { @@ -107,14 +106,12 @@ func (f Feed) Watch(news chan News) { } } -func WatchNews(conn *irc.Conn, room string) { +func watchNews(msg chan string) { news := make(chan News) - - for _, f := range Feeds { - go f.Watch(news) + for _, feed := range Feeds { + go feed.Watch(news) } - for n := range news { - conn.Notice(room, n.String()) + msg <- fmt.Sprint(n) } } -- cgit v1.2.3 From 91d96257792d34ef8af6027d70775b8bc376618f Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Wed, 21 Dec 2016 00:00:22 +0100 Subject: Remove all commands --- command.go | 28 ---------------------------- last.go | 33 --------------------------------- main.go | 2 -- 3 files changed, 63 deletions(-) delete mode 100644 command.go delete mode 100644 last.go diff --git a/command.go b/command.go deleted file mode 100644 index 665d530..0000000 --- a/command.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "log" - "strings" - - irc "github.com/fluffle/goirc/client" -) - -type Commander interface { - irc.Handler -} - -var commands = make(map[string]Commander) - -func Register(cmd string, f Commander) { - commands[cmd] = f -} - -func Dispatch(conn *irc.Conn, line *irc.Line) { - if f := strings.Fields(line.Text()); len(f) > 0 { - cmd := strings.ToLower(f[0]) - if c, ok := commands[cmd]; ok { - log.Println(line.Nick, f) - c.Handle(conn, line) - } - } -} diff --git a/last.go b/last.go deleted file mode 100644 index aa326e4..0000000 --- a/last.go +++ /dev/null @@ -1,33 +0,0 @@ -package main - -import ( - "container/ring" - "fmt" - - irc "github.com/fluffle/goirc/client" -) - -type Last struct{} - -var buffer = ring.New(10) - -func (Last) Handle(conn *irc.Conn, line *irc.Line) { - buffer.Do(func(v interface{}) { - if v != nil { - l := v.(*irc.Line) - s := fmt.Sprintf("%v <%v> %v", - l.Time.UTC().Format("15:04 UTC"), - l.Nick, l.Text()) - conn.Notice(line.Nick, s) - } - }) -} - -func Push(line *irc.Line) { - buffer.Value = line - buffer = buffer.Next() -} - -func init() { - Register("last", &Last{}) -} diff --git a/main.go b/main.go index 1b8ac33..3b8daa5 100644 --- a/main.go +++ b/main.go @@ -41,14 +41,12 @@ func discon(c chan struct{}) irc.HandlerFunc { func privmsg(room string) irc.HandlerFunc { return func(conn *irc.Conn, line *irc.Line) { - go Dispatch(conn, line) go Links(conn, line) if line.Public() && line.Nick != conn.Me().Nick { if isFlood(line.Text()) { log.Println("flood", line.Nick) conn.Kick(room, line.Nick, "flood") } - Push(line) } } } -- cgit v1.2.3 From 429466e258c9228483ae8928f66fd52cec1178eb Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Wed, 21 Dec 2016 00:25:57 +0100 Subject: privmsg --- href.go | 31 ++++++++++++++++--------------- main.go | 34 +++++++++++++++++++++------------- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/href.go b/href.go index 918a2f2..5efa71c 100644 --- a/href.go +++ b/href.go @@ -2,19 +2,17 @@ package main import ( "errors" + "fmt" "log" "net/http" "strings" - irc "github.com/fluffle/goirc/client" "golang.org/x/net/html" "golang.org/x/net/html/charset" ) var errNotHTML = errors.New("not HTML content") -const maxLen = 500 - func title(n *html.Node) (s string) { if n.Type == html.ElementNode && n.Data == "title" { for c := n.FirstChild; c != nil; c = c.NextSibling { @@ -55,7 +53,7 @@ func getTitle(uri string) (string, error) { return title(doc), nil } -func links(s string) (ret []string) { +func getLinks(s string) (ret []string) { for _, v := range strings.Fields(s) { switch { case strings.HasPrefix(v, "www"): @@ -68,17 +66,20 @@ func links(s string) (ret []string) { return } -func Links(conn *irc.Conn, line *irc.Line) { - for _, v := range links(line.Text()) { - t, err := getTitle(v) - if err != nil { - log.Println(err) - } - if t != "" { - if len(t) > maxLen { - t = t[:maxLen] + "..." +func links(msg chan string) chan string { + c := make(chan string) + go func() { + for l := range c { + for _, v := range getLinks(l) { + t, err := getTitle(v) + if err != nil { + log.Println(err) + } + if t != "" { + msg <- fmt.Sprint("Title:", t) + } } - conn.Notice(line.Target(), "Title: "+t) } - } + }() + return c } diff --git a/main.go b/main.go index 3b8daa5..da2f50b 100644 --- a/main.go +++ b/main.go @@ -7,10 +7,16 @@ import ( irc "github.com/fluffle/goirc/client" ) +const maxLen = 500 + func notify(conn *irc.Conn, target string) chan string { c := make(chan string) go func() { for msg := range c { + log.Println("send", msg) + if len(msg) > maxLen { + msg = msg[:maxLen] + "..." + } conn.Notice(target, msg) } }() @@ -21,7 +27,10 @@ func kicker(conn *irc.Conn, channel string) chan string { c := make(chan string) go func() { for nick := range c { - conn.Kick(channel, nick) + if nick != conn.Me().Nick { + log.Println("kick", nick) + conn.Kick(channel, nick) + } } }() return c @@ -39,14 +48,14 @@ func discon(c chan struct{}) irc.HandlerFunc { } } -func privmsg(room string) irc.HandlerFunc { +func privmsg(n, k chan string, room string) irc.HandlerFunc { + go watchNews(n) // TODO shall it be there? + l := links(n) return func(conn *irc.Conn, line *irc.Line) { - go Links(conn, line) - if line.Public() && line.Nick != conn.Me().Nick { - if isFlood(line.Text()) { - log.Println("flood", line.Nick) - conn.Kick(room, line.Nick, "flood") - } + t := line.Text() + l <- t + if isFlood(t) { + k <- line.Nick } } } @@ -58,8 +67,10 @@ func main() { flag.Parse() c := irc.SimpleClient(*name) - c.EnableStateTracking() // XXX + //c.EnableStateTracking() // XXX done := make(chan struct{}) + n := notify(c, *room) + k := kicker(c, *room) // setup event handler handler := []struct { @@ -69,7 +80,7 @@ func main() { {irc.DISCONNECTED, discon(done)}, {irc.CONNECTED, join(*room)}, {irc.KICK, join(*room)}, - {irc.PRIVMSG, privmsg(*room)}, + {irc.PRIVMSG, privmsg(n, k, *room)}, } for _, h := range handler { c.HandleFunc(h.ev, h.f) @@ -80,9 +91,6 @@ func main() { log.Fatal(err) } - n := notify(c, *room) - go watchNews(n) - <-done log.Println("Disconnected") } -- cgit v1.2.3 From 432d01e3872d050663379006a7e66dc2932a89d7 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Wed, 21 Dec 2016 00:31:46 +0100 Subject: Fix title --- href.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/href.go b/href.go index 5efa71c..9c67bb0 100644 --- a/href.go +++ b/href.go @@ -76,7 +76,7 @@ func links(msg chan string) chan string { log.Println(err) } if t != "" { - msg <- fmt.Sprint("Title:", t) + msg <- fmt.Sprintf("Title: %v", t) } } } -- cgit v1.2.3 From 75bec51affee1f01d107e68b38180c9d5d5edae0 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Wed, 21 Dec 2016 00:38:25 +0100 Subject: Split feeds --- feeds.go | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 2 +- rss.go | 66 ++++------------------------------------------------------------ 3 files changed, 66 insertions(+), 63 deletions(-) create mode 100644 feeds.go diff --git a/feeds.go b/feeds.go new file mode 100644 index 0000000..9e6412e --- /dev/null +++ b/feeds.go @@ -0,0 +1,61 @@ +package main + +import "time" + +var Feeds = []Feed{ + { + Name: "LOR News", + URL: `https://www.linux.org.ru/section-rss.jsp?section=1`, + Every: time.Hour, + }, + { + Name: "LOR Forum", + URL: `https://www.linux.org.ru/section-rss.jsp?section=2&filter=tech`, + Every: time.Minute, + }, + { + Name: "LOR Gallery", + URL: `https://www.linux.org.ru/section-rss.jsp?section=3`, + Every: 2 * time.Hour, + }, + { + Name: "LOR Polls", + URL: `https://www.linux.org.ru/section-rss.jsp?section=5`, + Every: 2 * time.Hour, + }, + { + Name: "OpenNET", + URL: `http://www.opennet.ru/opennews/opennews_all_noadv.rss`, + Every: 4 * time.Hour, + }, + { + Name: "Undeadly", + URL: `http://undeadly.org/cgi?action=rss`, + Every: 2 * time.Hour, + }, + { + Name: "Kernel", + URL: `https://www.kernel.org/feeds/kdist.xml`, + Every: 6 * time.Hour, + }, + { + Name: "Ted Unangst", + URL: `http://www.tedunangst.com/flak/rss`, + Every: 6 * time.Hour, + }, + { + Name: "Calomel", + URL: `https://calomel.org/calomel_rss.xml`, + Every: 6 * time.Hour, + }, + { + Name: "Golang News", + URL: `https://golangnews.com/index.xml`, + Every: 6 * time.Hour, + }, + { + Name: "Golang Weekly", + URL: `http://golangweekly.com/rss/1fg21ahk`, + Every: 6 * time.Hour, + }, +} diff --git a/main.go b/main.go index da2f50b..cd1d751 100644 --- a/main.go +++ b/main.go @@ -49,7 +49,6 @@ func discon(c chan struct{}) irc.HandlerFunc { } func privmsg(n, k chan string, room string) irc.HandlerFunc { - go watchNews(n) // TODO shall it be there? l := links(n) return func(conn *irc.Conn, line *irc.Line) { t := line.Text() @@ -71,6 +70,7 @@ func main() { done := make(chan struct{}) n := notify(c, *room) k := kicker(c, *room) + go Watch(n, Feeds) // TODO shall it be there? // setup event handler handler := []struct { diff --git a/rss.go b/rss.go index 741b81d..6f5239b 100644 --- a/rss.go +++ b/rss.go @@ -14,64 +14,6 @@ type Feed struct { Every time.Duration } -var Feeds = []Feed{ - { - Name: "LOR News", - URL: `https://www.linux.org.ru/section-rss.jsp?section=1`, - Every: time.Hour, - }, - { - Name: "LOR Forum", - URL: `https://www.linux.org.ru/section-rss.jsp?section=2&filter=tech`, - Every: time.Minute, - }, - { - Name: "LOR Gallery", - URL: `https://www.linux.org.ru/section-rss.jsp?section=3`, - Every: 2 * time.Hour, - }, - { - Name: "LOR Polls", - URL: `https://www.linux.org.ru/section-rss.jsp?section=5`, - Every: 2 * time.Hour, - }, - { - Name: "OpenNET", - URL: `http://www.opennet.ru/opennews/opennews_all_noadv.rss`, - Every: 4 * time.Hour, - }, - { - Name: "Undeadly", - URL: `http://undeadly.org/cgi?action=rss`, - Every: 2 * time.Hour, - }, - { - Name: "Kernel", - URL: `https://www.kernel.org/feeds/kdist.xml`, - Every: 6 * time.Hour, - }, - { - Name: "Ted Unangst", - URL: `http://www.tedunangst.com/flak/rss`, - Every: 6 * time.Hour, - }, - { - Name: "Calomel", - URL: `https://calomel.org/calomel_rss.xml`, - Every: 6 * time.Hour, - }, - { - Name: "Golang News", - URL: `https://golangnews.com/index.xml`, - Every: 6 * time.Hour, - }, - { - Name: "Golang Weekly", - URL: `http://golangweekly.com/rss/1fg21ahk`, - Every: 6 * time.Hour, - }, -} - type News struct { Feed rss.Item @@ -88,7 +30,7 @@ func (n News) String() string { return s } -func (f Feed) Watch(news chan News) { +func (f Feed) watch(news chan News) { ticker := time.NewTicker(f.Every) defer ticker.Stop() for t := range ticker.C { @@ -106,10 +48,10 @@ func (f Feed) Watch(news chan News) { } } -func watchNews(msg chan string) { +func Watch(msg chan string, feeds []Feed) { news := make(chan News) - for _, feed := range Feeds { - go feed.Watch(news) + for _, feed := range feeds { + go feed.watch(news) } for n := range news { msg <- fmt.Sprint(n) -- cgit v1.2.3 From 2edd25a655c9d0c908edae0b3c752630bde299ed Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Wed, 21 Dec 2016 00:47:29 +0100 Subject: go flood --- main.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/main.go b/main.go index cd1d751..45758b0 100644 --- a/main.go +++ b/main.go @@ -10,7 +10,7 @@ import ( const maxLen = 500 func notify(conn *irc.Conn, target string) chan string { - c := make(chan string) + c := make(chan string, 1) go func() { for msg := range c { log.Println("send", msg) @@ -24,7 +24,7 @@ func notify(conn *irc.Conn, target string) chan string { } func kicker(conn *irc.Conn, channel string) chan string { - c := make(chan string) + c := make(chan string, 1) go func() { for nick := range c { if nick != conn.Me().Nick { @@ -50,13 +50,15 @@ func discon(c chan struct{}) irc.HandlerFunc { func privmsg(n, k chan string, room string) irc.HandlerFunc { l := links(n) - return func(conn *irc.Conn, line *irc.Line) { - t := line.Text() - l <- t - if isFlood(t) { + f := func(line *irc.Line) { + if isFlood(line.Text()) { k <- line.Nick } } + return func(conn *irc.Conn, line *irc.Line) { + go f(line) + l <- line.Text() + } } func main() { -- cgit v1.2.3 From d3c97e413a8731bf61dba3f5a0fa9d8a62def0e5 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Wed, 21 Dec 2016 01:07:35 +0100 Subject: add ssl flag --- href.go | 1 + main.go | 18 +++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/href.go b/href.go index 9c67bb0..88c9680 100644 --- a/href.go +++ b/href.go @@ -71,6 +71,7 @@ func links(msg chan string) chan string { go func() { for l := range c { for _, v := range getLinks(l) { + log.Println("URL:", v) t, err := getTitle(v) if err != nil { log.Println(err) diff --git a/main.go b/main.go index 45758b0..ac44a7e 100644 --- a/main.go +++ b/main.go @@ -62,16 +62,20 @@ func privmsg(n, k chan string, room string) irc.HandlerFunc { } func main() { - node := flag.String("node", "irc.freenode.org:6667", "IRC Server") + node := flag.String("node", "irc.freenode.org", "IRC Server") + ssl := flag.Bool("ssl", false, "Use SSL") room := flag.String("room", "#lor", "IRC Channel") name := flag.String("name", "dim13", "Bots Name") flag.Parse() - c := irc.SimpleClient(*name) - //c.EnableStateTracking() // XXX + conf := irc.NewConfig(*name) + conf.Server = *node + conf.SSL = *ssl + conn := irc.Client(conf) + //conn.EnableStateTracking() // XXX done := make(chan struct{}) - n := notify(c, *room) - k := kicker(c, *room) + n := notify(conn, *room) + k := kicker(conn, *room) go Watch(n, Feeds) // TODO shall it be there? // setup event handler @@ -85,11 +89,11 @@ func main() { {irc.PRIVMSG, privmsg(n, k, *room)}, } for _, h := range handler { - c.HandleFunc(h.ev, h.f) + conn.HandleFunc(h.ev, h.f) } log.Println("Connect to", *node) - if err := c.ConnectTo(*node); err != nil { + if err := conn.Connect(); err != nil { log.Fatal(err) } -- cgit v1.2.3 From b4c6a6a35a9416ed57a636352fcc4152ff6f08bf Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Wed, 21 Dec 2016 01:10:24 +0100 Subject: cleanup --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index ac44a7e..a33ab2c 100644 --- a/main.go +++ b/main.go @@ -92,7 +92,7 @@ func main() { conn.HandleFunc(h.ev, h.f) } - log.Println("Connect to", *node) + log.Println("Connect to", conf.Server) if err := conn.Connect(); err != nil { log.Fatal(err) } -- cgit v1.2.3 From ddd7dba5aca6abc2ce70ba13456f09a0568209de Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Wed, 21 Dec 2016 01:12:35 +0100 Subject: regexp --- re.go | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 re.go diff --git a/re.go b/re.go new file mode 100644 index 0000000..6584c15 --- /dev/null +++ b/re.go @@ -0,0 +1,3 @@ +package main + +// TODO add regexp handler -- cgit v1.2.3 From 58981abe098c4e7062020de2332acaeb5fc6d5b1 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Wed, 21 Dec 2016 13:34:30 +0100 Subject: cleanup --- href.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/href.go b/href.go index 88c9680..0743807 100644 --- a/href.go +++ b/href.go @@ -11,7 +11,7 @@ import ( "golang.org/x/net/html/charset" ) -var errNotHTML = errors.New("not HTML content") +var errNotHTML = errors.New("Not HTML") func title(n *html.Node) (s string) { if n.Type == html.ElementNode && n.Data == "title" { -- cgit v1.2.3 From b114a48e677059e24e1e0cea4a424ebfda879a72 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sat, 24 Dec 2016 20:43:43 +0100 Subject: readd last --- main.go | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/main.go b/main.go index a33ab2c..e1fd32f 100644 --- a/main.go +++ b/main.go @@ -1,14 +1,36 @@ package main import ( + "container/ring" "flag" + "fmt" "log" + "time" irc "github.com/fluffle/goirc/client" ) const maxLen = 500 +var buffer = ring.New(10) + +func push(l *irc.Line) { + buffer.Value = l + buffer = buffer.Next() +} + +func last(target string) { + buffer.Do(func(v interface{}) { + if v != nil { + l := v.(*irc.Line) + s := fmt.Sprintf("%v <%v> %v", + l.Time.UTC().Format(time.Kitchen), + l.Nick, l.Text()) + conn.Notice(target, s) + } + }) +} + func notify(conn *irc.Conn, target string) chan string { c := make(chan string, 1) go func() { @@ -50,13 +72,15 @@ func discon(c chan struct{}) irc.HandlerFunc { func privmsg(n, k chan string, room string) irc.HandlerFunc { l := links(n) - f := func(line *irc.Line) { + return func(conn *irc.Conn, line *irc.Line) { if isFlood(line.Text()) { k <- line.Nick } - } - return func(conn *irc.Conn, line *irc.Line) { - go f(line) + if line.Text() == "last" { + last(line.Nick) + } else { + push(line) + } l <- line.Text() } } -- cgit v1.2.3 From 6f756f7f5e0f196476ea2b7910d38e6bab6e2f47 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sun, 25 Dec 2016 10:52:43 +0100 Subject: wip --- main.go | 97 +++++++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 32 deletions(-) diff --git a/main.go b/main.go index e1fd32f..79fd538 100644 --- a/main.go +++ b/main.go @@ -10,28 +10,61 @@ import ( irc "github.com/fluffle/goirc/client" ) -const maxLen = 500 +type bot struct { + room string + conn *irc.Conn + notice chan string + kick chan string + last *ring.Ring +} -var buffer = ring.New(10) +func New(name, node, room string, ssl bool) *bot { + conf := irc.NewConfig(name) + conf.Server = node + conf.SSL = ssl + conn := irc.Client(conf) + return &bot{ + room: room, + conn: conn, + notice: notify(conn, room), + kick: kicker(conn, room), + last: ring.New(10), + } +} -func push(l *irc.Line) { - buffer.Value = l - buffer = buffer.Next() +func (b *bot) push(line *irc.Line) { + b.last.Value = line + b.last = b.last.Next() +} + +func (b *bot) find(c chan string, nick string) { + var msg string + b.last.Do(func(v interface{}) { + if v != nil { + l := v.(*irc.Line) + if l.Nick == nick { + msg = l.Text() + } + } + }) + if msg != "" { + c <- msg + } } -func last(target string) { - buffer.Do(func(v interface{}) { +func (b *bot) lastMsgs(c chan string) { + b.last.Do(func(v interface{}) { if v != nil { l := v.(*irc.Line) - s := fmt.Sprintf("%v <%v> %v", + c <- fmt.Sprintf("%v <%v> %v", l.Time.UTC().Format(time.Kitchen), l.Nick, l.Text()) - conn.Notice(target, s) } }) } func notify(conn *irc.Conn, target string) chan string { + const maxLen = 500 c := make(chan string, 1) go func() { for msg := range c { @@ -58,9 +91,9 @@ func kicker(conn *irc.Conn, channel string) chan string { return c } -func join(room string) irc.HandlerFunc { +func (b *bot) join() irc.HandlerFunc { return func(conn *irc.Conn, _ *irc.Line) { - conn.Join(room) + conn.Join(b.room) } } @@ -70,16 +103,21 @@ func discon(c chan struct{}) irc.HandlerFunc { } } -func privmsg(n, k chan string, room string) irc.HandlerFunc { - l := links(n) +func (b *bot) privmsg() irc.HandlerFunc { + l := links(b.notice) return func(conn *irc.Conn, line *irc.Line) { if isFlood(line.Text()) { - k <- line.Nick + b.kick <- line.Nick } - if line.Text() == "last" { - last(line.Nick) - } else { - push(line) + switch line.Text() { + case "last": + c := notify(conn, line.Nick) + defer close(c) + b.lastMsgs(c) + case "find": + b.find(b.notice, line.Nick) + default: + b.push(line) } l <- line.Text() } @@ -92,15 +130,10 @@ func main() { name := flag.String("name", "dim13", "Bots Name") flag.Parse() - conf := irc.NewConfig(*name) - conf.Server = *node - conf.SSL = *ssl - conn := irc.Client(conf) - //conn.EnableStateTracking() // XXX + b := New(*name, *node, *room, *ssl) + done := make(chan struct{}) - n := notify(conn, *room) - k := kicker(conn, *room) - go Watch(n, Feeds) // TODO shall it be there? + go Watch(b.notice, Feeds) // TODO shall it be there? // setup event handler handler := []struct { @@ -108,19 +141,19 @@ func main() { f irc.HandlerFunc }{ {irc.DISCONNECTED, discon(done)}, - {irc.CONNECTED, join(*room)}, - {irc.KICK, join(*room)}, - {irc.PRIVMSG, privmsg(n, k, *room)}, + {irc.CONNECTED, b.join()}, + {irc.KICK, b.join()}, + {irc.PRIVMSG, b.privmsg()}, } for _, h := range handler { - conn.HandleFunc(h.ev, h.f) + b.conn.HandleFunc(h.ev, h.f) } - log.Println("Connect to", conf.Server) - if err := conn.Connect(); err != nil { + if err := b.conn.Connect(); err != nil { log.Fatal(err) } + log.Println("Connected") <-done log.Println("Disconnected") } -- cgit v1.2.3 From b6158fe79d01268a0033c2b220f1a104193290a4 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sun, 25 Dec 2016 11:03:13 +0100 Subject: Add RE stub --- re.go | 21 ++++++++++++++++++++- re_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 re_test.go diff --git a/re.go b/re.go index 6584c15..714afcf 100644 --- a/re.go +++ b/re.go @@ -1,3 +1,22 @@ package main -// TODO add regexp handler +import ( + "regexp" + "strings" +) + +func re(s, r string) string { + // min: s// + if len(r) < 3 || r[0] != 's' { + return "" + } + z := strings.Split(r[2:], string(r[1])) + if len(z) < 2 { + return "" + } + re, err := regexp.Compile(z[0]) + if err != nil { + return "" + } + return re.ReplaceAllString(s, z[1]) +} diff --git a/re_test.go b/re_test.go new file mode 100644 index 0000000..447c60f --- /dev/null +++ b/re_test.go @@ -0,0 +1,28 @@ +package main + +import "testing" + +func TestRE(t *testing.T) { + testCases := []struct { + r, s, x string + }{ + {"s/ddd/xxx/", "abd ddd xxx", "abd xxx xxx"}, + {"s,ddd,xxx,", "abd ddd xxx", "abd xxx xxx"}, + {"s/ddd/xxx", "abd ddd xxx", "abd xxx xxx"}, + {"s/x$/X", "abd ddd xxx", "abd ddd xxX"}, + {"s/ /A", "abd ddd xxx", "abdAdddAxxx"}, + {"s///", "abd ddd xxx", "abd ddd xxx"}, + {"s//", "abd ddd xxx", "abd ddd xxx"}, + {"s/", "abd ddd xxx", ""}, + {"S//", "abd ddd xxx", ""}, + {"s/^d/X", "abd ddd xxx", "abd ddd xxx"}, + } + for _, tc := range testCases { + t.Run(tc.r, func(t *testing.T) { + res := re(tc.s, tc.r) + if res != tc.x { + t.Errorf("got %q, want %q", res, tc.x) + } + }) + } +} -- cgit v1.2.3 From 1c780ab0000890760bc923fc9322dd8462e83fa1 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sun, 25 Dec 2016 14:31:37 +0100 Subject: Split last --- href.go | 8 ++--- last.go | 49 +++++++++++++++++++++++++ main.go | 126 +++++++++++++++++++--------------------------------------------- 3 files changed, 89 insertions(+), 94 deletions(-) create mode 100644 last.go diff --git a/href.go b/href.go index 0743807..b18b3f3 100644 --- a/href.go +++ b/href.go @@ -66,18 +66,18 @@ func getLinks(s string) (ret []string) { return } -func links(msg chan string) chan string { - c := make(chan string) +func linker(out chan string) chan string { + c := make(chan string, 1) go func() { for l := range c { for _, v := range getLinks(l) { - log.Println("URL:", v) + log.Println("URL", v) t, err := getTitle(v) if err != nil { log.Println(err) } if t != "" { - msg <- fmt.Sprintf("Title: %v", t) + out <- fmt.Sprintf("Title: %v", t) } } } diff --git a/last.go b/last.go new file mode 100644 index 0000000..34a3022 --- /dev/null +++ b/last.go @@ -0,0 +1,49 @@ +package main + +import ( + "container/ring" + "fmt" + "time" +) + +type Msg struct { + Time time.Time + Nick string + Text string +} + +type LastBuf struct { + *ring.Ring +} + +func NewLastBuf(n int) *LastBuf { + return &LastBuf{ring.New(n)} +} + +func (v *LastBuf) Push(t time.Time, nick, text string) { + v.Value = Msg{Time: t, Nick: nick, Text: text} + v.Ring = v.Next() +} + +// walk through buffer and find last message +func (v *LastBuf) Last(nick string) string { + var msg string + v.Do(func(v interface{}) { + if l, ok := v.(Msg); ok { + if l.Nick == nick { + msg = l.Text + } + } + }) + return msg +} + +func (v *LastBuf) Dump(c chan string) { + v.Do(func(v interface{}) { + if l, ok := v.(Msg); ok { + c <- fmt.Sprintf("%v <%v> %v", + l.Time.UTC().Format(time.Kitchen), + l.Nick, l.Text) + } + }) +} diff --git a/main.go b/main.go index 79fd538..82940ff 100644 --- a/main.go +++ b/main.go @@ -1,77 +1,23 @@ package main import ( - "container/ring" "flag" "fmt" "log" - "time" + "strings" irc "github.com/fluffle/goirc/client" ) -type bot struct { - room string - conn *irc.Conn - notice chan string - kick chan string - last *ring.Ring -} - -func New(name, node, room string, ssl bool) *bot { - conf := irc.NewConfig(name) - conf.Server = node - conf.SSL = ssl - conn := irc.Client(conf) - return &bot{ - room: room, - conn: conn, - notice: notify(conn, room), - kick: kicker(conn, room), - last: ring.New(10), - } -} - -func (b *bot) push(line *irc.Line) { - b.last.Value = line - b.last = b.last.Next() -} - -func (b *bot) find(c chan string, nick string) { - var msg string - b.last.Do(func(v interface{}) { - if v != nil { - l := v.(*irc.Line) - if l.Nick == nick { - msg = l.Text() - } - } - }) - if msg != "" { - c <- msg - } -} - -func (b *bot) lastMsgs(c chan string) { - b.last.Do(func(v interface{}) { - if v != nil { - l := v.(*irc.Line) - c <- fmt.Sprintf("%v <%v> %v", - l.Time.UTC().Format(time.Kitchen), - l.Nick, l.Text()) - } - }) -} - func notify(conn *irc.Conn, target string) chan string { const maxLen = 500 c := make(chan string, 1) go func() { for msg := range c { - log.Println("send", msg) if len(msg) > maxLen { msg = msg[:maxLen] + "..." } + log.Println("send", msg) conn.Notice(target, msg) } }() @@ -91,9 +37,9 @@ func kicker(conn *irc.Conn, channel string) chan string { return c } -func (b *bot) join() irc.HandlerFunc { +func join(room string) irc.HandlerFunc { return func(conn *irc.Conn, _ *irc.Line) { - conn.Join(b.room) + conn.Join(room) } } @@ -103,23 +49,30 @@ func discon(c chan struct{}) irc.HandlerFunc { } } -func (b *bot) privmsg() irc.HandlerFunc { - l := links(b.notice) +func privmsg(note, kick chan string) irc.HandlerFunc { + last := NewLastBuf(10) + links := linker(note) + go Watch(note, Feeds) return func(conn *irc.Conn, line *irc.Line) { - if isFlood(line.Text()) { - b.kick <- line.Nick - } - switch line.Text() { - case "last": + switch t := line.Text(); { + case isFlood(t): + kick <- line.Nick + case t == "last": c := notify(conn, line.Nick) - defer close(c) - b.lastMsgs(c) - case "find": - b.find(b.notice, line.Nick) + last.Dump(c) + close(c) + case strings.HasPrefix(t, "s"): + tofix := last.Last(line.Nick) + if fixed := re(tofix, t); fixed != "" { + note <- fmt.Sprintf("%v meant to say: %v", + line.Nick, fixed) + return + } + fallthrough default: - b.push(line) + links <- t + last.Push(line.Time, line.Nick, t) } - l <- line.Text() } } @@ -130,30 +83,23 @@ func main() { name := flag.String("name", "dim13", "Bots Name") flag.Parse() - b := New(*name, *node, *room, *ssl) + conf := irc.NewConfig(*name) + conf.Server = *node + conf.SSL = *ssl + conn := irc.Client(conf) + + note := notify(conn, *room) + kick := kicker(conn, *room) done := make(chan struct{}) - go Watch(b.notice, Feeds) // TODO shall it be there? - // setup event handler - handler := []struct { - ev string - f irc.HandlerFunc - }{ - {irc.DISCONNECTED, discon(done)}, - {irc.CONNECTED, b.join()}, - {irc.KICK, b.join()}, - {irc.PRIVMSG, b.privmsg()}, - } - for _, h := range handler { - b.conn.HandleFunc(h.ev, h.f) - } + conn.HandleFunc(irc.DISCONNECTED, discon(done)) + conn.HandleFunc(irc.CONNECTED, join(*room)) + conn.HandleFunc(irc.KICK, join(*room)) + conn.HandleFunc(irc.PRIVMSG, privmsg(note, kick)) - if err := b.conn.Connect(); err != nil { + if err := conn.Connect(); err != nil { log.Fatal(err) } - - log.Println("Connected") <-done - log.Println("Disconnected") } -- cgit v1.2.3 From b646b6d6b5d6715fe80d3eb508c8bcda937145b9 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sun, 25 Dec 2016 14:44:18 +0100 Subject: kiss --- main.go | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/main.go b/main.go index 82940ff..2ff436c 100644 --- a/main.go +++ b/main.go @@ -37,22 +37,9 @@ func kicker(conn *irc.Conn, channel string) chan string { return c } -func join(room string) irc.HandlerFunc { - return func(conn *irc.Conn, _ *irc.Line) { - conn.Join(room) - } -} - -func discon(c chan struct{}) irc.HandlerFunc { - return func(_ *irc.Conn, _ *irc.Line) { - close(c) - } -} - func privmsg(note, kick chan string) irc.HandlerFunc { last := NewLastBuf(10) links := linker(note) - go Watch(note, Feeds) return func(conn *irc.Conn, line *irc.Line) { switch t := line.Text(); { case isFlood(t): @@ -93,11 +80,21 @@ func main() { done := make(chan struct{}) - conn.HandleFunc(irc.DISCONNECTED, discon(done)) - conn.HandleFunc(irc.CONNECTED, join(*room)) - conn.HandleFunc(irc.KICK, join(*room)) + conn.HandleFunc(irc.DISCONNECTED, func(_ *irc.Conn, _ *irc.Line) { + close(done) + }) + + conn.HandleFunc(irc.CONNECTED, func(conn *irc.Conn, _ *irc.Line) { + conn.Join(*room) + go Watch(note, Feeds) + }) + conn.HandleFunc(irc.PRIVMSG, privmsg(note, kick)) + conn.HandleFunc(irc.KICK, func(conn *irc.Conn, _ *irc.Line) { + conn.Join(*room) + }) + if err := conn.Connect(); err != nil { log.Fatal(err) } -- cgit v1.2.3 From 422a15a09efd2d44fe53c5ce2c46bc8b5aee08e6 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sun, 25 Dec 2016 14:51:25 +0100 Subject: last --- last.go | 12 ++++++------ main.go | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/last.go b/last.go index 34a3022..50524dd 100644 --- a/last.go +++ b/last.go @@ -12,21 +12,21 @@ type Msg struct { Text string } -type LastBuf struct { +type Last struct { *ring.Ring } -func NewLastBuf(n int) *LastBuf { - return &LastBuf{ring.New(n)} +func NewLast(n int) *Last { + return &Last{ring.New(n)} } -func (v *LastBuf) Push(t time.Time, nick, text string) { +func (v *Last) Push(t time.Time, nick, text string) { v.Value = Msg{Time: t, Nick: nick, Text: text} v.Ring = v.Next() } // walk through buffer and find last message -func (v *LastBuf) Last(nick string) string { +func (v *Last) Last(nick string) string { var msg string v.Do(func(v interface{}) { if l, ok := v.(Msg); ok { @@ -38,7 +38,7 @@ func (v *LastBuf) Last(nick string) string { return msg } -func (v *LastBuf) Dump(c chan string) { +func (v *Last) Dump(c chan string) { v.Do(func(v interface{}) { if l, ok := v.(Msg); ok { c <- fmt.Sprintf("%v <%v> %v", diff --git a/main.go b/main.go index 2ff436c..e2fd650 100644 --- a/main.go +++ b/main.go @@ -38,7 +38,7 @@ func kicker(conn *irc.Conn, channel string) chan string { } func privmsg(note, kick chan string) irc.HandlerFunc { - last := NewLastBuf(10) + last := NewLast(10) links := linker(note) return func(conn *irc.Conn, line *irc.Line) { switch t := line.Text(); { -- cgit v1.2.3 From 384585ae8848a5f16d570c5febf16eaa7b2084c6 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sun, 25 Dec 2016 15:15:38 +0100 Subject: minor fixes --- href.go | 2 +- re.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/href.go b/href.go index b18b3f3..bd4cec6 100644 --- a/href.go +++ b/href.go @@ -56,7 +56,7 @@ func getTitle(uri string) (string, error) { func getLinks(s string) (ret []string) { for _, v := range strings.Fields(s) { switch { - case strings.HasPrefix(v, "www"): + case strings.HasPrefix(v, "www."): v = "http://" + v fallthrough case strings.HasPrefix(v, "http:"), strings.HasPrefix(v, "https:"): diff --git a/re.go b/re.go index 714afcf..90a9fda 100644 --- a/re.go +++ b/re.go @@ -11,7 +11,8 @@ func re(s, r string) string { return "" } z := strings.Split(r[2:], string(r[1])) - if len(z) < 2 { + // match s// and s/// + if len(z) < 2 || len(z) > 3 { return "" } re, err := regexp.Compile(z[0]) -- cgit v1.2.3 From f8ad03a76772ada7dc2b46adf8d485c6c1d17e4c Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sun, 25 Dec 2016 15:28:47 +0100 Subject: add rate stub --- rate.go | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 rate.go diff --git a/rate.go b/rate.go new file mode 100644 index 0000000..c4c9668 --- /dev/null +++ b/rate.go @@ -0,0 +1,3 @@ +package main + +// TODO rate limiting -- cgit v1.2.3 From fc1b0999a35bba9760d9d58395fb04581784c160 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sun, 25 Dec 2016 16:45:15 +0100 Subject: watchlist --- main.go | 3 +++ rate.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/main.go b/main.go index e2fd650..c884fe5 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "strings" + "time" irc "github.com/fluffle/goirc/client" ) @@ -40,6 +41,7 @@ func kicker(conn *irc.Conn, channel string) chan string { func privmsg(note, kick chan string) irc.HandlerFunc { last := NewLast(10) links := linker(note) + wl := NewWatchList(3, 5*time.Second) return func(conn *irc.Conn, line *irc.Line) { switch t := line.Text(); { case isFlood(t): @@ -59,6 +61,7 @@ func privmsg(note, kick chan string) irc.HandlerFunc { default: links <- t last.Push(line.Time, line.Nick, t) + wl.Add(kick, line.Nick) } } } diff --git a/rate.go b/rate.go index c4c9668..a4b630e 100644 --- a/rate.go +++ b/rate.go @@ -1,3 +1,37 @@ package main +import ( + "sync" + "time" +) + // TODO rate limiting + +type WatchList struct { + sync.Mutex + n int + d time.Duration + list map[string]int +} + +func NewWatchList(n int, d time.Duration) WatchList { + return WatchList{n: n, d: d, list: make(map[string]int)} +} + +func (w WatchList) Add(kick chan string, nick string) { + w.Lock() + defer w.Unlock() + if _, ok := w.list[nick]; !ok { + go func() { + <-time.After(w.d) + w.Lock() + delete(w.list, nick) + w.Unlock() + }() + } + w.list[nick]++ + if w.list[nick] > w.n { + kick <- nick + } + return +} -- cgit v1.2.3 From a04048625848c4aeab33e3e2dce24e006ebe59e1 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sun, 25 Dec 2016 17:30:34 +0100 Subject: Bump # of messages per second --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index c884fe5..b2e3abf 100644 --- a/main.go +++ b/main.go @@ -41,7 +41,7 @@ func kicker(conn *irc.Conn, channel string) chan string { func privmsg(note, kick chan string) irc.HandlerFunc { last := NewLast(10) links := linker(note) - wl := NewWatchList(3, 5*time.Second) + wl := NewWatchList(5, 5*time.Second) return func(conn *irc.Conn, line *irc.Line) { switch t := line.Text(); { case isFlood(t): -- cgit v1.2.3 From 5d506643a6b543d46d18f3ec832f84f094a4f438 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Mon, 26 Dec 2016 05:03:32 +0100 Subject: Tweak --- main.go | 4 ++-- re.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index b2e3abf..68965b1 100644 --- a/main.go +++ b/main.go @@ -41,7 +41,7 @@ func kicker(conn *irc.Conn, channel string) chan string { func privmsg(note, kick chan string) irc.HandlerFunc { last := NewLast(10) links := linker(note) - wl := NewWatchList(5, 5*time.Second) + wl := NewWatchList(3, 5*time.Second) return func(conn *irc.Conn, line *irc.Line) { switch t := line.Text(); { case isFlood(t): @@ -50,7 +50,7 @@ func privmsg(note, kick chan string) irc.HandlerFunc { c := notify(conn, line.Nick) last.Dump(c) close(c) - case strings.HasPrefix(t, "s"): + case strings.HasPrefix(t, "s/"): tofix := last.Last(line.Nick) if fixed := re(tofix, t); fixed != "" { note <- fmt.Sprintf("%v meant to say: %v", diff --git a/re.go b/re.go index 90a9fda..9429ac8 100644 --- a/re.go +++ b/re.go @@ -7,7 +7,7 @@ import ( func re(s, r string) string { // min: s// - if len(r) < 3 || r[0] != 's' { + if len(s) < 3 { return "" } z := strings.Split(r[2:], string(r[1])) -- cgit v1.2.3 From e144aa0bc9a66b2314f57b9344697d429049944f Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Tue, 27 Dec 2016 17:11:02 +0100 Subject: wip --- main.go | 2 +- rate.go | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/main.go b/main.go index 68965b1..ea85c63 100644 --- a/main.go +++ b/main.go @@ -41,7 +41,7 @@ func kicker(conn *irc.Conn, channel string) chan string { func privmsg(note, kick chan string) irc.HandlerFunc { last := NewLast(10) links := linker(note) - wl := NewWatchList(3, 5*time.Second) + wl := NewWatchList(2, time.Second) return func(conn *irc.Conn, line *irc.Line) { switch t := line.Text(); { case isFlood(t): diff --git a/rate.go b/rate.go index a4b630e..0ab03ac 100644 --- a/rate.go +++ b/rate.go @@ -1,6 +1,7 @@ package main import ( + "log" "sync" "time" ) @@ -21,17 +22,21 @@ func NewWatchList(n int, d time.Duration) WatchList { func (w WatchList) Add(kick chan string, nick string) { w.Lock() defer w.Unlock() + if _, ok := w.list[nick]; !ok { go func() { <-time.After(w.d) w.Lock() + defer w.Unlock() + log.Println(w.list[nick], "clear", nick) delete(w.list, nick) - w.Unlock() }() } - w.list[nick]++ + + log.Println(w.list[nick], "hit", nick) if w.list[nick] > w.n { kick <- nick } - return + + w.list[nick]++ } -- cgit v1.2.3 From 64f84d0b79ef09b1d6f7f8cc94f9108bdcdb2ae0 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Tue, 27 Dec 2016 17:16:07 +0100 Subject: Fix test --- re_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/re_test.go b/re_test.go index 447c60f..ef89847 100644 --- a/re_test.go +++ b/re_test.go @@ -14,7 +14,6 @@ func TestRE(t *testing.T) { {"s///", "abd ddd xxx", "abd ddd xxx"}, {"s//", "abd ddd xxx", "abd ddd xxx"}, {"s/", "abd ddd xxx", ""}, - {"S//", "abd ddd xxx", ""}, {"s/^d/X", "abd ddd xxx", "abd ddd xxx"}, } for _, tc := range testCases { -- cgit v1.2.3 From 01d5301e77b4054223d21289a17ace48539cbeb6 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Mon, 6 Mar 2017 11:14:21 +0100 Subject: Drop watchlist --- main.go | 3 --- rate.go | 42 ------------------------------------------ 2 files changed, 45 deletions(-) delete mode 100644 rate.go diff --git a/main.go b/main.go index ea85c63..802fc8f 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,6 @@ import ( "fmt" "log" "strings" - "time" irc "github.com/fluffle/goirc/client" ) @@ -41,7 +40,6 @@ func kicker(conn *irc.Conn, channel string) chan string { func privmsg(note, kick chan string) irc.HandlerFunc { last := NewLast(10) links := linker(note) - wl := NewWatchList(2, time.Second) return func(conn *irc.Conn, line *irc.Line) { switch t := line.Text(); { case isFlood(t): @@ -61,7 +59,6 @@ func privmsg(note, kick chan string) irc.HandlerFunc { default: links <- t last.Push(line.Time, line.Nick, t) - wl.Add(kick, line.Nick) } } } diff --git a/rate.go b/rate.go deleted file mode 100644 index 0ab03ac..0000000 --- a/rate.go +++ /dev/null @@ -1,42 +0,0 @@ -package main - -import ( - "log" - "sync" - "time" -) - -// TODO rate limiting - -type WatchList struct { - sync.Mutex - n int - d time.Duration - list map[string]int -} - -func NewWatchList(n int, d time.Duration) WatchList { - return WatchList{n: n, d: d, list: make(map[string]int)} -} - -func (w WatchList) Add(kick chan string, nick string) { - w.Lock() - defer w.Unlock() - - if _, ok := w.list[nick]; !ok { - go func() { - <-time.After(w.d) - w.Lock() - defer w.Unlock() - log.Println(w.list[nick], "clear", nick) - delete(w.list, nick) - }() - } - - log.Println(w.list[nick], "hit", nick) - if w.list[nick] > w.n { - kick <- nick - } - - w.list[nick]++ -} -- cgit v1.2.3 From 0d651bca8901257683f5fe366e840bb59f8fd84d Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sun, 31 Dec 2017 23:43:39 +0100 Subject: remove unnecessary stuff --- feeds.go | 30 ------------------------------ last.go | 49 ------------------------------------------------- main.go | 16 ---------------- re.go | 23 ----------------------- re_test.go | 27 --------------------------- 5 files changed, 145 deletions(-) delete mode 100644 last.go delete mode 100644 re.go delete mode 100644 re_test.go diff --git a/feeds.go b/feeds.go index 9e6412e..6950194 100644 --- a/feeds.go +++ b/feeds.go @@ -28,34 +28,4 @@ var Feeds = []Feed{ URL: `http://www.opennet.ru/opennews/opennews_all_noadv.rss`, Every: 4 * time.Hour, }, - { - Name: "Undeadly", - URL: `http://undeadly.org/cgi?action=rss`, - Every: 2 * time.Hour, - }, - { - Name: "Kernel", - URL: `https://www.kernel.org/feeds/kdist.xml`, - Every: 6 * time.Hour, - }, - { - Name: "Ted Unangst", - URL: `http://www.tedunangst.com/flak/rss`, - Every: 6 * time.Hour, - }, - { - Name: "Calomel", - URL: `https://calomel.org/calomel_rss.xml`, - Every: 6 * time.Hour, - }, - { - Name: "Golang News", - URL: `https://golangnews.com/index.xml`, - Every: 6 * time.Hour, - }, - { - Name: "Golang Weekly", - URL: `http://golangweekly.com/rss/1fg21ahk`, - Every: 6 * time.Hour, - }, } diff --git a/last.go b/last.go deleted file mode 100644 index 50524dd..0000000 --- a/last.go +++ /dev/null @@ -1,49 +0,0 @@ -package main - -import ( - "container/ring" - "fmt" - "time" -) - -type Msg struct { - Time time.Time - Nick string - Text string -} - -type Last struct { - *ring.Ring -} - -func NewLast(n int) *Last { - return &Last{ring.New(n)} -} - -func (v *Last) Push(t time.Time, nick, text string) { - v.Value = Msg{Time: t, Nick: nick, Text: text} - v.Ring = v.Next() -} - -// walk through buffer and find last message -func (v *Last) Last(nick string) string { - var msg string - v.Do(func(v interface{}) { - if l, ok := v.(Msg); ok { - if l.Nick == nick { - msg = l.Text - } - } - }) - return msg -} - -func (v *Last) Dump(c chan string) { - v.Do(func(v interface{}) { - if l, ok := v.(Msg); ok { - c <- fmt.Sprintf("%v <%v> %v", - l.Time.UTC().Format(time.Kitchen), - l.Nick, l.Text) - } - }) -} diff --git a/main.go b/main.go index 802fc8f..d7c6e38 100644 --- a/main.go +++ b/main.go @@ -2,9 +2,7 @@ package main import ( "flag" - "fmt" "log" - "strings" irc "github.com/fluffle/goirc/client" ) @@ -38,27 +36,13 @@ func kicker(conn *irc.Conn, channel string) chan string { } func privmsg(note, kick chan string) irc.HandlerFunc { - last := NewLast(10) links := linker(note) return func(conn *irc.Conn, line *irc.Line) { switch t := line.Text(); { case isFlood(t): kick <- line.Nick - case t == "last": - c := notify(conn, line.Nick) - last.Dump(c) - close(c) - case strings.HasPrefix(t, "s/"): - tofix := last.Last(line.Nick) - if fixed := re(tofix, t); fixed != "" { - note <- fmt.Sprintf("%v meant to say: %v", - line.Nick, fixed) - return - } - fallthrough default: links <- t - last.Push(line.Time, line.Nick, t) } } } diff --git a/re.go b/re.go deleted file mode 100644 index 9429ac8..0000000 --- a/re.go +++ /dev/null @@ -1,23 +0,0 @@ -package main - -import ( - "regexp" - "strings" -) - -func re(s, r string) string { - // min: s// - if len(s) < 3 { - return "" - } - z := strings.Split(r[2:], string(r[1])) - // match s// and s/// - if len(z) < 2 || len(z) > 3 { - return "" - } - re, err := regexp.Compile(z[0]) - if err != nil { - return "" - } - return re.ReplaceAllString(s, z[1]) -} diff --git a/re_test.go b/re_test.go deleted file mode 100644 index ef89847..0000000 --- a/re_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import "testing" - -func TestRE(t *testing.T) { - testCases := []struct { - r, s, x string - }{ - {"s/ddd/xxx/", "abd ddd xxx", "abd xxx xxx"}, - {"s,ddd,xxx,", "abd ddd xxx", "abd xxx xxx"}, - {"s/ddd/xxx", "abd ddd xxx", "abd xxx xxx"}, - {"s/x$/X", "abd ddd xxx", "abd ddd xxX"}, - {"s/ /A", "abd ddd xxx", "abdAdddAxxx"}, - {"s///", "abd ddd xxx", "abd ddd xxx"}, - {"s//", "abd ddd xxx", "abd ddd xxx"}, - {"s/", "abd ddd xxx", ""}, - {"s/^d/X", "abd ddd xxx", "abd ddd xxx"}, - } - for _, tc := range testCases { - t.Run(tc.r, func(t *testing.T) { - res := re(tc.s, tc.r) - if res != tc.x { - t.Errorf("got %q, want %q", res, tc.x) - } - }) - } -} -- cgit v1.2.3 From e663cdca3df5471ffbf7bfc2d329e7780e5ccf6f Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Mon, 1 Jan 2018 09:48:16 +0100 Subject: 10M limit --- href.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/href.go b/href.go index bd4cec6..a4cc5c9 100644 --- a/href.go +++ b/href.go @@ -11,7 +11,10 @@ import ( "golang.org/x/net/html/charset" ) -var errNotHTML = errors.New("Not HTML") +var ( + errNotHTML = errors.New("Not HTML") + errTooBig = errors.New("Content too big") +) func title(n *html.Node) (s string) { if n.Type == html.ElementNode && n.Data == "title" { @@ -40,6 +43,10 @@ func getTitle(uri string) (string, error) { return "", errNotHTML } + if resp.ContentLength > 10*1024*1024 { + return "", errTooBig + } + r, err := charset.NewReader(resp.Body, ct) if err != nil { return "", err -- cgit v1.2.3