1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2025-04-19 17:42:53 +00:00

Compare commits

...

3 Commits

Author SHA1 Message Date
9875458b01
rewrite time unmarshaler for mediabrowser
Last ditch effort for #69, removes quotes and trailing Z's manually and
also removes nanoseconds since they're useless.
2021-03-23 21:59:41 +00:00
f0dccc58aa
separate pprof from debug mode
enabled with -pprof now.
2021-03-23 21:59:04 +00:00
636bc22d52
reimplement Lshortfile for log wrapper
Fixes all debug messages having "logger:<line>:" instead of the actual
caller.
2021-03-23 21:57:53 +00:00
4 changed files with 101 additions and 47 deletions

View File

@ -3,6 +3,8 @@ package main
import ( import (
"io" "io"
"log" "log"
"runtime"
"strconv"
c "github.com/fatih/color" c "github.com/fatih/color"
) )
@ -16,24 +18,84 @@ type Logger interface {
} }
type logger struct { type logger struct {
logger *log.Logger logger *log.Logger
printer *c.Color shortfile bool
printer *c.Color
}
func Lshortfile() string {
_, file, line, ok := runtime.Caller(2)
lineString := strconv.Itoa(line)
if !ok {
return ""
}
if file == "" {
return lineString
}
for i := len(file) - 1; i > 0; i-- {
if file[i] == '/' || file[i] == '\\' {
file = file[i+1:]
break
}
}
return file + ":" + lineString + ":"
} }
func NewLogger(out io.Writer, prefix string, flag int, color c.Attribute) (l logger) { func NewLogger(out io.Writer, prefix string, flag int, color c.Attribute) (l logger) {
// Use reimplemented Lshortfile since wrapping the log functions messes them up
if flag&log.Lshortfile != 0 {
flag -= log.Lshortfile
l.shortfile = true
}
l.logger = log.New(out, prefix, flag) l.logger = log.New(out, prefix, flag)
l.printer = c.New(color) l.printer = c.New(color)
return l return l
} }
func (l logger) Printf(format string, v ...interface{}) { func (l logger) Printf(format string, v ...interface{}) {
l.logger.Print(l.printer.Sprintf(format, v...)) var out string
if l.shortfile {
out = Lshortfile()
}
out += " " + l.printer.Sprintf(format, v...)
l.logger.Print(out)
} }
func (l logger) Print(v ...interface{}) { l.logger.Print(l.printer.Sprint(v...)) }
func (l logger) Println(v ...interface{}) { l.logger.Print(l.printer.Sprintln(v...)) } func (l logger) Print(v ...interface{}) {
func (l logger) Fatal(v ...interface{}) { l.logger.Fatal(l.printer.Sprint(v...)) } var out string
if l.shortfile {
out = Lshortfile()
}
out += " " + l.printer.Sprint(v...)
l.logger.Print(out)
}
func (l logger) Println(v ...interface{}) {
var out string
if l.shortfile {
out = Lshortfile()
}
out += " " + l.printer.Sprintln(v...)
l.logger.Print(out)
}
func (l logger) Fatal(v ...interface{}) {
var out string
if l.shortfile {
out = Lshortfile()
}
out += " " + l.printer.Sprint(v...)
l.logger.Fatal(out)
}
func (l logger) Fatalf(format string, v ...interface{}) { func (l logger) Fatalf(format string, v ...interface{}) {
l.logger.Fatal(l.printer.Sprintf(format, v...)) var out string
if l.shortfile {
out = Lshortfile()
}
out += " " + l.printer.Sprintf(format, v...)
l.logger.Fatal(out)
} }
type emptyLogger bool type emptyLogger bool

14
main.go
View File

@ -38,6 +38,7 @@ var (
DATA, CONFIG, HOST *string DATA, CONFIG, HOST *string
PORT *int PORT *int
DEBUG *bool DEBUG *bool
PPROF *bool
TEST bool TEST bool
SWAGGER *bool SWAGGER *bool
warning = color.New(color.FgYellow).SprintfFunc() warning = color.New(color.FgYellow).SprintfFunc()
@ -172,7 +173,8 @@ func start(asDaemon, firstCall bool) {
CONFIG = flag.String("config", app.configPath, "alternate path to config file.") CONFIG = flag.String("config", app.configPath, "alternate path to config file.")
HOST = flag.String("host", "", "alternate address to host web ui on.") HOST = flag.String("host", "", "alternate address to host web ui on.")
PORT = flag.Int("port", 0, "alternate port 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.") DEBUG = flag.Bool("debug", false, "Enables debug logging.")
PPROF = flag.Bool("pprof", false, "Exposes pprof profiler on /debug/pprof.")
SWAGGER = flag.Bool("swagger", false, "Enable swagger at /swagger/index.html") SWAGGER = flag.Bool("swagger", false, "Enable swagger at /swagger/index.html")
flag.Parse() flag.Parse()
@ -182,6 +184,9 @@ func start(asDaemon, firstCall bool) {
if *DEBUG { if *DEBUG {
os.Setenv("DEBUG", "1") os.Setenv("DEBUG", "1")
} }
if *PPROF {
os.Setenv("PPROF", "1")
}
} }
if os.Getenv("SWAGGER") == "1" { if os.Getenv("SWAGGER") == "1" {
@ -190,6 +195,9 @@ func start(asDaemon, firstCall bool) {
if os.Getenv("DEBUG") == "1" { if os.Getenv("DEBUG") == "1" {
*DEBUG = true *DEBUG = true
} }
if os.Getenv("PPROF") == "1" {
*PPROF = true
}
// attempt to apply command line flags correctly // attempt to apply command line flags correctly
if app.configPath == *CONFIG && app.dataPath != *DATA { if app.configPath == *CONFIG && app.dataPath != *DATA {
app.dataPath = *DATA app.dataPath = *DATA
@ -248,11 +256,13 @@ func start(asDaemon, firstCall bool) {
debugMode = true debugMode = true
} }
if debugMode { if debugMode {
app.info.Print(warning("\n\nWARNING: Don't use debug mode in production, as it exposes pprof on the network.\n\n"))
app.debug = NewLogger(os.Stdout, "[DEBUG] ", log.Ltime|log.Lshortfile, color.FgYellow) app.debug = NewLogger(os.Stdout, "[DEBUG] ", log.Ltime|log.Lshortfile, color.FgYellow)
} else { } else {
app.debug = emptyLogger(false) app.debug = emptyLogger(false)
} }
if *PPROF {
app.info.Print(warning("\n\nWARNING: Don't use pprof in production.\n\n"))
}
// Starts listener to receive commands over a unix socket. Use with 'jfa-go start/stop' // Starts listener to receive commands over a unix socket. Use with 'jfa-go start/stop'
if asDaemon { if asDaemon {

View File

@ -1,9 +1,6 @@
package mediabrowser package mediabrowser
import ( import (
"encoding/json"
"fmt"
"strings"
"time" "time"
) )
@ -17,44 +14,29 @@ type Time struct {
} }
func (t *Time) UnmarshalJSON(b []byte) (err error) { func (t *Time) UnmarshalJSON(b []byte) (err error) {
str := strings.TrimSuffix(strings.TrimPrefix(string(b), "\""), "\"") // str := strings.TrimSuffix(strings.TrimPrefix(string(b), "\""), "\"")
// Trim nanoseconds to always have 6 digits, so overall length is always the same. // Trim quotes from beginning and end, and any number of Zs (indicates UTC).
if str[len(str)-1] == 'Z' { for b[0] == '"' {
if str[len(str)-2] == 'Z' { b = b[1:]
/* From #69, "ZZ" is sometimes used, meaning UTC-8:00.
TZ doesn't really matter to us, so we'll pretend it's UTC. */
str = str[:25] + "0Z"
} else {
str = str[:26] + "Z"
}
} else {
str = str[:26]
} }
// decent method for b[len(b)-1] == '"' || b[len(b)-1] == 'Z' {
t.Time, err = time.Parse("2006-01-02T15:04:05.000000Z", str) b = b[:len(b)-1]
if err == nil {
return
} }
t.Time, err = time.Parse("2006-01-02T15:04:05.000000", str) // Trim nanoseconds and anything after, we don't care
if err == nil { i := len(b) - 1
return for b[i] != '.' && i > 0 {
i--
} }
// emby method if i != 0 {
t.Time, err = time.Parse("2006-01-02T15:04:05.0000000+00:00", str) b = b[:i]
if err == nil {
return
} }
fmt.Println("THIRDERR", err) t.Time, err = time.Parse("2006-01-02T15:04:05", string(b))
// if all else fails, just do whatever would usually be done. // str := string(b) + "Z"
// some stored dates from jellyfin have no timezone at the end, if not we assume UTC // timeJSON := []byte("{ \"parseme\": \"" + str + "\" }")
if str[len(str)-1] != 'Z' { // var parsed magicParse
str += "Z" // // Magically turn it into a time.Time
} // err = json.Unmarshal(timeJSON, &parsed)
timeJSON := []byte("{ \"parseme\": \"" + str + "\" }") // t.Time = parsed.Parsed
var parsed magicParse
// Magically turn it into a time.Time
err = json.Unmarshal(timeJSON, &parsed)
t.Time = parsed.Parsed
return return
} }

View File

@ -85,7 +85,7 @@ func (app *appContext) loadRouter(address string, debug bool) *gin.Engine {
app.loadHTML(router) app.loadHTML(router)
router.Use(static.Serve("/", app.webFS)) router.Use(static.Serve("/", app.webFS))
router.NoRoute(app.NoRouteHandler) router.NoRoute(app.NoRouteHandler)
if debug { if *PPROF {
app.debug.Println("Loading pprof") app.debug.Println("Loading pprof")
pprof.Register(router) pprof.Register(router)
} }