summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2018-01-01 09:49:01 +0100
committerDimitri Sokolyuk <demon@dim13.org>2018-01-01 09:49:01 +0100
commit2e61e20da46d10af33a84a18dc2e1b77e43002b3 (patch)
tree7245894614a2c5c294cd48047f3d2b2a2cf4ccea
parent50d3b0f4927c3fc4b92cc368062ce2bf42e1a99d (diff)
parente663cdca3df5471ffbf7bfc2d329e7780e5ccf6f (diff)
Merge branch 'kiss'
-rw-r--r--blame.go26
-rw-r--r--command.go32
-rw-r--r--duck.go28
-rw-r--r--feeds.go31
-rw-r--r--help.go29
-rw-r--r--href.go47
-rw-r--r--href_test.go2
-rw-r--r--last.go37
-rw-r--r--main.go85
-rw-r--r--rss.go77
-rw-r--r--urban.go33
11 files changed, 146 insertions, 281 deletions
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 <demon@dim13.org>",
- "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/command.go b/command.go
deleted file mode 100644
index 9f20c45..0000000
--- a/command.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package main
-
-import (
- "fmt"
- "log"
- "strings"
-
- irc "github.com/fluffle/goirc/client"
-)
-
-type Commander interface {
- irc.Handler
- fmt.Stringer
-}
-
-const maxLen = 500
-
-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/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/feeds.go b/feeds.go
new file mode 100644
index 0000000..6950194
--- /dev/null
+++ b/feeds.go
@@ -0,0 +1,31 @@
+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,
+ },
+}
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..a4cc5c9 100644
--- a/href.go
+++ b/href.go
@@ -2,16 +2,19 @@ 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")
+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" {
@@ -28,7 +31,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
@@ -40,6 +43,10 @@ func findTitle(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
@@ -53,26 +60,34 @@ 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 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"):
- go func(uri string) {
- log.Println(line.Nick, uri)
- t, err := findTitle(uri)
+ case strings.HasPrefix(v, "http:"), strings.HasPrefix(v, "https:"):
+ ret = append(ret, v)
+ }
+ }
+ return
+}
+
+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)
+ 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)
+ out <- fmt.Sprintf("Title: %v", t)
}
- }(v)
+ }
}
- }
+ }()
+ return c
}
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/last.go b/last.go
deleted file mode 100644
index 8cf12fa..0000000
--- a/last.go
+++ /dev/null
@@ -1,37 +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 (Last) String() string {
- return "Return last 10 messages"
-}
-
-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 84b0d6b..d7c6e38 100644
--- a/main.go
+++ b/main.go
@@ -7,45 +7,80 @@ import (
irc "github.com/fluffle/goirc/client"
)
+func notify(conn *irc.Conn, target string) chan string {
+ const maxLen = 500
+ c := make(chan string, 1)
+ go func() {
+ for msg := range c {
+ if len(msg) > maxLen {
+ msg = msg[:maxLen] + "..."
+ }
+ log.Println("send", msg)
+ conn.Notice(target, msg)
+ }
+ }()
+ return c
+}
+
+func kicker(conn *irc.Conn, channel string) chan string {
+ c := make(chan string, 1)
+ go func() {
+ for nick := range c {
+ if nick != conn.Me().Nick {
+ log.Println("kick", nick)
+ conn.Kick(channel, nick)
+ }
+ }
+ }()
+ return c
+}
+
+func privmsg(note, kick chan string) irc.HandlerFunc {
+ links := linker(note)
+ return func(conn *irc.Conn, line *irc.Line) {
+ switch t := line.Text(); {
+ case isFlood(t):
+ kick <- line.Nick
+ default:
+ links <- t
+ }
+ }
+}
+
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()
+ conf := irc.NewConfig(*name)
+ conf.Server = *node
+ conf.SSL = *ssl
+ conn := irc.Client(conf)
- discon := make(chan struct{})
- c.HandleFunc(irc.DISCONNECTED, func(conn *irc.Conn, line *irc.Line) {
- close(discon)
- })
+ note := notify(conn, *room)
+ kick := kicker(conn, *room)
- c.HandleFunc(irc.CONNECTED, func(conn *irc.Conn, line *irc.Line) {
- conn.Join(*room)
- ShowNews(conn, *room)
+ done := make(chan struct{})
+
+ conn.HandleFunc(irc.DISCONNECTED, func(_ *irc.Conn, _ *irc.Line) {
+ close(done)
})
- c.HandleFunc(irc.KICK, func(conn *irc.Conn, line *irc.Line) {
+ conn.HandleFunc(irc.CONNECTED, func(conn *irc.Conn, _ *irc.Line) {
conn.Join(*room)
+ go Watch(note, Feeds)
})
- c.HandleFunc(irc.PRIVMSG, func(conn *irc.Conn, line *irc.Line) {
- go Dispatch(conn, line)
- go ExtractLinks(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)
- }
+ conn.HandleFunc(irc.PRIVMSG, privmsg(note, kick))
+
+ conn.HandleFunc(irc.KICK, func(conn *irc.Conn, _ *irc.Line) {
+ conn.Join(*room)
})
- log.Println("Connect to", *node)
- if err := c.ConnectTo(*node); err != nil {
+ if err := conn.Connect(); err != nil {
log.Fatal(err)
}
- <-discon
- log.Println("Disconnected")
+ <-done
}
diff --git a/rss.go b/rss.go
index 143c82b..6f5239b 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 {
@@ -15,34 +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: 5 * 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,
- },
-}
-
type News struct {
Feed
rss.Item
@@ -59,32 +30,30 @@ func (n News) String() string {
return s
}
-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}
- }
- }
+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}
}
- }(f)
+ }
}
+}
- go func() {
- for n := range news {
- conn.Notice(room, n.String())
- }
- }()
+func Watch(msg chan string, feeds []Feed) {
+ news := make(chan News)
+ for _, feed := range feeds {
+ go feed.watch(news)
+ }
+ for n := range news {
+ msg <- fmt.Sprint(n)
+ }
}
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{})
-}