Browse Source

nc compatible /send endpoint, DRY-ed dispatcher

tags/v0.3.0
Richard Jones 7 years ago
parent
commit
d9ed25352a
5 changed files with 67 additions and 48 deletions
  1. 5
    3
      README.md
  2. 1
    1
      dispatcher/colours.go
  3. 46
    0
      dispatcher/dispatcher.go
  4. 13
    14
      httplistener/generic.go
  5. 2
    30
      tcplistener/tcplistener.go

+ 5
- 3
README.md View File

@@ -38,10 +38,12 @@ IRC formatting is supported (see a full [list of codes](tcplistener/colours.go#L
38 38
     echo "Status is%GREEN OK %NORMAL" | nc irccat-host 12345
39 39
 
40 40
 ## HTTP → IRC
41
-There's a simple HTTP endpoint for sending messages:
41
+There's a similar HTTP endpoint for sending messages. You can use curl in lieu
42
+of netcat, with "-d @-" to read POST data from stdin, like so:
42 43
 
43
-    curl -X POST http://irccat-host:8045/send -d
44
-        '{"to": "#channel", "body": "Hello world"}'
44
+    echo "Hello world" | curl -d @- http://irccat-host/send
45
+
46
+Everything that works via netcat also works by POST to /send.
45 47
 
46 48
 There are also endpoints which support app-specific webhooks, currently:
47 49
 

tcplistener/colours.go → dispatcher/colours.go View File

@@ -1,4 +1,4 @@
1
-package tcplistener
1
+package dispatcher
2 2
 
3 3
 import "strings"
4 4
 

+ 46
- 0
dispatcher/dispatcher.go View File

@@ -0,0 +1,46 @@
1
+package dispatcher
2
+
3
+import (
4
+	"github.com/juju/loggo"
5
+	"github.com/spf13/viper"
6
+	"github.com/thoj/go-ircevent"
7
+	"strings"
8
+)
9
+
10
+// Take a string, parse out the recipients, and send to IRC.
11
+//
12
+// eg:
13
+//  hello world                 [goes to default channel]
14
+//  #test hello world           [goes to #test, if joined]
15
+//  #test,@alice hello world    [goes to #test and alice]
16
+//  #* hello world              [goes to all channels bot is in]
17
+func Send(irc *irc.Connection, msg string, log loggo.Logger, origin string) {
18
+	channels := viper.GetStringSlice("irc.channels")
19
+
20
+	if msg[0] == '#' || msg[0] == '@' {
21
+		parts := strings.SplitN(msg, " ", 2)
22
+		if parts[0] == "#*" {
23
+			for _, channel := range channels {
24
+				irc.Privmsg(channel, replaceFormatting(parts[1]))
25
+			}
26
+		} else {
27
+			targets := strings.Split(parts[0], ",")
28
+			for _, target := range targets {
29
+				if target[0] == '@' {
30
+					target = target[1:]
31
+				}
32
+				irc.Privmsg(target, replaceFormatting(parts[1]))
33
+			}
34
+		}
35
+		log.Infof("from[%s] send[%s] %s", origin, parts[0], parts[1])
36
+	} else if len(msg) > 7 && msg[0:6] == "%TOPIC" {
37
+		parts := strings.SplitN(msg, " ", 3)
38
+		irc.SendRawf("TOPIC %s :%s", parts[1], replaceFormatting(parts[2]))
39
+		log.Infof("from[%s] topic[%s] %s", origin, parts[1], parts[2])
40
+	} else {
41
+		if len(channels) > 0 {
42
+			irc.Privmsg(channels[0], replaceFormatting(msg))
43
+			log.Infof("from[%s] send_default[%s] %s", origin, channels[0], msg)
44
+		}
45
+	}
46
+}

+ 13
- 14
httplistener/generic.go View File

@@ -2,29 +2,28 @@ package httplistener
2 2
 
3 3
 import (
4 4
 	"bytes"
5
-	"encoding/json"
5
+	"github.com/irccloud/irccat/dispatcher"
6 6
 	"net/http"
7 7
 )
8 8
 
9
-type genericMessage struct {
10
-	To   string
11
-	Body string
12
-}
13
-
9
+// Examples of using curl to post to /send.
10
+//
11
+// echo "Hello, world" | curl -d @- http://irccat.example.com/send
12
+// echo "#test,@alice Hello, world" | curl -d @- http://irccat.example.com/send
13
+//
14 14
 func (hl *HTTPListener) genericHandler(w http.ResponseWriter, request *http.Request) {
15 15
 	if request.Method != "POST" {
16 16
 		http.NotFound(w, request)
17 17
 		return
18 18
 	}
19 19
 
20
-	var message genericMessage
21
-	buf := new(bytes.Buffer)
22
-	buf.ReadFrom(request.Body)
23
-	json.Unmarshal(buf.Bytes(), &message)
20
+	body := new(bytes.Buffer)
21
+	body.ReadFrom(request.Body)
22
+	message := body.String()
24 23
 
25
-	log.Infof("%s [%s] %s", request.RemoteAddr, message.To, message.Body)
26
-
27
-	if message.To != "" && message.Body != "" {
28
-		hl.irc.Privmsgf(message.To, message.Body)
24
+	if message == "" {
25
+		log.Warningf("%s - No message body in POST request", request.RemoteAddr)
26
+		return
29 27
 	}
28
+	dispatcher.Send(hl.irc, message, log, request.RemoteAddr)
30 29
 }

+ 2
- 30
tcplistener/tcplistener.go View File

@@ -2,6 +2,7 @@ package tcplistener
2 2
 
3 3
 import (
4 4
 	"bufio"
5
+	"github.com/irccloud/irccat/dispatcher"
5 6
 	"github.com/juju/loggo"
6 7
 	"github.com/spf13/viper"
7 8
 	"github.com/thoj/go-ircevent"
@@ -54,37 +55,8 @@ func (l *TCPListener) handleConnection(conn net.Conn) {
54 55
 		}
55 56
 		msg = strings.Trim(msg, "\r\n")
56 57
 		if len(msg) > 0 {
57
-			log.Infof("[%s] message: %s", conn.RemoteAddr(), msg)
58
-			l.parseMessage(msg)
58
+			dispatcher.Send(l.irc, msg, log, conn.RemoteAddr().String())
59 59
 		}
60 60
 	}
61 61
 	conn.Close()
62 62
 }
63
-
64
-func (l *TCPListener) parseMessage(msg string) {
65
-	channels := viper.GetStringSlice("irc.channels")
66
-
67
-	if msg[0] == '#' || msg[0] == '@' {
68
-		parts := strings.SplitN(msg, " ", 2)
69
-		if parts[0] == "#*" {
70
-			for _, channel := range channels {
71
-				l.irc.Privmsg(channel, replaceFormatting(parts[1]))
72
-			}
73
-		} else {
74
-			targets := strings.Split(parts[0], ",")
75
-			for _, target := range targets {
76
-				if target[0] == '@' {
77
-					target = target[1:]
78
-				}
79
-				l.irc.Privmsg(target, replaceFormatting(parts[1]))
80
-			}
81
-		}
82
-	} else if len(msg) > 7 && msg[0:6] == "%TOPIC" {
83
-		parts := strings.SplitN(msg, " ", 3)
84
-		l.irc.SendRawf("TOPIC %s :%s", parts[1], replaceFormatting(parts[2]))
85
-	} else {
86
-		if len(channels) > 0 {
87
-			l.irc.Privmsg(channels[0], replaceFormatting(msg))
88
-		}
89
-	}
90
-}

Loading…
Cancel
Save