mirror of https://github.com/nealey/spongy
Add the handler program call
This commit is contained in:
parent
53d8d003b4
commit
b3a222ba88
|
@ -3,10 +3,10 @@ package main
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
|
Unparsed string
|
||||||
Command string
|
Command string
|
||||||
FullSender string
|
FullSender string
|
||||||
Sender string
|
Sender string
|
||||||
|
@ -20,6 +20,7 @@ func NewMessage(v string) (Message, error) {
|
||||||
var parts []string
|
var parts []string
|
||||||
var lhs string
|
var lhs string
|
||||||
|
|
||||||
|
m.Unparsed = v
|
||||||
parts = strings.SplitN(v, " :", 2)
|
parts = strings.SplitN(v, " :", 2)
|
||||||
if len(parts) == 2 {
|
if len(parts) == 2 {
|
||||||
lhs = parts[0]
|
lhs = parts[0]
|
||||||
|
@ -98,11 +99,9 @@ func NewMessage(v string) (Message, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m Message) String() string {
|
func (m Message) String() string {
|
||||||
args := strings.Join(m.Args, " ")
|
return m.Unparsed
|
||||||
return fmt.Sprintf("%s %s %s %s %s :%s", m.FullSender, m.Command, m.Sender, m.Forum, args, m.Text)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func SplitTarget(s string) (string, string, string) {
|
func SplitTarget(s string) (string, string, string) {
|
||||||
var parts []string
|
var parts []string
|
||||||
|
|
||||||
|
@ -130,4 +129,3 @@ func IsChannel(s string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"log"
|
||||||
"path"
|
"path"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -13,19 +14,56 @@ type Logfile struct {
|
||||||
name string
|
name string
|
||||||
nlines int
|
nlines int
|
||||||
maxlines int
|
maxlines int
|
||||||
|
outq chan string
|
||||||
|
}
|
||||||
|
|
||||||
|
func timestamp(s string) string {
|
||||||
|
ret := fmt.Sprintf("%d %s", time.Now().Unix(), s)
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLogfile(baseDir string, maxlines int) (*Logfile) {
|
func NewLogfile(baseDir string, maxlines int) (*Logfile) {
|
||||||
return &Logfile{baseDir, nil, "", 0, maxlines}
|
lf := Logfile{baseDir, nil, "", 0, maxlines, make(chan string, 50)}
|
||||||
|
go lf.processQueue();
|
||||||
|
return &lf
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lf *Logfile) Close() {
|
func (lf *Logfile) Close() {
|
||||||
if lf.file != nil {
|
if lf.file != nil {
|
||||||
lf.writeln("EXIT")
|
lf.Log("EXIT")
|
||||||
lf.file.Close()
|
close(lf.outq)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (lf *Logfile) Log(s string) error {
|
||||||
|
lf.outq <- timestamp(s)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
func (lf *Logfile) processQueue() {
|
||||||
|
for line := range lf.outq {
|
||||||
|
if (lf.file == nil) || (lf.nlines >= lf.maxlines) {
|
||||||
|
if err := lf.rotate(); err != nil {
|
||||||
|
// Just keep trying, I guess.
|
||||||
|
log.Print(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lf.nlines = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := fmt.Fprintln(lf.file, line); err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lf.nlines += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
lf.file.Close()
|
||||||
|
}
|
||||||
|
|
||||||
func (lf *Logfile) writeln(s string) error {
|
func (lf *Logfile) writeln(s string) error {
|
||||||
_, err := fmt.Fprintf(lf.file, "%d %s\n", time.Now().Unix(), s)
|
_, err := fmt.Fprintf(lf.file, "%d %s\n", time.Now().Unix(), s)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -52,8 +90,8 @@ func (lf *Logfile) rotate() error {
|
||||||
|
|
||||||
if lf.file != nil {
|
if lf.file != nil {
|
||||||
// Note location of new log
|
// Note location of new log
|
||||||
logmsg := fmt.Sprintf(". NEXTLOG %s", fn)
|
logmsg := fmt.Sprintf("NEXTLOG %s", fn)
|
||||||
lf.writeln(logmsg)
|
lf.writeln(timestamp(logmsg))
|
||||||
|
|
||||||
// All done with the current log
|
// All done with the current log
|
||||||
lf.file.Close()
|
lf.file.Close()
|
||||||
|
@ -66,27 +104,10 @@ func (lf *Logfile) rotate() error {
|
||||||
os.Remove(currentPath)
|
os.Remove(currentPath)
|
||||||
os.Symlink(fn, currentPath)
|
os.Symlink(fn, currentPath)
|
||||||
|
|
||||||
logmsg := fmt.Sprintf(". PREVLOG %s", lf.name)
|
logmsg := fmt.Sprintf("PREVLOG %s", lf.name)
|
||||||
lf.writeln(logmsg)
|
lf.writeln(timestamp(logmsg))
|
||||||
|
|
||||||
lf.name = fn
|
lf.name = fn
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lf *Logfile) Log(s string) error {
|
|
||||||
if lf.file == nil {
|
|
||||||
lf.rotate()
|
|
||||||
}
|
|
||||||
|
|
||||||
err := lf.writeln(s)
|
|
||||||
if err == nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if lf.nlines >= lf.maxlines {
|
|
||||||
return lf.rotate()
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -48,7 +49,9 @@ type Network struct {
|
||||||
serverIndex int
|
serverIndex int
|
||||||
|
|
||||||
conn io.ReadWriteCloser
|
conn io.ReadWriteCloser
|
||||||
logq chan Message
|
|
||||||
|
logf *Logfile
|
||||||
|
|
||||||
inq chan string
|
inq chan string
|
||||||
outq chan string
|
outq chan string
|
||||||
}
|
}
|
||||||
|
@ -57,23 +60,21 @@ func NewNetwork(basePath string) *Network {
|
||||||
nw := Network{
|
nw := Network{
|
||||||
running: true,
|
running: true,
|
||||||
basePath: basePath,
|
basePath: basePath,
|
||||||
logq: make(chan Message, 20),
|
|
||||||
}
|
}
|
||||||
|
nw.logf = NewLogfile(nw.basePath, int(maxlogsize))
|
||||||
go nw.LogLoop()
|
|
||||||
|
|
||||||
return &nw
|
return &nw
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nw *Network) Close() {
|
func (nw *Network) Close() {
|
||||||
nw.running = false
|
nw.running = false
|
||||||
close(nw.logq)
|
|
||||||
if nw.conn != nil {
|
if nw.conn != nil {
|
||||||
nw.conn.Close()
|
nw.conn.Close()
|
||||||
}
|
}
|
||||||
|
nw.logf.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nw *Network) WatchOutqDirectory() {
|
func (nw *Network) watchOutqDirectory() {
|
||||||
outqDirname := path.Join(nw.basePath, "outq")
|
outqDirname := path.Join(nw.basePath, "outq")
|
||||||
|
|
||||||
dir, err := os.Open(outqDirname)
|
dir, err := os.Open(outqDirname)
|
||||||
|
@ -113,20 +114,12 @@ func (nw *Network) HandleInfile(fn string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nw *Network) LogLoop() {
|
func (nw *Network) serverWriteLoop() {
|
||||||
logf := NewLogfile(nw.basePath, int(maxlogsize))
|
|
||||||
defer logf.Close()
|
|
||||||
|
|
||||||
for m := range nw.logq {
|
|
||||||
logf.Log(m.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (nw *Network) ServerWriteLoop() {
|
|
||||||
for v := range nw.outq {
|
for v := range nw.outq {
|
||||||
m, _ := NewMessage(v)
|
debug("» %s", v)
|
||||||
nw.logq <- m
|
nw.logf.Log(v)
|
||||||
fmt.Fprintln(nw.conn, v)
|
fmt.Fprintln(nw.conn, v)
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,21 +156,21 @@ func (nw *Network) JoinChannels() {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ch := range chans {
|
for _, ch := range chans {
|
||||||
|
debug("Joining %s", ch)
|
||||||
nw.outq <- "JOIN " + ch
|
nw.outq <- "JOIN " + ch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (nw *Network) MessageDispatch() {
|
func (nw *Network) messageDispatchLoop() {
|
||||||
for line := range nw.inq {
|
for line := range nw.inq {
|
||||||
|
nw.logf.Log(line)
|
||||||
|
|
||||||
m, err := NewMessage(line)
|
m, err := NewMessage(line)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
nw.logq <- m
|
|
||||||
// XXX: Add in a handler subprocess call
|
|
||||||
|
|
||||||
switch m.Command {
|
switch m.Command {
|
||||||
case "PING":
|
case "PING":
|
||||||
nw.outq <- "PONG :" + m.Text
|
nw.outq <- "PONG :" + m.Text
|
||||||
|
@ -186,6 +179,30 @@ func (nw *Network) MessageDispatch() {
|
||||||
case "433":
|
case "433":
|
||||||
nw.NextNick()
|
nw.NextNick()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handlerPath := path.Join(nw.basePath, "handler")
|
||||||
|
cmd := exec.Command(handlerPath, m.Args...)
|
||||||
|
cmd.Env = []string{
|
||||||
|
"command=" + m.Command,
|
||||||
|
"fullsender=" + m.FullSender,
|
||||||
|
"sender=" + m.Sender,
|
||||||
|
"forum=" + m.Forum,
|
||||||
|
"text=" + m.Text,
|
||||||
|
"raw=" + line,
|
||||||
|
}
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
out, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Print(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(out) > 0 {
|
||||||
|
outlines := strings.Split(string(out), "\n")
|
||||||
|
for _, line := range outlines {
|
||||||
|
nw.outq <- line
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,6 +218,7 @@ func (nw *Network) ConnectToNextServer() bool {
|
||||||
}
|
}
|
||||||
server := servers[nw.serverIndex]
|
server := servers[nw.serverIndex]
|
||||||
|
|
||||||
|
debug("Connecting to %s", server)
|
||||||
switch (server[0]) {
|
switch (server[0]) {
|
||||||
case '|':
|
case '|':
|
||||||
parts := strings.Split(server[1:], " ")
|
parts := strings.Split(server[1:], " ")
|
||||||
|
@ -219,6 +237,7 @@ func (nw *Network) ConnectToNextServer() bool {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
debug("Connected")
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -246,6 +265,13 @@ func (nw *Network) login() {
|
||||||
nw.NextNick()
|
nw.NextNick()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (nw *Network) keepaliveLoop() {
|
||||||
|
for nw.running {
|
||||||
|
time.Sleep(1 * time.Minute)
|
||||||
|
nw.outq <- "PING :keepalive"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func (nw *Network) Connect() {
|
func (nw *Network) Connect() {
|
||||||
for nw.running {
|
for nw.running {
|
||||||
|
@ -257,9 +283,10 @@ func (nw *Network) Connect(){
|
||||||
nw.inq = make(chan string, 20)
|
nw.inq = make(chan string, 20)
|
||||||
nw.outq = make(chan string, 20)
|
nw.outq = make(chan string, 20)
|
||||||
|
|
||||||
go nw.ServerWriteLoop()
|
go nw.serverWriteLoop()
|
||||||
go nw.MessageDispatch()
|
go nw.messageDispatchLoop()
|
||||||
go nw.WatchOutqDirectory()
|
go nw.watchOutqDirectory()
|
||||||
|
go nw.keepaliveLoop()
|
||||||
|
|
||||||
nw.login()
|
nw.login()
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,15 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var running bool = true
|
var running bool = true
|
||||||
|
var verbose bool = false
|
||||||
var maxlogsize uint
|
var maxlogsize uint
|
||||||
|
|
||||||
|
func debug(format string, a ...interface{}) {
|
||||||
|
if verbose {
|
||||||
|
log.Printf(format, a...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func exists(filename string) bool {
|
func exists(filename string) bool {
|
||||||
_, err := os.Stat(filename); if err != nil {
|
_, err := os.Stat(filename); if err != nil {
|
||||||
return false
|
return false
|
||||||
|
@ -78,8 +85,9 @@ func usage() {
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.Usage = usage
|
flag.Usage = usage
|
||||||
flag.UintVar(&maxlogsize, "logsize", 1000, "Log entries before rotating")
|
flag.UintVar(&maxlogsize, "logsize", 6000, "Log entries before rotating")
|
||||||
notime := flag.Bool("notime", false, "Don't timestamp log messages")
|
flag.BoolVar(&verbose, "verbose", false, "Verbose logging")
|
||||||
|
notime := flag.Bool("notime", false, "Don't timestamp debugging messages")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if flag.NArg() != 1 {
|
if flag.NArg() != 1 {
|
||||||
usage()
|
usage()
|
||||||
|
|
Loading…
Reference in New Issue