mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-25 02:20:10 +00:00
Compare commits
2 Commits
f5f2a0f190
...
831296a3e8
Author | SHA1 | Date | |
---|---|---|---|
831296a3e8 | |||
bbb0568cc4 |
47
api.go
47
api.go
@ -2,10 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -699,24 +696,30 @@ func (app *appContext) Logout(gc *gin.Context) {
|
|||||||
// panic(fmt.Errorf("restarting"))
|
// 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 {
|
func (app *appContext) Restart() error {
|
||||||
defer func() {
|
RESTART <- true
|
||||||
if r := recover(); r != nil {
|
return 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"))
|
|
||||||
}
|
}
|
||||||
|
@ -269,15 +269,6 @@
|
|||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title">Warning</h5>
|
<h5 class="modal-title">Warning</h5>
|
||||||
</div>
|
</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">
|
<div class="modal-body">
|
||||||
<p>A restart is needed to apply some settings. Restart now, later, or cancel?</p>
|
<p>A restart is needed to apply some settings. Restart now, later, or cancel?</p>
|
||||||
</div>
|
</div>
|
||||||
@ -286,7 +277,6 @@
|
|||||||
<button type="button" class="btn btn-secondary" id="applyRestarts" data-dismiss="modal">Apply, Restart later</button>
|
<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 & Restart</button>
|
<button type="button" class="btn btn-primary" id="applyAndRestart" data-dismiss="modal">Apply & Restart</button>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -359,11 +359,7 @@
|
|||||||
<div class="card-body text-center">
|
<div class="card-body text-center">
|
||||||
<h5 class="card-title">Finished!</h5>
|
<h5 class="card-title">Finished!</h5>
|
||||||
<p class="card-text">
|
<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.
|
Press the button below to submit your settings. The program will restart. Once it's done, refresh this page.
|
||||||
{{ end }}
|
|
||||||
</p>
|
</p>
|
||||||
<button id="submitButton" class="btn btn-primary">Submit</button>
|
<button id="submitButton" class="btn btn-primary">Submit</button>
|
||||||
</div>
|
</div>
|
||||||
|
175
main.go
175
main.go
@ -10,8 +10,10 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
@ -96,10 +98,17 @@ func setGinLogger(router *gin.Engine, debugMode bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var PLATFORM string = runtime.GOOS
|
var (
|
||||||
|
PLATFORM string = runtime.GOOS
|
||||||
|
SOCK string = "jfa-go.sock"
|
||||||
|
SRV *http.Server
|
||||||
|
RESTART chan bool
|
||||||
|
DATA, CONFIG, HOST *string
|
||||||
|
PORT *int
|
||||||
|
DEBUG *bool
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func start(asDaemon, firstCall bool) {
|
||||||
fmt.Printf("jfa-go version: %s (%s)\n", VERSION, COMMIT)
|
|
||||||
// app encompasses essentially all useful functions.
|
// app encompasses essentially all useful functions.
|
||||||
app := new(appContext)
|
app := new(appContext)
|
||||||
|
|
||||||
@ -117,23 +126,25 @@ func main() {
|
|||||||
app.info = log.New(os.Stdout, "[INFO] ", log.Ltime)
|
app.info = log.New(os.Stdout, "[INFO] ", log.Ltime)
|
||||||
app.err = log.New(os.Stdout, "[ERROR] ", log.Ltime|log.Lshortfile)
|
app.err = log.New(os.Stdout, "[ERROR] ", log.Ltime|log.Lshortfile)
|
||||||
|
|
||||||
dataPath := flag.String("data", app.data_path, "alternate path to data directory.")
|
if firstCall {
|
||||||
configPath := flag.String("config", app.config_path, "alternate path to config file.")
|
DATA = flag.String("data", app.data_path, "alternate path to data directory.")
|
||||||
host := flag.String("host", "", "alternate address to host web ui on.")
|
CONFIG = flag.String("config", app.config_path, "alternate path to config file.")
|
||||||
port := flag.Int("port", 0, "alternate port to host web ui on.")
|
HOST = flag.String("host", "", "alternate address to host web ui on.")
|
||||||
debug := flag.Bool("debug", false, "Enables debug logging and exposes pprof.")
|
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()
|
flag.Parse()
|
||||||
|
}
|
||||||
|
|
||||||
// attempt to apply command line flags correctly
|
// attempt to apply command line flags correctly
|
||||||
if app.config_path == *configPath && app.data_path != *dataPath {
|
if app.config_path == *CONFIG && app.data_path != *DATA {
|
||||||
app.data_path = *dataPath
|
app.data_path = *DATA
|
||||||
app.config_path = filepath.Join(app.data_path, "config.ini")
|
app.config_path = filepath.Join(app.data_path, "config.ini")
|
||||||
} else if app.config_path != *configPath && app.data_path == *dataPath {
|
} else if app.config_path != *CONFIG && app.data_path == *DATA {
|
||||||
app.config_path = *configPath
|
app.config_path = *CONFIG
|
||||||
} else {
|
} else {
|
||||||
app.config_path = *configPath
|
app.config_path = *CONFIG
|
||||||
app.data_path = *dataPath
|
app.data_path = *DATA
|
||||||
}
|
}
|
||||||
|
|
||||||
// env variables are necessary because syscall.Exec for self-restarts doesn't doesn't work with arguments for some reason.
|
// env variables are necessary because syscall.Exec for self-restarts doesn't doesn't work with arguments for some reason.
|
||||||
@ -183,7 +194,7 @@ func main() {
|
|||||||
// read from config...
|
// read from config...
|
||||||
debugMode = app.config.Section("ui").Key("debug").MustBool(false)
|
debugMode = app.config.Section("ui").Key("debug").MustBool(false)
|
||||||
// then from flag
|
// then from flag
|
||||||
if *debug {
|
if *DEBUG {
|
||||||
debugMode = true
|
debugMode = true
|
||||||
}
|
}
|
||||||
if debugMode {
|
if debugMode {
|
||||||
@ -193,15 +204,54 @@ func main() {
|
|||||||
app.debug = log.New(ioutil.Discard, "", 0)
|
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 {
|
if !firstRun {
|
||||||
app.host = app.config.Section("ui").Key("host").String()
|
app.host = app.config.Section("ui").Key("host").String()
|
||||||
app.port = app.config.Section("ui").Key("port").MustInt(8056)
|
app.port = app.config.Section("ui").Key("port").MustInt(8056)
|
||||||
|
|
||||||
if *host != app.host && *host != "" {
|
if *HOST != app.host && *HOST != "" {
|
||||||
app.host = *host
|
app.host = *HOST
|
||||||
}
|
}
|
||||||
if *port != app.port && *port > 0 {
|
if *PORT != app.port && *PORT > 0 {
|
||||||
app.port = *port
|
app.port = *PORT
|
||||||
}
|
}
|
||||||
|
|
||||||
if h := os.Getenv("JFA_HOST"); h != "" {
|
if h := os.Getenv("JFA_HOST"); h != "" {
|
||||||
@ -365,37 +415,100 @@ func main() {
|
|||||||
}
|
}
|
||||||
app.info.Printf("Starting router @ %s", address)
|
app.info.Printf("Starting router @ %s", address)
|
||||||
} else {
|
} else {
|
||||||
windows := false
|
|
||||||
if PLATFORM == "windows" {
|
|
||||||
windows = true
|
|
||||||
}
|
|
||||||
router.GET("/", func(gc *gin.Context) {
|
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("/testJF", app.TestJF)
|
||||||
router.POST("/modifyConfig", app.ModifyConfig)
|
router.POST("/modifyConfig", app.ModifyConfig)
|
||||||
app.info.Printf("Loading setup @ %s", address)
|
app.info.Printf("Loading setup @ %s", address)
|
||||||
}
|
}
|
||||||
|
|
||||||
srv := &http.Server{
|
SRV = &http.Server{
|
||||||
Addr: address,
|
Addr: address,
|
||||||
Handler: router,
|
Handler: router,
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
if err := srv.ListenAndServe(); err != nil {
|
if err := SRV.ListenAndServe(); err != nil {
|
||||||
app.err.Printf("Failure serving: %s", err)
|
app.err.Printf("Failure serving: %s", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
app.quit = make(chan os.Signal)
|
app.quit = make(chan os.Signal)
|
||||||
signal.Notify(app.quit, os.Interrupt)
|
signal.Notify(app.quit, os.Interrupt)
|
||||||
<-app.quit
|
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.info.Println("Shutting down...")
|
app.info.Println("Shutting down...")
|
||||||
|
|
||||||
cntx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
cntx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if err := srv.Shutdown(cntx); err != nil {
|
if err := SRV.Shutdown(cntx); err != nil {
|
||||||
app.err.Fatalf("Server shutdown error: %s", err)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
5
views.go
5
views.go
@ -11,10 +11,6 @@ func (app *appContext) AdminPage(gc *gin.Context) {
|
|||||||
emailEnabled, _ := app.config.Section("invite_emails").Key("enabled").Bool()
|
emailEnabled, _ := app.config.Section("invite_emails").Key("enabled").Bool()
|
||||||
notificationsEnabled, _ := app.config.Section("notifications").Key("enabled").Bool()
|
notificationsEnabled, _ := app.config.Section("notifications").Key("enabled").Bool()
|
||||||
ombiEnabled := app.config.Section("ombi").Key("enabled").MustBool(false)
|
ombiEnabled := app.config.Section("ombi").Key("enabled").MustBool(false)
|
||||||
windows := false
|
|
||||||
if PLATFORM == "windows" {
|
|
||||||
windows = true
|
|
||||||
}
|
|
||||||
gc.HTML(http.StatusOK, "admin.html", gin.H{
|
gc.HTML(http.StatusOK, "admin.html", gin.H{
|
||||||
"bs5": bs5,
|
"bs5": bs5,
|
||||||
"cssFile": app.cssFile,
|
"cssFile": app.cssFile,
|
||||||
@ -24,7 +20,6 @@ func (app *appContext) AdminPage(gc *gin.Context) {
|
|||||||
"version": VERSION,
|
"version": VERSION,
|
||||||
"commit": COMMIT,
|
"commit": COMMIT,
|
||||||
"ombiEnabled": ombiEnabled,
|
"ombiEnabled": ombiEnabled,
|
||||||
"windows": windows,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user