Transition to new logger

This commit is contained in:
Melon 2024-05-13 19:33:33 +01:00
parent a8db73d957
commit 1f4f4414d5
Signed by: melon
GPG Key ID: 6C9D970C50D26A25
17 changed files with 161 additions and 95 deletions

View File

@ -4,11 +4,11 @@ import (
"crypto/tls" "crypto/tls"
"crypto/x509/pkix" "crypto/x509/pkix"
"fmt" "fmt"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/utils" "github.com/1f349/violet/utils"
"github.com/mrmelon54/certgen" "github.com/mrmelon54/certgen"
"github.com/mrmelon54/rescheduler" "github.com/mrmelon54/rescheduler"
"io/fs" "io/fs"
"log"
"math/big" "math/big"
"os" "os"
"strings" "strings"
@ -17,6 +17,8 @@ import (
"time" "time"
) )
var Logger = logger.Logger.WithPrefix("Violet Certs")
// Certs is the certificate loader and management system. // Certs is the certificate loader and management system.
type Certs struct { type Certs struct {
cDir fs.FS cDir fs.FS
@ -69,7 +71,7 @@ func New(certDir fs.FS, keyDir fs.FS, selfCert bool) *Certs {
return now.AddDate(10, 0, 0) return now.AddDate(10, 0, 0)
}) })
if err != nil { if err != nil {
log.Fatalln("Failed to generate CA cert for self-signed mode:", err) logger.Logger.Fatal("Failed to generate CA cert for self-signed mode", "err", err)
} }
c.ca = ca c.ca = ca
} }
@ -145,7 +147,7 @@ func (c *Certs) threadCompile() {
// compile map and check errors // compile map and check errors
err := c.internalCompile(certMap) err := c.internalCompile(certMap)
if err != nil { if err != nil {
log.Printf("[Certs] Compile failed: %s\n", err) Logger.Infof("Compile failed: %s\n", err)
return return
} }
@ -168,7 +170,7 @@ func (c *Certs) internalCompile(m map[string]*tls.Certificate) error {
return fmt.Errorf("failed to read cert dir: %w", err) return fmt.Errorf("failed to read cert dir: %w", err)
} }
log.Printf("[Certs] Compiling lookup table for %d certificates\n", len(files)) Logger.Infof("Compiling lookup table for %d certificates\n", len(files))
// find and parse certs // find and parse certs
for _, i := range files { for _, i := range files {

View File

@ -10,6 +10,7 @@ import (
"github.com/1f349/violet/domains" "github.com/1f349/violet/domains"
errorPages "github.com/1f349/violet/error-pages" errorPages "github.com/1f349/violet/error-pages"
"github.com/1f349/violet/favicons" "github.com/1f349/violet/favicons"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/proxy" "github.com/1f349/violet/proxy"
"github.com/1f349/violet/proxy/websocket" "github.com/1f349/violet/proxy/websocket"
"github.com/1f349/violet/router" "github.com/1f349/violet/router"
@ -17,12 +18,11 @@ import (
"github.com/1f349/violet/servers/api" "github.com/1f349/violet/servers/api"
"github.com/1f349/violet/servers/conf" "github.com/1f349/violet/servers/conf"
"github.com/1f349/violet/utils" "github.com/1f349/violet/utils"
"github.com/mrmelon54/exit-reload"
"github.com/google/subcommands" "github.com/google/subcommands"
"github.com/mrmelon54/exit-reload"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/collectors"
"io/fs" "io/fs"
"log"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
@ -45,19 +45,19 @@ func (s *serveCmd) Usage() string {
} }
func (s *serveCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { func (s *serveCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
log.Println("[Violet] Starting...") logger.Logger.Info("Starting...")
if s.configPath == "" { if s.configPath == "" {
log.Println("[Violet] Error: config flag is missing") logger.Logger.Info("Error: config flag is missing")
return subcommands.ExitUsageError return subcommands.ExitUsageError
} }
openConf, err := os.Open(s.configPath) openConf, err := os.Open(s.configPath)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
log.Println("[Violet] Error: missing config file") logger.Logger.Info("Error: missing config file")
} else { } else {
log.Println("[Violet] Error: open config file: ", err) logger.Logger.Info("Error: open config file: ", err)
} }
return subcommands.ExitFailure return subcommands.ExitFailure
} }
@ -65,7 +65,7 @@ func (s *serveCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
var config startUpConfig var config startUpConfig
err = json.NewDecoder(openConf).Decode(&config) err = json.NewDecoder(openConf).Decode(&config)
if err != nil { if err != nil {
log.Println("[Violet] Error: invalid config file: ", err) logger.Logger.Info("Error: invalid config file: ", err)
return subcommands.ExitFailure return subcommands.ExitFailure
} }
@ -81,12 +81,12 @@ func normalLoad(startUp startUpConfig, wd string) {
// create path to cert dir // create path to cert dir
err := os.MkdirAll(filepath.Join(wd, "certs"), os.ModePerm) err := os.MkdirAll(filepath.Join(wd, "certs"), os.ModePerm)
if err != nil { if err != nil {
log.Fatal("[Violet] Failed to create certificate path") logger.Logger.Fatal("Failed to create certificate path")
} }
// create path to key dir // create path to key dir
err = os.MkdirAll(filepath.Join(wd, "keys"), os.ModePerm) err = os.MkdirAll(filepath.Join(wd, "keys"), os.ModePerm)
if err != nil { if err != nil {
log.Fatal("[Violet] Failed to create certificate key path") logger.Logger.Fatal("Failed to create certificate key path")
} }
} }
@ -96,20 +96,20 @@ func normalLoad(startUp startUpConfig, wd string) {
errorPageDir = os.DirFS(startUp.ErrorPagePath) errorPageDir = os.DirFS(startUp.ErrorPagePath)
err := os.MkdirAll(startUp.ErrorPagePath, os.ModePerm) err := os.MkdirAll(startUp.ErrorPagePath, os.ModePerm)
if err != nil { if err != nil {
log.Fatalf("[Violet] Failed to create error page path '%s'", startUp.ErrorPagePath) logger.Logger.Fatal("Failed to create error page", "path", startUp.ErrorPagePath)
} }
} }
// load the MJWT RSA public key from a pem encoded file // load the MJWT RSA public key from a pem encoded file
mJwtVerify, err := mjwt.NewMJwtVerifierFromFile(filepath.Join(wd, "signer.public.pem")) mJwtVerify, err := mjwt.NewMJwtVerifierFromFile(filepath.Join(wd, "signer.public.pem"))
if err != nil { if err != nil {
log.Fatalf("[Violet] Failed to load MJWT verifier public key from file '%s': %s", filepath.Join(wd, "signer.public.pem"), err) logger.Logger.Fatal("Failed to load MJWT verifier public key", "file", filepath.Join(wd, "signer.public.pem"), "err", err)
} }
// open sqlite database // open sqlite database
db, err := violet.InitDB(filepath.Join(wd, "violet.db.sqlite")) db, err := violet.InitDB(filepath.Join(wd, "violet.db.sqlite"))
if err != nil { if err != nil {
log.Fatal("[Violet] Failed to open database") logger.Logger.Fatal("Failed to open database", "err", err)
} }
certDir := os.DirFS(filepath.Join(wd, "certs")) certDir := os.DirFS(filepath.Join(wd, "certs"))
@ -155,20 +155,23 @@ func normalLoad(startUp startUpConfig, wd string) {
if srvConf.ApiListen != "" { if srvConf.ApiListen != "" {
srvApi = api.NewApiServer(srvConf, allCompilables, promRegistry) srvApi = api.NewApiServer(srvConf, allCompilables, promRegistry)
srvApi.SetKeepAlivesEnabled(false) srvApi.SetKeepAlivesEnabled(false)
log.Printf("[API] Starting API server on: '%s'\n", srvApi.Addr) l := logger.Logger.With("server", "API")
go utils.RunBackgroundHttp("API", srvApi) l.Info("Starting server", "addr", srvApi.Addr)
go utils.RunBackgroundHttp(l, srvApi)
} }
if srvConf.HttpListen != "" { if srvConf.HttpListen != "" {
srvHttp = servers.NewHttpServer(srvConf, promRegistry) srvHttp = servers.NewHttpServer(srvConf, promRegistry)
srvHttp.SetKeepAlivesEnabled(false) srvHttp.SetKeepAlivesEnabled(false)
log.Printf("[HTTP] Starting HTTP server on: '%s'\n", srvHttp.Addr) l := logger.Logger.With("server", "HTTP")
go utils.RunBackgroundHttp("HTTP", srvHttp) l.Info("Starting server", "addr", srvHttp.Addr)
go utils.RunBackgroundHttp(l, srvHttp)
} }
if srvConf.HttpsListen != "" { if srvConf.HttpsListen != "" {
srvHttps = servers.NewHttpsServer(srvConf, promRegistry) srvHttps = servers.NewHttpsServer(srvConf, promRegistry)
srvHttps.SetKeepAlivesEnabled(false) srvHttps.SetKeepAlivesEnabled(false)
log.Printf("[HTTPS] Starting HTTPS server on: '%s'\n", srvHttps.Addr) l := logger.Logger.With("server", "HTTPS")
go utils.RunBackgroundHttps("HTTPS", srvHttps) l.Info("Starting server", "addr", srvHttps.Addr)
go utils.RunBackgroundHttps(l, srvHttps)
} }
exit_reload.ExitReload("Violet", func() { exit_reload.ExitReload("Violet", func() {

View File

@ -7,13 +7,13 @@ import (
"fmt" "fmt"
"github.com/1f349/violet" "github.com/1f349/violet"
"github.com/1f349/violet/domains" "github.com/1f349/violet/domains"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/proxy" "github.com/1f349/violet/proxy"
"github.com/1f349/violet/proxy/websocket" "github.com/1f349/violet/proxy/websocket"
"github.com/1f349/violet/router" "github.com/1f349/violet/router"
"github.com/1f349/violet/target" "github.com/1f349/violet/target"
"github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2"
"github.com/google/subcommands" "github.com/google/subcommands"
"log"
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
@ -42,7 +42,7 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
// get absolute path to specify files // get absolute path to specify files
wdAbs, err := filepath.Abs(s.wdPath) wdAbs, err := filepath.Abs(s.wdPath)
if err != nil { if err != nil {
fmt.Println("[Violet] Failed to get full directory path: ", err) fmt.Println("Failed to get full directory path: ", err)
return subcommands.ExitFailure return subcommands.ExitFailure
} }
@ -50,11 +50,11 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
createFile := false createFile := false
err = survey.AskOne(&survey.Confirm{Message: fmt.Sprintf("Create Violet config files in this directory: '%s'?", wdAbs)}, &createFile) err = survey.AskOne(&survey.Confirm{Message: fmt.Sprintf("Create Violet config files in this directory: '%s'?", wdAbs)}, &createFile)
if err != nil { if err != nil {
fmt.Println("[Violet] Error: ", err) fmt.Println("Error: ", err)
return subcommands.ExitFailure return subcommands.ExitFailure
} }
if !createFile { if !createFile {
fmt.Println("[Violet] Goodbye") fmt.Println("Goodbye")
return subcommands.ExitSuccess return subcommands.ExitSuccess
} }
@ -111,7 +111,7 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
}, },
}, &answers) }, &answers)
if err != nil { if err != nil {
fmt.Println("[Violet] Error: ", err) fmt.Println("Error: ", err)
return subcommands.ExitFailure return subcommands.ExitFailure
} }
@ -142,14 +142,14 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
RateLimit: answers.RateLimit, RateLimit: answers.RateLimit,
}) })
if err != nil { if err != nil {
fmt.Println("[Violet] Failed to write config file: ", err) fmt.Println("Failed to write config file: ", err)
return subcommands.ExitFailure return subcommands.ExitFailure
} }
// open sqlite database // open sqlite database
db, err := violet.InitDB(databaseFile) db, err := violet.InitDB(databaseFile)
if err != nil { if err != nil {
log.Fatalf("[Violet] Failed to open database '%s'...", databaseFile) logger.Logger.Fatal("Failed to open database", "err", err)
} }
// domain manager to add a domain, no need to compile here as the program needs // domain manager to add a domain, no need to compile here as the program needs
@ -168,14 +168,14 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
return nil return nil
})) }))
if err != nil { if err != nil {
fmt.Println("[Violet] Error: ", err) fmt.Println("Error: ", err)
return subcommands.ExitFailure return subcommands.ExitFailure
} }
// parse the api url // parse the api url
apiUrl, err := url.Parse(answers.ApiUrl) apiUrl, err := url.Parse(answers.ApiUrl)
if err != nil { if err != nil {
fmt.Println("[Violet] Failed to parse API URL: ", err) fmt.Println("Failed to parse API URL: ", err)
return subcommands.ExitFailure return subcommands.ExitFailure
} }
@ -191,13 +191,13 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
Active: true, Active: true,
}) })
if err != nil { if err != nil {
fmt.Println("[Violet] Failed to insert api route into database: ", err) fmt.Println("Failed to insert api route into database: ", err)
return subcommands.ExitFailure return subcommands.ExitFailure
} }
} }
fmt.Println("[Violet] Setup complete") fmt.Println("Setup complete")
fmt.Printf("[Violet] Run the reverse proxy with `violet serve -conf %s`\n", confFile) fmt.Printf("Run the reverse proxy with `violet serve -conf %s`\n", confFile)
return subcommands.ExitSuccess return subcommands.ExitSuccess
} }

View File

@ -4,13 +4,15 @@ import (
"context" "context"
_ "embed" _ "embed"
"github.com/1f349/violet/database" "github.com/1f349/violet/database"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/utils" "github.com/1f349/violet/utils"
"github.com/mrmelon54/rescheduler" "github.com/mrmelon54/rescheduler"
"log"
"strings" "strings"
"sync" "sync"
) )
var Logger = logger.Logger.WithPrefix("Violet Domains")
// Domains is the domain list and management system. // Domains is the domain list and management system.
type Domains struct { type Domains struct {
db *database.Queries db *database.Queries
@ -68,7 +70,7 @@ func (d *Domains) threadCompile() {
// compile map and check errors // compile map and check errors
err := d.internalCompile(domainMap) err := d.internalCompile(domainMap)
if err != nil { if err != nil {
log.Printf("[Domains] Compile failed: %s\n", err) Logger.Info("Compile faile", "err", err)
return return
} }
@ -81,7 +83,7 @@ func (d *Domains) threadCompile() {
// internalCompile is a hidden internal method for querying the database during // internalCompile is a hidden internal method for querying the database during
// the Compile() method. // the Compile() method.
func (d *Domains) internalCompile(m map[string]struct{}) error { func (d *Domains) internalCompile(m map[string]struct{}) error {
log.Println("[Domains] Updating domains from database") Logger.Info("Updating domains from database")
// sql or something? // sql or something?
rows, err := d.db.GetActiveDomains(context.Background()) rows, err := d.db.GetActiveDomains(context.Background())
@ -105,7 +107,7 @@ func (d *Domains) Put(domain string, active bool) {
Active: active, Active: active,
}) })
if err != nil { if err != nil {
log.Printf("[Violet] Database error: %s\n", err) logger.Logger.Infof("Database error: %s\n", err)
} }
} }
@ -114,6 +116,6 @@ func (d *Domains) Delete(domain string) {
defer d.s.Unlock() defer d.s.Unlock()
err := d.db.DeleteDomain(context.Background(), domain) err := d.db.DeleteDomain(context.Background(), domain)
if err != nil { if err != nil {
log.Printf("[Violet] Database error: %s\n", err) logger.Logger.Infof("Database error: %s\n", err)
} }
} }

View File

@ -2,9 +2,9 @@ package error_pages
import ( import (
"fmt" "fmt"
"github.com/1f349/violet/logger"
"github.com/mrmelon54/rescheduler" "github.com/mrmelon54/rescheduler"
"io/fs" "io/fs"
"log"
"net/http" "net/http"
"path/filepath" "path/filepath"
"strconv" "strconv"
@ -12,6 +12,8 @@ import (
"sync" "sync"
) )
var Logger = logger.Logger.WithPrefix("Violet Error Pages")
// ErrorPages stores the custom error pages and is called by the servers to // ErrorPages stores the custom error pages and is called by the servers to
// output meaningful pages for HTTP error codes // output meaningful pages for HTTP error codes
type ErrorPages struct { type ErrorPages struct {
@ -78,7 +80,7 @@ func (e *ErrorPages) threadCompile() {
if e.dir != nil { if e.dir != nil {
err := e.internalCompile(errorPageMap) err := e.internalCompile(errorPageMap)
if err != nil { if err != nil {
log.Printf("[ErrorPages] Compile failed: %s\n", err) Logger.Info("Compile failed", "err", err)
return return
} }
} }
@ -96,7 +98,7 @@ func (e *ErrorPages) internalCompile(m map[int]func(rw http.ResponseWriter)) err
return fmt.Errorf("failed to read error pages dir: %w", err) return fmt.Errorf("failed to read error pages dir: %w", err)
} }
log.Printf("[ErrorPages] Compiling lookup table for %d error pages\n", len(files)) Logger.Info("Compiling lookup table", "page count", len(files))
// find and load error pages // find and load error pages
for _, i := range files { for _, i := range files {
@ -111,20 +113,20 @@ func (e *ErrorPages) internalCompile(m map[int]func(rw http.ResponseWriter)) err
// if the extension is not 'html' then ignore the file // if the extension is not 'html' then ignore the file
if ext != ".html" { if ext != ".html" {
log.Printf("[ErrorPages] WARNING: ignoring non '.html' file in error pages directory: '%s'\n", name) Logger.Warn("Ignoring non '.html' file in error pages directory", "name", name)
continue continue
} }
// if the name can't be // if the name can't be
nameInt, err := strconv.Atoi(strings.TrimSuffix(name, ".html")) nameInt, err := strconv.Atoi(strings.TrimSuffix(name, ".html"))
if err != nil { if err != nil {
log.Printf("[ErrorPages] WARNING: ignoring invalid error page in error pages directory: '%s'\n", name) Logger.Warn("Ignoring invalid error page in error pages directory", "name", name)
continue continue
} }
// check if code is in range 100-599 // check if code is in range 100-599
if nameInt < 100 || nameInt >= 600 { if nameInt < 100 || nameInt >= 600 {
log.Printf("[ErrorPages] WARNING: ignoring invalid error page in error pages directory must be 100-599: '%s'\n", name) Logger.Warn("Ignoring invalid error page in error pages directory must be 100-599", "name", name)
continue continue
} }

View File

@ -74,7 +74,7 @@ func (l *FaviconList) PreProcess(convert func(in []byte) ([]byte, error)) error
// download SVG // download SVG
l.Svg.Raw, err = getFaviconViaRequest(l.Svg.Url) l.Svg.Raw, err = getFaviconViaRequest(l.Svg.Url)
if err != nil { if err != nil {
return fmt.Errorf("[Favicons] Failed to fetch SVG icon: %w", err) return fmt.Errorf("favicons: failed to fetch SVG icon: %w", err)
} }
l.Svg.Hash = hex.EncodeToString(sha256.New().Sum(l.Svg.Raw)) l.Svg.Hash = hex.EncodeToString(sha256.New().Sum(l.Svg.Raw))
} }
@ -84,14 +84,14 @@ func (l *FaviconList) PreProcess(convert func(in []byte) ([]byte, error)) error
// download PNG // download PNG
l.Png.Raw, err = getFaviconViaRequest(l.Png.Url) l.Png.Raw, err = getFaviconViaRequest(l.Png.Url)
if err != nil { if err != nil {
return fmt.Errorf("[Favicons] Failed to fetch PNG icon: %w", err) return fmt.Errorf("favicons: failed to fetch PNG icon: %w", err)
} }
} else if l.Svg != nil { } else if l.Svg != nil {
// generate PNG from SVG // generate PNG from SVG
l.Png = &FaviconImage{} l.Png = &FaviconImage{}
l.Png.Raw, err = convert(l.Svg.Raw) l.Png.Raw, err = convert(l.Svg.Raw)
if err != nil { if err != nil {
return fmt.Errorf("[Favicons] Failed to generate PNG icon: %w", err) return fmt.Errorf("favicons: failed to generate PNG icon: %w", err)
} }
} }
@ -100,19 +100,19 @@ func (l *FaviconList) PreProcess(convert func(in []byte) ([]byte, error)) error
// download ICO // download ICO
l.Ico.Raw, err = getFaviconViaRequest(l.Ico.Url) l.Ico.Raw, err = getFaviconViaRequest(l.Ico.Url)
if err != nil { if err != nil {
return fmt.Errorf("[Favicons] Failed to fetch ICO icon: %w", err) return fmt.Errorf("favicons: failed to fetch ICO icon: %w", err)
} }
} else if l.Png != nil { } else if l.Png != nil {
// generate ICO from PNG // generate ICO from PNG
l.Ico = &FaviconImage{} l.Ico = &FaviconImage{}
decode, err := png.Decode(bytes.NewReader(l.Png.Raw)) decode, err := png.Decode(bytes.NewReader(l.Png.Raw))
if err != nil { if err != nil {
return fmt.Errorf("[Favicons] Failed to decode PNG icon: %w", err) return fmt.Errorf("favicons: failed to decode PNG icon: %w", err)
} }
b := decode.Bounds() b := decode.Bounds()
l.Ico.Raw, err = png2ico.ConvertPngToIco(l.Png.Raw, b.Dx(), b.Dy()) l.Ico.Raw, err = png2ico.ConvertPngToIco(l.Png.Raw, b.Dx(), b.Dy())
if err != nil { if err != nil {
return fmt.Errorf("[Favicons] Failed to generate ICO icon: %w", err) return fmt.Errorf("favicons: failed to generate ICO icon: %w", err)
} }
} }
@ -139,16 +139,16 @@ func (l *FaviconList) genSha256() {
var getFaviconViaRequest = func(url string) ([]byte, error) { var getFaviconViaRequest = func(url string) ([]byte, error) {
req, err := http.NewRequest(http.MethodGet, url, nil) req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("[Favicons] Failed to send request '%s': %w", url, err) return nil, fmt.Errorf("favicons: Failed to send request '%s': %w", url, err)
} }
req.Header.Set("X-Violet-Raw-Favicon", "1") req.Header.Set("X-Violet-Raw-Favicon", "1")
resp, err := http.DefaultClient.Do(req) resp, err := http.DefaultClient.Do(req)
if err != nil { if err != nil {
return nil, fmt.Errorf("[Favicons] Failed to do request '%s': %w", url, err) return nil, fmt.Errorf("favicons: failed to do request '%s': %w", url, err)
} }
rawBody, err := io.ReadAll(resp.Body) rawBody, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
return nil, fmt.Errorf("[Favicons] Failed to read response '%s': %w", url, err) return nil, fmt.Errorf("favicons: failed to read response '%s': %w", url, err)
} }
return rawBody, nil return rawBody, nil
} }

View File

@ -6,12 +6,14 @@ import (
"errors" "errors"
"fmt" "fmt"
"github.com/1f349/violet/database" "github.com/1f349/violet/database"
"github.com/1f349/violet/logger"
"github.com/mrmelon54/rescheduler" "github.com/mrmelon54/rescheduler"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"log"
"sync" "sync"
) )
var Logger = logger.Logger.WithPrefix("Violet Favicons")
var ErrFaviconNotFound = errors.New("favicon not found") var ErrFaviconNotFound = errors.New("favicon not found")
// Favicons is a dynamic favicon generator which supports overwriting favicons // Favicons is a dynamic favicon generator which supports overwriting favicons
@ -66,7 +68,7 @@ func (f *Favicons) threadCompile() {
err := f.internalCompile(favicons) err := f.internalCompile(favicons)
if err != nil { if err != nil {
// log compile errors // log compile errors
log.Printf("[Favicons] Compile failed: %s\n", err) Logger.Info("Compile failed", "err", err)
return return
} }

10
go.mod
View File

@ -5,6 +5,7 @@ go 1.22
require ( require (
github.com/1f349/mjwt v0.2.5 github.com/1f349/mjwt v0.2.5
github.com/AlecAivazis/survey/v2 v2.3.7 github.com/AlecAivazis/survey/v2 v2.3.7
github.com/charmbracelet/log v0.4.0
github.com/golang-migrate/migrate/v4 v4.17.1 github.com/golang-migrate/migrate/v4 v4.17.1
github.com/google/subcommands v1.2.0 github.com/google/subcommands v1.2.0
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
@ -25,25 +26,34 @@ require (
) )
require ( require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/becheran/wildmatch-go v1.0.0 // indirect github.com/becheran/wildmatch-go v1.0.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charmbracelet/lipgloss v0.10.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.53.0 // indirect github.com/prometheus/common v0.53.0 // indirect
github.com/prometheus/procfs v0.14.0 // indirect github.com/prometheus/procfs v0.14.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect
go.uber.org/atomic v1.11.0 // indirect go.uber.org/atomic v1.11.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/sys v0.20.0 // indirect golang.org/x/sys v0.20.0 // indirect
golang.org/x/term v0.20.0 // indirect golang.org/x/term v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect golang.org/x/text v0.15.0 // indirect

23
go.sum
View File

@ -4,18 +4,26 @@ github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkk
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/becheran/wildmatch-go v1.0.0 h1:mE3dGGkTmpKtT4Z+88t8RStG40yN9T+kFEGj2PZFSzA= github.com/becheran/wildmatch-go v1.0.0 h1:mE3dGGkTmpKtT4Z+88t8RStG40yN9T+kFEGj2PZFSzA=
github.com/becheran/wildmatch-go v1.0.0/go.mod h1:gbMvj0NtVdJ15Mg/mH9uxk2R1QCistMyU7d9KFzroX4= github.com/becheran/wildmatch-go v1.0.0/go.mod h1:gbMvj0NtVdJ15Mg/mH9uxk2R1QCistMyU7d9KFzroX4=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s=
github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE=
github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM=
github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMnX7wLTPnnYO4= github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMnX7wLTPnnYO4=
@ -45,6 +53,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
@ -52,6 +62,9 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
@ -67,6 +80,10 @@ github.com/mrmelon54/rescheduler v0.0.3 h1:TrkJL6S7PKvXuo1mvdgRgsILA/pk5L1lrXhV/
github.com/mrmelon54/rescheduler v0.0.3/go.mod h1:q415n6W1xcePPP5Rix6FOiADgcN66BYMyNOsFnNyoWQ= github.com/mrmelon54/rescheduler v0.0.3/go.mod h1:q415n6W1xcePPP5Rix6FOiADgcN66BYMyNOsFnNyoWQ=
github.com/mrmelon54/trie v0.0.3 h1:wZmws84FiGNBZJ00garLyQ2EQhtx0SipVoV7fK8+kZE= github.com/mrmelon54/trie v0.0.3 h1:wZmws84FiGNBZJ00garLyQ2EQhtx0SipVoV7fK8+kZE=
github.com/mrmelon54/trie v0.0.3/go.mod h1:d3hl0YUBSWR3XN4S9BDLkGVzLT4VgwP2mZkBJM6uFpw= github.com/mrmelon54/trie v0.0.3/go.mod h1:d3hl0YUBSWR3XN4S9BDLkGVzLT4VgwP2mZkBJM6uFpw=
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@ -79,6 +96,10 @@ github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+a
github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U= github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
github.com/prometheus/procfs v0.14.0 h1:Lw4VdGGoKEZilJsayHf0B+9YgLGREba2C6xr+Fdfq6s= github.com/prometheus/procfs v0.14.0 h1:Lw4VdGGoKEZilJsayHf0B+9YgLGREba2C6xr+Fdfq6s=
github.com/prometheus/procfs v0.14.0/go.mod h1:XL+Iwz8k8ZabyZfMFHPiilCniixqQarAy5Mu67pHlNQ= github.com/prometheus/procfs v0.14.0/go.mod h1:XL+Iwz8k8ZabyZfMFHPiilCniixqQarAy5Mu67pHlNQ=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po=
@ -94,6 +115,8 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=

12
logger/logger.go Normal file
View File

@ -0,0 +1,12 @@
package logger
import (
"github.com/charmbracelet/log"
"os"
)
var Logger = log.NewWithOptions(os.Stderr, log.Options{
ReportCaller: true,
ReportTimestamp: true,
Prefix: "Violet",
})

View File

@ -2,15 +2,19 @@ package proxy
import ( import (
"crypto/tls" "crypto/tls"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/proxy/websocket" "github.com/1f349/violet/proxy/websocket"
"github.com/google/uuid" "github.com/google/uuid"
"log"
"net" "net"
"net/http" "net/http"
"sync" "sync"
"time" "time"
) )
var loggerSecure = logger.Logger.WithPrefix("Violet Secure Transport")
var loggerInsecure = logger.Logger.WithPrefix("Violet Insecure Transport")
var loggerWebsocket = logger.Logger.WithPrefix("Violet Websocket Transport")
type HybridTransport struct { type HybridTransport struct {
baseDialer *net.Dialer baseDialer *net.Dialer
normalTransport http.RoundTripper normalTransport http.RoundTripper
@ -72,23 +76,23 @@ func NewHybridTransportWithCalls(normal, insecure http.RoundTripper, ws *websock
// SecureRoundTrip calls the secure transport // SecureRoundTrip calls the secure transport
func (h *HybridTransport) SecureRoundTrip(req *http.Request) (*http.Response, error) { func (h *HybridTransport) SecureRoundTrip(req *http.Request) (*http.Response, error) {
u := uuid.New() u := uuid.New()
log.Println("[Transport] Start upgrade:", u) loggerSecure.Info("Start upgrade", "id", u)
defer log.Println("[Transport] Stop upgrade:", u) defer loggerSecure.Info("Stop upgrade", "id", u)
return h.normalTransport.RoundTrip(req) return h.normalTransport.RoundTrip(req)
} }
// InsecureRoundTrip calls the insecure transport // InsecureRoundTrip calls the insecure transport
func (h *HybridTransport) InsecureRoundTrip(req *http.Request) (*http.Response, error) { func (h *HybridTransport) InsecureRoundTrip(req *http.Request) (*http.Response, error) {
u := uuid.New() u := uuid.New()
log.Println("[Transport insecure] Start upgrade:", u) loggerInsecure.Info("Start upgrade", "id", u)
defer log.Println("[Transport insecure] Stop upgrade:", u) defer loggerInsecure.Info("Stop upgrade", "id", u)
return h.insecureTransport.RoundTrip(req) return h.insecureTransport.RoundTrip(req)
} }
// ConnectWebsocket calls the websocket upgrader and thus hijacks the connection // ConnectWebsocket calls the websocket upgrader and thus hijacks the connection
func (h *HybridTransport) ConnectWebsocket(rw http.ResponseWriter, req *http.Request) { func (h *HybridTransport) ConnectWebsocket(rw http.ResponseWriter, req *http.Request) {
u := uuid.New() u := uuid.New()
log.Println("[Websocket] Start upgrade:", u) loggerWebsocket.Info("Start upgrade", "id", u)
h.ws.Upgrade(rw, req) h.ws.Upgrade(rw, req)
log.Println("[Websocket] Stop upgrade:", u) loggerWebsocket.Info("Stop upgrade", "id", u)
} }

View File

@ -1,13 +1,15 @@
package websocket package websocket
import ( import (
"github.com/1f349/violet/logger"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"log"
"net/http" "net/http"
"sync" "sync"
"time" "time"
) )
var Logger = logger.Logger.WithPrefix("Violet Websocket")
var upgrader = websocket.Upgrader{ var upgrader = websocket.Upgrader{
HandshakeTimeout: time.Second * 5, HandshakeTimeout: time.Second * 5,
ReadBufferSize: 1024, ReadBufferSize: 1024,
@ -34,7 +36,7 @@ func NewServer() *Server {
func (s *Server) Upgrade(rw http.ResponseWriter, req *http.Request) { func (s *Server) Upgrade(rw http.ResponseWriter, req *http.Request) {
req.URL.Scheme = "ws" req.URL.Scheme = "ws"
log.Printf("[Websocket] Upgrading request to '%s' from '%s'\n", req.URL.String(), req.Header.Get("Origin")) Logger.Info("Upgrading request", "url", req.URL, "origin", req.Header.Get("Origin"))
c, err := upgrader.Upgrade(rw, req, nil) c, err := upgrader.Upgrade(rw, req, nil)
if err != nil { if err != nil {
@ -54,12 +56,12 @@ func (s *Server) Upgrade(rw http.ResponseWriter, req *http.Request) {
s.conns[c.RemoteAddr().String()] = c s.conns[c.RemoteAddr().String()] = c
s.connLock.Unlock() s.connLock.Unlock()
log.Printf("[Websocket] Dialing: '%s'\n", req.URL.String()) Logger.Info("Dialing", "url", req.URL)
// dial for internal connection // dial for internal connection
ic, _, err := websocket.DefaultDialer.DialContext(req.Context(), req.URL.String(), nil) ic, _, err := websocket.DefaultDialer.DialContext(req.Context(), req.URL.String(), nil)
if err != nil { if err != nil {
log.Printf("[Websocket] Failed to dial '%s': %s\n", req.URL.String(), err) Logger.Info("Failed to dial", "url", req.URL, "err", err)
s.Remove(c) s.Remove(c)
return return
} }
@ -73,7 +75,7 @@ func (s *Server) Upgrade(rw http.ResponseWriter, req *http.Request) {
go s.wsRelay(d2, ic, c) go s.wsRelay(d2, ic, c)
// wait for done signal and close both connections // wait for done signal and close both connections
log.Println("[Websocket] Completed websocket hijacking") Logger.Info("Completed websocket hijacking")
// waiting until d1 or d2 close then automatically defer close both connections // waiting until d1 or d2 close then automatically defer close both connections
select { select {
@ -89,7 +91,7 @@ func (s *Server) wsRelay(done chan struct{}, a, b *websocket.Conn) {
for { for {
mt, message, err := a.ReadMessage() mt, message, err := a.ReadMessage()
if err != nil { if err != nil {
log.Println("Websocket read message error: ", err) Logger.Info("Read message", "err", err)
return return
} }
if b.WriteMessage(mt, message) != nil { if b.WriteMessage(mt, message) != nil {

View File

@ -4,15 +4,17 @@ import (
"context" "context"
_ "embed" _ "embed"
"github.com/1f349/violet/database" "github.com/1f349/violet/database"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/proxy" "github.com/1f349/violet/proxy"
"github.com/1f349/violet/target" "github.com/1f349/violet/target"
"github.com/mrmelon54/rescheduler" "github.com/mrmelon54/rescheduler"
"log"
"net/http" "net/http"
"strings" "strings"
"sync" "sync"
) )
var Logger = logger.Logger.WithPrefix("Violet Manager")
// Manager is a database and mutex wrap around router allowing it to be // Manager is a database and mutex wrap around router allowing it to be
// dynamically regenerated after updating the database of routes. // dynamically regenerated after updating the database of routes.
type Manager struct { type Manager struct {
@ -54,7 +56,7 @@ func (m *Manager) threadCompile() {
// compile router and check errors // compile router and check errors
err := m.internalCompile(router) err := m.internalCompile(router)
if err != nil { if err != nil {
log.Printf("[Manager] Compile failed: %s\n", err) Logger.Info("Compile failed", "err", err)
return return
} }
@ -67,7 +69,7 @@ func (m *Manager) threadCompile() {
// internalCompile is a hidden internal method for querying the database during // internalCompile is a hidden internal method for querying the database during
// the Compile() method. // the Compile() method.
func (m *Manager) internalCompile(router *Router) error { func (m *Manager) internalCompile(router *Router) error {
log.Println("[Manager] Updating routes from database") Logger.Info("Updating routes from database")
// sql or something? // sql or something?
routeRows, err := m.db.GetActiveRoutes(context.Background()) routeRows, err := m.db.GetActiveRoutes(context.Background())

View File

@ -3,11 +3,11 @@ package api
import ( import (
"encoding/json" "encoding/json"
"github.com/1f349/mjwt" "github.com/1f349/mjwt"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/router" "github.com/1f349/violet/router"
"github.com/1f349/violet/target" "github.com/1f349/violet/target"
"github.com/1f349/violet/utils" "github.com/1f349/violet/utils"
"github.com/julienschmidt/httprouter" "github.com/julienschmidt/httprouter"
"log"
"net/http" "net/http"
"strings" "strings"
) )
@ -19,7 +19,7 @@ func SetupTargetApis(r *httprouter.Router, verify mjwt.Verifier, manager *router
routes, err := manager.GetAllRoutes(domains) routes, err := manager.GetAllRoutes(domains)
if err != nil { if err != nil {
log.Printf("[Violet] Failed to get routes from database: %s\n", err) logger.Logger.Infof("Failed to get routes from database: %s\n", err)
apiError(rw, http.StatusInternalServerError, "Failed to get routes from database") apiError(rw, http.StatusInternalServerError, "Failed to get routes from database")
return return
} }
@ -29,7 +29,7 @@ func SetupTargetApis(r *httprouter.Router, verify mjwt.Verifier, manager *router
r.POST("/route", parseJsonAndCheckOwnership[routeSource](verify, "route", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims, t routeSource) { r.POST("/route", parseJsonAndCheckOwnership[routeSource](verify, "route", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims, t routeSource) {
err := manager.InsertRoute(target.RouteWithActive(t)) err := manager.InsertRoute(target.RouteWithActive(t))
if err != nil { if err != nil {
log.Printf("[Violet] Failed to insert route into database: %s\n", err) logger.Logger.Infof("Failed to insert route into database: %s\n", err)
apiError(rw, http.StatusInternalServerError, "Failed to insert route into database") apiError(rw, http.StatusInternalServerError, "Failed to insert route into database")
return return
} }
@ -38,7 +38,7 @@ func SetupTargetApis(r *httprouter.Router, verify mjwt.Verifier, manager *router
r.DELETE("/route", parseJsonAndCheckOwnership[sourceJson](verify, "route", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims, t sourceJson) { r.DELETE("/route", parseJsonAndCheckOwnership[sourceJson](verify, "route", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims, t sourceJson) {
err := manager.DeleteRoute(t.Src) err := manager.DeleteRoute(t.Src)
if err != nil { if err != nil {
log.Printf("[Violet] Failed to delete route from database: %s\n", err) logger.Logger.Infof("Failed to delete route from database: %s\n", err)
apiError(rw, http.StatusInternalServerError, "Failed to delete route from database") apiError(rw, http.StatusInternalServerError, "Failed to delete route from database")
return return
} }
@ -51,7 +51,7 @@ func SetupTargetApis(r *httprouter.Router, verify mjwt.Verifier, manager *router
redirects, err := manager.GetAllRedirects(domains) redirects, err := manager.GetAllRedirects(domains)
if err != nil { if err != nil {
log.Printf("[Violet] Failed to get redirects from database: %s\n", err) logger.Logger.Infof("Failed to get redirects from database: %s\n", err)
apiError(rw, http.StatusInternalServerError, "Failed to get redirects from database") apiError(rw, http.StatusInternalServerError, "Failed to get redirects from database")
return return
} }
@ -61,7 +61,7 @@ func SetupTargetApis(r *httprouter.Router, verify mjwt.Verifier, manager *router
r.POST("/redirect", parseJsonAndCheckOwnership[redirectSource](verify, "redirect", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims, t redirectSource) { r.POST("/redirect", parseJsonAndCheckOwnership[redirectSource](verify, "redirect", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims, t redirectSource) {
err := manager.InsertRedirect(target.RedirectWithActive(t)) err := manager.InsertRedirect(target.RedirectWithActive(t))
if err != nil { if err != nil {
log.Printf("[Violet] Failed to insert redirect into database: %s\n", err) logger.Logger.Infof("Failed to insert redirect into database: %s\n", err)
apiError(rw, http.StatusInternalServerError, "Failed to insert redirect into database") apiError(rw, http.StatusInternalServerError, "Failed to insert redirect into database")
return return
} }
@ -70,7 +70,7 @@ func SetupTargetApis(r *httprouter.Router, verify mjwt.Verifier, manager *router
r.DELETE("/redirect", parseJsonAndCheckOwnership[sourceJson](verify, "redirect", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims, t sourceJson) { r.DELETE("/redirect", parseJsonAndCheckOwnership[sourceJson](verify, "redirect", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params, b AuthClaims, t sourceJson) {
err := manager.DeleteRedirect(t.Src) err := manager.DeleteRedirect(t.Src)
if err != nil { if err != nil {
log.Printf("[Violet] Failed to delete redirect from database: %s\n", err) logger.Logger.Infof("Failed to delete redirect from database: %s\n", err)
apiError(rw, http.StatusInternalServerError, "Failed to delete redirect from database") apiError(rw, http.StatusInternalServerError, "Failed to delete redirect from database")
return return
} }

View File

@ -4,13 +4,13 @@ import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"github.com/1f349/violet/favicons" "github.com/1f349/violet/favicons"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/servers/conf" "github.com/1f349/violet/servers/conf"
"github.com/1f349/violet/servers/metrics" "github.com/1f349/violet/servers/metrics"
"github.com/1f349/violet/utils" "github.com/1f349/violet/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/sethvargo/go-limiter/httplimit" "github.com/sethvargo/go-limiter/httplimit"
"github.com/sethvargo/go-limiter/memorystore" "github.com/sethvargo/go-limiter/memorystore"
"log"
"net/http" "net/http"
"path" "path"
"runtime" "runtime"
@ -21,7 +21,7 @@ import (
// endpoints for the reverse proxy. // endpoints for the reverse proxy.
func NewHttpsServer(conf *conf.Conf, registry *prometheus.Registry) *http.Server { func NewHttpsServer(conf *conf.Conf, registry *prometheus.Registry) *http.Server {
r := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { r := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
log.Printf("[Debug] Request: %s - '%s' - '%s' - '%s' - len: %d - thread: %d\n", req.Method, req.URL.String(), req.RemoteAddr, req.Host, req.ContentLength, runtime.NumGoroutine()) logger.Logger.Debug("Request", "method", req.Method, "url", req.URL, "remote", req.RemoteAddr, "host", req.Host, "length", req.ContentLength, "goroutine", runtime.NumGoroutine())
conf.Router.ServeHTTP(rw, req) conf.Router.ServeHTTP(rw, req)
}) })
favMiddleware := setupFaviconMiddleware(conf.Favicons, r) favMiddleware := setupFaviconMiddleware(conf.Favicons, r)
@ -88,13 +88,13 @@ func setupRateLimiter(rateLimit uint64, next http.Handler) http.Handler {
Interval: time.Minute, Interval: time.Minute,
}) })
if err != nil { if err != nil {
log.Fatalln(err) logger.Logger.Fatal("Failed to initialize memory store", "err", err)
} }
// create a middleware using ips as the key for rate limits // create a middleware using ips as the key for rate limits
middleware, err := httplimit.NewMiddleware(store, httplimit.IPKeyFunc()) middleware, err := httplimit.NewMiddleware(store, httplimit.IPKeyFunc())
if err != nil { if err != nil {
log.Fatalln(err) logger.Logger.Fatal("Failed to initialize httplimit middleware", "err", err)
} }
return middleware.Handle(next) return middleware.Handle(next)
} }

View File

@ -2,6 +2,7 @@ package target
import ( import (
"fmt" "fmt"
"github.com/1f349/violet/logger"
"github.com/1f349/violet/proxy" "github.com/1f349/violet/proxy"
"github.com/1f349/violet/utils" "github.com/1f349/violet/utils"
"github.com/google/uuid" "github.com/google/uuid"
@ -9,7 +10,6 @@ import (
"github.com/rs/cors" "github.com/rs/cors"
"golang.org/x/net/http/httpguts" "golang.org/x/net/http/httpguts"
"io" "io"
"log"
"net" "net"
"net/http" "net/http"
"net/textproto" "net/textproto"
@ -18,6 +18,8 @@ import (
"strings" "strings"
) )
var Logger = logger.Logger.WithPrefix("Violet Serve Route")
// serveApiCors outputs the cors headers to make APIs work. // serveApiCors outputs the cors headers to make APIs work.
var serveApiCors = cors.New(cors.Options{ var serveApiCors = cors.New(cors.Options{
// allow all origins for api requests // allow all origins for api requests
@ -128,7 +130,7 @@ func (r Route) internalServeHTTP(rw http.ResponseWriter, req *http.Request) {
// create the internal request // create the internal request
req2, err := http.NewRequest(req.Method, u.String(), req.Body) req2, err := http.NewRequest(req.Method, u.String(), req.Body)
if err != nil { if err != nil {
log.Printf("[ServeRoute::ServeHTTP()] Error generating new request: %s\n", err) Logger.Warn("Error generating new request", "err", err)
utils.RespondVioletError(rw, http.StatusBadGateway, "error generating new request") utils.RespondVioletError(rw, http.StatusBadGateway, "error generating new request")
return return
} }
@ -179,7 +181,7 @@ func (r Route) internalServeHTTP(rw http.ResponseWriter, req *http.Request) {
resp, err = r.Proxy.SecureRoundTrip(req2) resp, err = r.Proxy.SecureRoundTrip(req2)
} }
if err != nil { if err != nil {
log.Printf("[ServeRoute::ServeHTTP()] Error receiving internal round trip response: %s\n", err) Logger.Warn("Error receiving internal round trip response", "err", err)
utils.RespondVioletError(rw, http.StatusBadGateway, "error receiving internal round trip response") utils.RespondVioletError(rw, http.StatusBadGateway, "error receiving internal round trip response")
return return
} }
@ -191,7 +193,7 @@ func (r Route) internalServeHTTP(rw http.ResponseWriter, req *http.Request) {
if resp.StatusCode == http.StatusLoopDetected { if resp.StatusCode == http.StatusLoopDetected {
u := uuid.New() u := uuid.New()
log.Printf("[ServeRoute::ServeHTTP()] Loop Detected: %s %s '%s' -> '%s'\n", u, req.Method, req.URL.String(), req2.URL.String()) Logger.Warn("Loop Detected", "id", u, "method", req.Method, "url", req.URL, "url2", req2.URL.String())
utils.RespondVioletError(rw, http.StatusLoopDetected, "error loop detected: "+u.String()) utils.RespondVioletError(rw, http.StatusLoopDetected, "error loop detected: "+u.String())
return return
} }

View File

@ -2,33 +2,33 @@ package utils
import ( import (
"errors" "errors"
"log" "github.com/charmbracelet/log"
"net/http" "net/http"
"strings" "strings"
) )
// logHttpServerError is the internal function powering the logging in // logHttpServerError is the internal function powering the logging in
// RunBackgroundHttp and RunBackgroundHttps. // RunBackgroundHttp and RunBackgroundHttps.
func logHttpServerError(prefix string, err error) { func logHttpServerError(logger *log.Logger, err error) {
if err != nil { if err != nil {
if errors.Is(err, http.ErrServerClosed) { if errors.Is(err, http.ErrServerClosed) {
log.Printf("[%s] The http server shutdown successfully\n", prefix) logger.Info("The http server shutdown successfully")
} else { } else {
log.Printf("[%s] Error trying to host the http server: %s\n", prefix, err.Error()) logger.Info("Error trying to host the http server", "err", err.Error())
} }
} }
} }
// RunBackgroundHttp runs a http server and logs when the server closes or // RunBackgroundHttp runs a http server and logs when the server closes or
// errors. // errors.
func RunBackgroundHttp(prefix string, s *http.Server) { func RunBackgroundHttp(logger *log.Logger, s *http.Server) {
logHttpServerError(prefix, s.ListenAndServe()) logHttpServerError(logger, s.ListenAndServe())
} }
// RunBackgroundHttps runs a http server with TLS encryption and logs when the // RunBackgroundHttps runs a http server with TLS encryption and logs when the
// server closes or errors. // server closes or errors.
func RunBackgroundHttps(prefix string, s *http.Server) { func RunBackgroundHttps(logger *log.Logger, s *http.Server) {
logHttpServerError(prefix, s.ListenAndServeTLS("", "")) logHttpServerError(logger, s.ListenAndServeTLS("", ""))
} }
// GetBearer returns the bearer from the Authorization header or an empty string // GetBearer returns the bearer from the Authorization header or an empty string