1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-12-24 01:50:11 +00:00

Compare commits

..

No commits in common. "831296a3e88e0772f6cc4c68788a15f037b7694d" and "f5f2a0f1904c0077b60dd2969fa57b18539cd0db" have entirely different histories.

5 changed files with 72 additions and 169 deletions

47
api.go
View File

@ -2,7 +2,10 @@ package main
import (
"fmt"
"os"
"os/signal"
"strings"
"syscall"
"time"
"github.com/gin-gonic/gin"
@ -696,30 +699,24 @@ func (app *appContext) Logout(gc *gin.Context) {
// panic(fmt.Errorf("restarting"))
// }
// func (app *appContext) Restart() error {
// defer func() {
// if r := recover(); r != nil {
// signal.Notify(app.quit, os.Interrupt)
// <-app.quit
// }
// }()
// args := os.Args
// // After a single restart, args[0] gets messed up and isnt the real executable.
// // JFA_DEEP tells the new process its a child, and JFA_EXEC is the real executable
// if os.Getenv("JFA_DEEP") == "" {
// os.Setenv("JFA_DEEP", "1")
// os.Setenv("JFA_EXEC", args[0])
// }
// env := os.Environ()
// err := syscall.Exec(os.Getenv("JFA_EXEC"), []string{""}, env)
// if err != nil {
// return err
// }
// panic(fmt.Errorf("restarting"))
// }
// no need to syscall.exec anymore!
func (app *appContext) Restart() error {
RESTART <- true
return nil
defer func() {
if r := recover(); r != nil {
signal.Notify(app.quit, os.Interrupt)
<-app.quit
}
}()
args := os.Args
// After a single restart, args[0] gets messed up and isnt the real executable.
// JFA_DEEP tells the new process its a child, and JFA_EXEC is the real executable
if os.Getenv("JFA_DEEP") == "" {
os.Setenv("JFA_DEEP", "1")
os.Setenv("JFA_EXEC", args[0])
}
env := os.Environ()
err := syscall.Exec(os.Getenv("JFA_EXEC"), []string{""}, env)
if err != nil {
return err
}
panic(fmt.Errorf("restarting"))
}

View File

@ -269,6 +269,15 @@
<div class="modal-header">
<h5 class="modal-title">Warning</h5>
</div>
{{ if .windows }}
<div class="modal-body">
<p>A restart is needed to apply some settings. Self-restarts aren't possible on Windows, so you must restart manually.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-secondary" id="applyRestarts" data-dismiss="modal">Apply, Restart manually</button>
</div>
{{ else }}
<div class="modal-body">
<p>A restart is needed to apply some settings. Restart now, later, or cancel?</p>
</div>
@ -277,6 +286,7 @@
<button type="button" class="btn btn-secondary" id="applyRestarts" data-dismiss="modal">Apply, Restart later</button>
<button type="button" class="btn btn-primary" id="applyAndRestart" data-dismiss="modal">Apply &amp; Restart</button>
</div>
{{ end }}
</div>
</div>
</div>

View File

@ -359,7 +359,11 @@
<div class="card-body text-center">
<h5 class="card-title">Finished!</h5>
<p class="card-text">
{{ if .windows }}
Press the button below to submit your settings. Unfortunately you're running on Windows, so jfa-go <a href="https://github.com/golang/go/issues/30662">cannot restart itself.</a> You will manually have to restart.
{{ else }}
Press the button below to submit your settings. The program will restart. Once it's done, refresh this page.
{{ end }}
</p>
<button id="submitButton" class="btn btn-primary">Submit</button>
</div>

173
main.go
View File

@ -10,10 +10,8 @@ import (
"io"
"io/ioutil"
"log"
"net"
"net/http"
"os"
"os/exec"
"os/signal"
"path/filepath"
"runtime"
@ -98,17 +96,10 @@ func setGinLogger(router *gin.Engine, debugMode bool) {
}
}
var (
PLATFORM string = runtime.GOOS
SOCK string = "jfa-go.sock"
SRV *http.Server
RESTART chan bool
DATA, CONFIG, HOST *string
PORT *int
DEBUG *bool
)
var PLATFORM string = runtime.GOOS
func start(asDaemon, firstCall bool) {
func main() {
fmt.Printf("jfa-go version: %s (%s)\n", VERSION, COMMIT)
// app encompasses essentially all useful functions.
app := new(appContext)
@ -126,25 +117,23 @@ func start(asDaemon, firstCall bool) {
app.info = log.New(os.Stdout, "[INFO] ", log.Ltime)
app.err = log.New(os.Stdout, "[ERROR] ", log.Ltime|log.Lshortfile)
if firstCall {
DATA = flag.String("data", app.data_path, "alternate path to data directory.")
CONFIG = flag.String("config", app.config_path, "alternate path to config file.")
HOST = flag.String("host", "", "alternate address to host web ui on.")
PORT = flag.Int("port", 0, "alternate port to host web ui on.")
DEBUG = flag.Bool("debug", false, "Enables debug logging and exposes pprof.")
dataPath := flag.String("data", app.data_path, "alternate path to data directory.")
configPath := flag.String("config", app.config_path, "alternate path to config file.")
host := flag.String("host", "", "alternate address to host web ui on.")
port := flag.Int("port", 0, "alternate port to host web ui on.")
debug := flag.Bool("debug", false, "Enables debug logging and exposes pprof.")
flag.Parse()
}
// attempt to apply command line flags correctly
if app.config_path == *CONFIG && app.data_path != *DATA {
app.data_path = *DATA
if app.config_path == *configPath && app.data_path != *dataPath {
app.data_path = *dataPath
app.config_path = filepath.Join(app.data_path, "config.ini")
} else if app.config_path != *CONFIG && app.data_path == *DATA {
app.config_path = *CONFIG
} else if app.config_path != *configPath && app.data_path == *dataPath {
app.config_path = *configPath
} else {
app.config_path = *CONFIG
app.data_path = *DATA
app.config_path = *configPath
app.data_path = *dataPath
}
// env variables are necessary because syscall.Exec for self-restarts doesn't doesn't work with arguments for some reason.
@ -194,7 +183,7 @@ func start(asDaemon, firstCall bool) {
// read from config...
debugMode = app.config.Section("ui").Key("debug").MustBool(false)
// then from flag
if *DEBUG {
if *debug {
debugMode = true
}
if debugMode {
@ -204,54 +193,15 @@ func start(asDaemon, firstCall bool) {
app.debug = log.New(ioutil.Discard, "", 0)
}
if asDaemon {
go func() {
socket := SOCK
os.Remove(socket)
listener, err := net.Listen("unix", socket)
if err != nil {
app.err.Fatalf("Couldn't establish socket connection at %s\n", SOCK)
}
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
<-c
os.Remove(socket)
os.Exit(1)
}()
defer func() {
listener.Close()
os.Remove(SOCK)
}()
for {
con, err := listener.Accept()
if err != nil {
app.err.Printf("Couldn't read message on %s: %s", socket, err)
continue
}
buf := make([]byte, 512)
nr, err := con.Read(buf)
if err != nil {
app.err.Printf("Couldn't read message on %s: %s", socket, err)
continue
}
command := string(buf[0:nr])
if command == "stop" {
app.shutdown()
}
}
}()
}
if !firstRun {
app.host = app.config.Section("ui").Key("host").String()
app.port = app.config.Section("ui").Key("port").MustInt(8056)
if *HOST != app.host && *HOST != "" {
app.host = *HOST
if *host != app.host && *host != "" {
app.host = *host
}
if *PORT != app.port && *PORT > 0 {
app.port = *PORT
if *port != app.port && *port > 0 {
app.port = *port
}
if h := os.Getenv("JFA_HOST"); h != "" {
@ -415,100 +365,37 @@ func start(asDaemon, firstCall bool) {
}
app.info.Printf("Starting router @ %s", address)
} else {
windows := false
if PLATFORM == "windows" {
windows = true
}
router.GET("/", func(gc *gin.Context) {
gc.HTML(200, "setup.html", gin.H{})
gc.HTML(200, "setup.html", gin.H{
"windows": windows,
})
})
router.POST("/testJF", app.TestJF)
router.POST("/modifyConfig", app.ModifyConfig)
app.info.Printf("Loading setup @ %s", address)
}
SRV = &http.Server{
srv := &http.Server{
Addr: address,
Handler: router,
}
go func() {
if err := SRV.ListenAndServe(); err != nil {
if err := srv.ListenAndServe(); err != nil {
app.err.Printf("Failure serving: %s", err)
}
}()
app.quit = make(chan os.Signal)
signal.Notify(app.quit, os.Interrupt)
go func() {
for range app.quit {
app.shutdown()
}
}()
for range RESTART {
cntx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
if err := SRV.Shutdown(cntx); err != nil {
app.err.Fatalf("Server shutdown error: %s", err)
}
return
}
}
func (app *appContext) shutdown() {
<-app.quit
app.info.Println("Shutting down...")
cntx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
if err := SRV.Shutdown(cntx); err != nil {
if err := srv.Shutdown(cntx); err != nil {
app.err.Fatalf("Server shutdown error: %s", err)
}
os.Exit(1)
}
func flagPassed(name string) (found bool) {
for _, f := range os.Args {
if f == name {
found = true
}
}
return
}
func main() {
fmt.Printf("jfa-go version: %s (%s)\n", VERSION, COMMIT)
folder := "/tmp"
if PLATFORM == "windows" {
folder = os.Getenv("TEMP")
}
SOCK = filepath.Join(folder, SOCK)
fmt.Println(SOCK)
if flagPassed("start") {
args := []string{}
for i, f := range os.Args {
if f == "start" {
args = append(args, "daemon")
} else if i != 0 {
args = append(args, f)
}
}
cmd := exec.Command(os.Args[0], args...)
cmd.Start()
os.Exit(1)
} else if flagPassed("stop") {
con, err := net.Dial("unix", SOCK)
if err != nil {
fmt.Printf("Couldn't dial socket %s, are you sure jfa-go is running?\n", SOCK)
os.Exit(1)
}
_, err = con.Write([]byte("stop"))
if err != nil {
fmt.Printf("Couldn't send command to socket %s, are you sure jfa-go is running?\n", SOCK)
os.Exit(1)
}
fmt.Println("Sent.")
} else if flagPassed("daemon") {
start(true, true)
} else {
RESTART = make(chan bool, 1)
start(false, true)
for {
fmt.Printf("jfa-go version: %s (%s)\n", VERSION, COMMIT)
start(false, false)
}
}
}

View File

@ -11,6 +11,10 @@ func (app *appContext) AdminPage(gc *gin.Context) {
emailEnabled, _ := app.config.Section("invite_emails").Key("enabled").Bool()
notificationsEnabled, _ := app.config.Section("notifications").Key("enabled").Bool()
ombiEnabled := app.config.Section("ombi").Key("enabled").MustBool(false)
windows := false
if PLATFORM == "windows" {
windows = true
}
gc.HTML(http.StatusOK, "admin.html", gin.H{
"bs5": bs5,
"cssFile": app.cssFile,
@ -20,6 +24,7 @@ func (app *appContext) AdminPage(gc *gin.Context) {
"version": VERSION,
"commit": COMMIT,
"ombiEnabled": ombiEnabled,
"windows": windows,
})
}