- commit
- b3a222b
- parent
- 53d8d00
- author
- Neale Pickett
- date
- 2016-01-18 18:09:29 -0700 MST
Add the handler program call
4 files changed,
+111,
-57
+3,
-5
1@@ -3,10 +3,10 @@ package main
2 import (
3 "strconv"
4 "strings"
5- "fmt"
6 )
7
8 type Message struct {
9+ Unparsed string
10 Command string
11 FullSender string
12 Sender string
13@@ -20,6 +20,7 @@ func NewMessage(v string) (Message, error) {
14 var parts []string
15 var lhs string
16
17+ m.Unparsed = v
18 parts = strings.SplitN(v, " :", 2)
19 if len(parts) == 2 {
20 lhs = parts[0]
21@@ -98,11 +99,9 @@ func NewMessage(v string) (Message, error) {
22 }
23
24 func (m Message) String() string {
25- args := strings.Join(m.Args, " ")
26- return fmt.Sprintf("%s %s %s %s %s :%s", m.FullSender, m.Command, m.Sender, m.Forum, args, m.Text)
27+ return m.Unparsed
28 }
29
30-
31 func SplitTarget(s string) (string, string, string) {
32 var parts []string
33
34@@ -130,4 +129,3 @@ func IsChannel(s string) bool {
35 return false
36 }
37 }
38-
+45,
-24
1@@ -3,6 +3,7 @@ package main
2 import (
3 "fmt"
4 "os"
5+ "log"
6 "path"
7 "time"
8 )
9@@ -13,17 +14,54 @@ type Logfile struct {
10 name string
11 nlines int
12 maxlines int
13+ outq chan string
14+}
15+
16+func timestamp(s string) string {
17+ ret := fmt.Sprintf("%d %s", time.Now().Unix(), s)
18+ return ret
19 }
20
21 func NewLogfile(baseDir string, maxlines int) (*Logfile) {
22- return &Logfile{baseDir, nil, "", 0, maxlines}
23+ lf := Logfile{baseDir, nil, "", 0, maxlines, make(chan string, 50)}
24+ go lf.processQueue();
25+ return &lf
26 }
27
28 func (lf *Logfile) Close() {
29 if lf.file != nil {
30- lf.writeln("EXIT")
31- lf.file.Close()
32+ lf.Log("EXIT")
33+ close(lf.outq)
34+ }
35+}
36+
37+func (lf *Logfile) Log(s string) error {
38+ lf.outq <- timestamp(s)
39+ return nil
40+}
41+
42+//
43+//
44+
45+func (lf *Logfile) processQueue() {
46+ for line := range lf.outq {
47+ if (lf.file == nil) || (lf.nlines >= lf.maxlines) {
48+ if err := lf.rotate(); err != nil {
49+ // Just keep trying, I guess.
50+ log.Print(err)
51+ continue
52+ }
53+ lf.nlines = 0
54+ }
55+
56+ if _, err := fmt.Fprintln(lf.file, line); err != nil {
57+ log.Print(err)
58+ continue
59+ }
60+ lf.nlines += 1
61 }
62+
63+ lf.file.Close()
64 }
65
66 func (lf *Logfile) writeln(s string) error {
67@@ -52,8 +90,8 @@ func (lf *Logfile) rotate() error {
68
69 if lf.file != nil {
70 // Note location of new log
71- logmsg := fmt.Sprintf(". NEXTLOG %s", fn)
72- lf.writeln(logmsg)
73+ logmsg := fmt.Sprintf("NEXTLOG %s", fn)
74+ lf.writeln(timestamp(logmsg))
75
76 // All done with the current log
77 lf.file.Close()
78@@ -66,27 +104,10 @@ func (lf *Logfile) rotate() error {
79 os.Remove(currentPath)
80 os.Symlink(fn, currentPath)
81
82- logmsg := fmt.Sprintf(". PREVLOG %s", lf.name)
83- lf.writeln(logmsg)
84+ logmsg := fmt.Sprintf("PREVLOG %s", lf.name)
85+ lf.writeln(timestamp(logmsg))
86
87 lf.name = fn
88
89 return nil
90 }
91-
92-func (lf *Logfile) Log(s string) error {
93- if lf.file == nil {
94- lf.rotate()
95- }
96-
97- err := lf.writeln(s)
98- if err == nil {
99- return err
100- }
101-
102- if lf.nlines >= lf.maxlines {
103- return lf.rotate()
104- }
105-
106- return nil
107-}
+53,
-26
1@@ -9,6 +9,7 @@ import (
2 "net"
3 "os"
4 "os/user"
5+ "os/exec"
6 "path"
7 "strings"
8 "time"
9@@ -48,7 +49,9 @@ type Network struct {
10 serverIndex int
11
12 conn io.ReadWriteCloser
13- logq chan Message
14+
15+ logf *Logfile
16+
17 inq chan string
18 outq chan string
19 }
20@@ -57,23 +60,21 @@ func NewNetwork(basePath string) *Network {
21 nw := Network{
22 running: true,
23 basePath: basePath,
24- logq: make(chan Message, 20),
25 }
26-
27- go nw.LogLoop()
28+ nw.logf = NewLogfile(nw.basePath, int(maxlogsize))
29
30 return &nw
31 }
32
33 func (nw *Network) Close() {
34 nw.running = false
35- close(nw.logq)
36 if nw.conn != nil {
37 nw.conn.Close()
38 }
39+ nw.logf.Close()
40 }
41
42-func (nw *Network) WatchOutqDirectory() {
43+func (nw *Network) watchOutqDirectory() {
44 outqDirname := path.Join(nw.basePath, "outq")
45
46 dir, err := os.Open(outqDirname)
47@@ -113,20 +114,12 @@ func (nw *Network) HandleInfile(fn string) {
48 }
49 }
50
51-func (nw *Network) LogLoop() {
52- logf := NewLogfile(nw.basePath, int(maxlogsize))
53- defer logf.Close()
54-
55- for m := range nw.logq {
56- logf.Log(m.String())
57- }
58-}
59-
60-func (nw *Network) ServerWriteLoop() {
61+func (nw *Network) serverWriteLoop() {
62 for v := range nw.outq {
63- m, _ := NewMessage(v)
64- nw.logq <- m
65+ debug("ยป %s", v)
66+ nw.logf.Log(v)
67 fmt.Fprintln(nw.conn, v)
68+ time.Sleep(500 * time.Millisecond)
69 }
70 }
71
72@@ -163,21 +156,21 @@ func (nw *Network) JoinChannels() {
73 }
74
75 for _, ch := range chans {
76+ debug("Joining %s", ch)
77 nw.outq <- "JOIN " + ch
78 }
79 }
80
81-func (nw *Network) MessageDispatch() {
82+func (nw *Network) messageDispatchLoop() {
83 for line := range nw.inq {
84+ nw.logf.Log(line)
85+
86 m, err := NewMessage(line)
87 if err != nil {
88 log.Print(err)
89 continue
90 }
91
92- nw.logq <- m
93- // XXX: Add in a handler subprocess call
94-
95 switch m.Command {
96 case "PING":
97 nw.outq <- "PONG :" + m.Text
98@@ -186,6 +179,30 @@ func (nw *Network) MessageDispatch() {
99 case "433":
100 nw.NextNick()
101 }
102+
103+ handlerPath := path.Join(nw.basePath, "handler")
104+ cmd := exec.Command(handlerPath, m.Args...)
105+ cmd.Env = []string{
106+ "command=" + m.Command,
107+ "fullsender=" + m.FullSender,
108+ "sender=" + m.Sender,
109+ "forum=" + m.Forum,
110+ "text=" + m.Text,
111+ "raw=" + line,
112+ }
113+ cmd.Stderr = os.Stderr
114+ out, err := cmd.Output()
115+ if err != nil {
116+ log.Print(err)
117+ continue
118+ }
119+
120+ if len(out) > 0 {
121+ outlines := strings.Split(string(out), "\n")
122+ for _, line := range outlines {
123+ nw.outq <- line
124+ }
125+ }
126 }
127 }
128
129@@ -201,6 +218,7 @@ func (nw *Network) ConnectToNextServer() bool {
130 }
131 server := servers[nw.serverIndex]
132
133+ debug("Connecting to %s", server)
134 switch (server[0]) {
135 case '|':
136 parts := strings.Split(server[1:], " ")
137@@ -219,6 +237,7 @@ func (nw *Network) ConnectToNextServer() bool {
138 log.Print(err)
139 return false
140 }
141+ debug("Connected")
142
143 return true
144 }
145@@ -246,8 +265,15 @@ func (nw *Network) login() {
146 nw.NextNick()
147 }
148
149+func (nw *Network) keepaliveLoop() {
150+ for nw.running {
151+ time.Sleep(1 * time.Minute)
152+ nw.outq <- "PING :keepalive"
153+ }
154+}
155+
156
157-func (nw *Network) Connect(){
158+func (nw *Network) Connect() {
159 for nw.running {
160 if ! nw.ConnectToNextServer() {
161 time.Sleep(8 * time.Second)
162@@ -257,9 +283,10 @@ func (nw *Network) Connect(){
163 nw.inq = make(chan string, 20)
164 nw.outq = make(chan string, 20)
165
166- go nw.ServerWriteLoop()
167- go nw.MessageDispatch()
168- go nw.WatchOutqDirectory()
169+ go nw.serverWriteLoop()
170+ go nw.messageDispatchLoop()
171+ go nw.watchOutqDirectory()
172+ go nw.keepaliveLoop()
173
174 nw.login()
175
+10,
-2
1@@ -11,8 +11,15 @@ import (
2 )
3
4 var running bool = true
5+var verbose bool = false
6 var maxlogsize uint
7
8+func debug(format string, a ...interface{}) {
9+ if verbose {
10+ log.Printf(format, a...)
11+ }
12+}
13+
14 func exists(filename string) bool {
15 _, err := os.Stat(filename); if err != nil {
16 return false
17@@ -78,8 +85,9 @@ func usage() {
18
19 func main() {
20 flag.Usage = usage
21- flag.UintVar(&maxlogsize, "logsize", 1000, "Log entries before rotating")
22- notime := flag.Bool("notime", false, "Don't timestamp log messages")
23+ flag.UintVar(&maxlogsize, "logsize", 6000, "Log entries before rotating")
24+ flag.BoolVar(&verbose, "verbose", false, "Verbose logging")
25+ notime := flag.Bool("notime", false, "Don't timestamp debugging messages")
26 flag.Parse()
27 if flag.NArg() != 1 {
28 usage()