mirror/merlin/arthur/arthur.go

137 lines
3.3 KiB
Go
Raw Normal View History

2021-12-11 18:28:09 -05:00
package arthur
import (
"errors"
"fmt"
2021-12-15 01:18:52 -05:00
"io/ioutil"
2021-12-11 18:28:09 -05:00
"net"
"os"
"path/filepath"
2021-12-15 01:18:52 -05:00
"sort"
2021-12-11 18:28:09 -05:00
"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"
)
2021-12-15 01:18:52 -05:00
// Reads and parses the message sent over the accepted connection
func GetCommand(conn net.Conn) (command, repoName string) {
command = ""
repoName = ""
2021-12-11 18:28:09 -05:00
2021-12-15 01:18:52 -05:00
buf, err := ioutil.ReadAll(conn)
2021-12-11 18:28:09 -05:00
if err != nil {
logger.ErrLog(err.Error())
return
}
2021-12-15 01:18:52 -05:00
args := strings.Split(string(buf), ":")
if len(args) >= 1 {
command = args[0]
}
if len(args) >= 2 {
repoName = args[1]
2021-12-11 18:28:09 -05:00
}
2021-12-15 01:18:52 -05:00
return
}
2021-12-11 18:28:09 -05:00
2021-12-15 01:18:52 -05:00
func SendAndLog(conn net.Conn, msg string) {
logger.OutLog(msg)
conn.Write([]byte(msg))
}
2021-12-11 18:28:09 -05:00
2021-12-15 01:18:52 -05:00
func SendStatus(conn net.Conn) {
2022-01-07 17:49:59 -05:00
// Force arthur to send back time information in America/Toronto time
location, err := time.LoadLocation("America/Toronto")
if err != nil {
logger.ErrLog(err)
}
2021-12-15 01:18:52 -05:00
status := tabwriter.NewWriter(conn, 5, 5, 5, ' ', 0)
fmt.Fprintf(status, "Repository\tLast Synced\tNext Expected Sync\tRunning\n")
2021-12-11 18:28:09 -05:00
2021-12-15 01:18:52 -05:00
keys := make([]string, 0)
for name, _ := range config.RepoMap {
keys = append(keys, name)
}
sort.Strings(keys)
// for other ways to format the time see: https://pkg.go.dev/time#pkg-constants
for _, name := range keys {
repo := config.RepoMap[name]
lastSync := repo.State.LastAttemptStartTime
nextSync := lastSync + int64(repo.Frequency)
fmt.Fprintf(status, "%s\t%s\t%s\t%t\n",
name,
2022-01-07 17:49:59 -05:00
time.Unix(lastSync, 0).In(location).Format(time.RFC1123),
time.Unix(nextSync, 0).In(location).Format(time.RFC1123),
2021-12-15 01:18:52 -05:00
repo.State.IsRunning,
)
}
status.Flush()
}
// Attempt to force the sync of the repo
func ForceSync(conn net.Conn, repoName string) (newSync bool) {
newSync = false
// TODO: send repoName and every key in RepoMap to lowercase
if repo, isInMap := config.RepoMap[repoName]; isInMap {
logger.OutLog("Attempting to force sync of " + repoName)
if sync.SyncIfPossible(repo) {
conn.Write([]byte("Forced sync for " + repoName))
newSync = true
2021-12-11 18:28:09 -05:00
} else {
2021-12-15 01:18:52 -05:00
SendAndLog(conn, "Could not force sync: "+repoName+" is already syncing.")
2021-12-11 18:28:09 -05:00
}
} else {
2021-12-15 01:18:52 -05:00
SendAndLog(conn, repoName+" is not tracked so cannot sync")
2021-12-11 18:28:09 -05:00
}
return
}
2021-12-15 01:18:52 -05:00
func StartListener(connChan chan net.Conn, stopLisChan chan struct{}) {
2021-12-11 18:28:09 -05:00
sockpath := config.Conf.SockPath
2021-12-15 01:18:52 -05:00
// must remove old cfg.SockPath otherwise get "bind: address already in use"
2021-12-11 18:28:09 -05:00
if filepath.Ext(sockpath) != ".sock" {
2021-12-15 01:18:52 -05:00
panic(fmt.Errorf("socket file must end with .sock"))
2021-12-11 18:28:09 -05:00
} 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 {
2021-12-15 01:18:52 -05:00
// Attempting to accept on a closed net.Listener will return a non-temporary error
2021-12-11 18:28:09 -05:00
conn, err := ear.Accept()
if err != nil {
2021-12-15 01:18:52 -05:00
if netErr, isTemp := err.(net.Error); isTemp && netErr.Temporary() {
2021-12-11 18:28:09 -05:00
logger.ErrLog("Accepted socket error: " + err.Error())
continue
}
logger.ErrLog("Unhandlable socket error: " + err.Error())
return
}
connChan <- conn
}
}()
2021-12-15 01:18:52 -05:00
// TODO: check handling of multiple SIGHUP
2021-12-11 18:28:09 -05:00
<-stopLisChan
ear.Close()
}