// Helper copied to the remote host to run commands and deploy configuration
// Copyright (C) 2021-2023 Simon Ruderich
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
package remote
import (
"fmt"
"log"
"os"
"golang.org/x/term"
"ruderich.org/simon/safcm"
"ruderich.org/simon/safcm/remote/ainsl"
"ruderich.org/simon/safcm/remote/info"
"ruderich.org/simon/safcm/remote/run"
"ruderich.org/simon/safcm/remote/sync"
)
func usage() {
log.Fatalf("usage: %[1]s sync\n"+
"usage: %[1]s ainsl [options] ",
os.Args[0])
}
func Main() {
// Timestamps are added by `safcm`
log.SetFlags(0)
if len(os.Args) < 2 {
usage()
}
var err error
switch os.Args[1] {
case "sync":
if len(os.Args) != 2 {
usage()
}
err = mainLoop()
case "ainsl":
err = ainsl.Main(os.Args)
default:
usage()
}
if err != nil {
log.Fatalf("%s: %v", os.Args[0], err)
}
}
func mainLoop() error {
if term.IsTerminal(int(os.Stdin.Fd())) ||
term.IsTerminal(int(os.Stdout.Fd())) {
return fmt.Errorf("sync should only be called from `safcm` " +
"(redirect stdin/stdout to circumvent this check)")
}
conn := safcm.NewGobConn(os.Stdin, os.Stdout)
var logLevel safcm.LogLevel
logFunc := func(level safcm.LogLevel, msg string) {
if logLevel >= level {
// Handling errors here is complex and quite verbose.
// If it happens the connection is gone anyway so skip
// the error handling.
conn.Send(safcm.MsgLog{ //nolint:errcheck
Level: level,
Text: msg,
})
}
}
var quitResp safcm.MsgQuitResp
for {
x, err := conn.Recv()
if err != nil {
return err
}
var resp safcm.Msg
switch x := x.(type) {
case safcm.MsgInfoReq:
logLevel = x.LogLevel // set log level globally
resp = info.Handle(x, run.ExecRunner{}, logFunc)
case safcm.MsgSyncReq:
resp = sync.Handle(x, run.ExecRunner{}, logFunc)
case safcm.MsgQuitReq:
resp = quitResp
default:
return fmt.Errorf("unsupported message %#v", x)
}
err = conn.Send(resp)
if err != nil {
return err
}
if resp == quitResp {
break
}
}
return nil
}