mirror/merlin/arthur/arthur.go

115 lines
2.7 KiB
Go

package arthur
import (
"bytes"
"errors"
"fmt"
"io"
"net"
"os"
"path/filepath"
"strings"
"text/tabwriter"
"time"
"git.csclub.uwaterloo.ca/public/merlin/config"
"git.csclub.uwaterloo.ca/public/merlin/logger"
"git.csclub.uwaterloo.ca/public/merlin/sync"
)
// get repo by name function in config
func GetAndRunCommand(conn net.Conn) (newSync bool) {
newSync = false
defer conn.Close()
var buf bytes.Buffer
_, err := io.Copy(&buf, conn)
if err != nil {
logger.ErrLog(err.Error())
return
}
command := buf.String()
args := strings.Split(command, ":")
respondAndLogErr := func(msg string) {
logger.OutLog(msg)
conn.Write([]byte(msg))
}
if args[0] == "status" {
status := tabwriter.NewWriter(conn, 5, 5, 5, ' ', 0)
fmt.Fprintf(status, "Repository\tLast Synced\tNext Expected Sync\n")
// for time formating see https://pkg.go.dev/time#pkg-constants
for name, repo := range config.RepoMap {
fmt.Fprintf(status, "%s\t%s\t%s\n",
name,
time.Unix(repo.State.LastAttemptStartTime, 0).Format(time.RFC1123),
time.Unix(repo.State.LastAttemptRunTime+int64(repo.Frequency), 0).Format(time.RFC1123),
)
}
status.Flush()
} else if args[0] == "sync" {
if len(args) != 2 {
respondAndLogErr("Could not parse sync command, forced sync fails.")
return
}
if repo, inMap := config.RepoMap[args[1]]; inMap {
logger.OutLog("Attempting to force sync of " + repo.Name)
if sync.SyncIfPossible(repo) {
conn.Write([]byte("Forced sync for " + repo.Name))
newSync = true
} else {
respondAndLogErr("Cannot force sync: " + repo.Name + ", already syncing.")
}
} else {
respondAndLogErr(args[1] + " is not tracked so cannot sync")
}
} else {
respondAndLogErr("Received unrecognized command: " + command)
}
return
}
func UnixSockListener(connChan chan net.Conn, stopLisChan chan struct{}) {
sockpath := config.Conf.SockPath
// must remove cfg.SockPath otherwise get "bind: address already in use"
if filepath.Ext(sockpath) != ".sock" {
panic(fmt.Errorf("Socket file must end with .sock"))
} else if _, err := os.Stat(sockpath); err == nil {
if err := os.Remove(sockpath); err != nil {
panic(err)
}
} else if !errors.Is(err, os.ErrNotExist) {
panic(err)
}
ear, err := net.Listen("unix", sockpath)
if err != nil {
panic(err)
}
logger.OutLog("Listening to unix socket at " + sockpath)
go func() {
for {
// will exit when ear is closed
conn, err := ear.Accept()
if err != nil {
if ne, ok := err.(net.Error); ok && ne.Temporary() {
logger.ErrLog("Accepted socket error: " + err.Error())
continue
}
logger.ErrLog("Unhandlable socket error: " + err.Error())
return
}
connChan <- conn
}
}()
<-stopLisChan
ear.Close()
}