From 34c0db9dff138afb9d7e09b6095b439e5537475e Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sun, 23 Jan 2022 15:17:40 -0500 Subject: [PATCH] Replace encoding/json with goccy/go-json for cpu and memory usage improvement This new package has significant better resource usage, and we do a _lot_ of JSON parsing in this application, so any amount of improvement becomes significant --- cmd/configure.go | 2 +- cmd/diagnostics.go | 2 +- config/config_docker.go | 2 +- environment/docker/container.go | 16 +++++----------- environment/docker/stats.go | 2 +- go.mod | 5 ++++- go.sum | 5 ++++- parser/parser.go | 16 +++++++--------- remote/http.go | 2 +- remote/types.go | 2 +- router/downloader/downloader.go | 2 +- router/router_server_ws.go | 2 +- router/tokens/websocket.go | 2 +- router/websocket/listeners.go | 3 ++- router/websocket/websocket.go | 2 +- server/filesystem/stat.go | 2 +- server/listeners.go | 2 +- server/manager.go | 2 +- server/resources.go | 4 ---- server/server.go | 5 +++-- system/utils.go | 2 +- 21 files changed, 39 insertions(+), 43 deletions(-) diff --git a/cmd/configure.go b/cmd/configure.go index 978615f..9c89935 100644 --- a/cmd/configure.go +++ b/cmd/configure.go @@ -2,7 +2,6 @@ package cmd import ( "crypto/tls" - "encoding/json" "fmt" "io" "net/http" @@ -14,6 +13,7 @@ import ( "github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2/terminal" + "github.com/goccy/go-json" "github.com/spf13/cobra" "github.com/pterodactyl/wings/config" diff --git a/cmd/diagnostics.go b/cmd/diagnostics.go index cf90ee6..94326a1 100644 --- a/cmd/diagnostics.go +++ b/cmd/diagnostics.go @@ -2,7 +2,6 @@ package cmd import ( "context" - "encoding/json" "errors" "fmt" "io" @@ -20,6 +19,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/parsers/kernel" "github.com/docker/docker/pkg/parsers/operatingsystem" + "github.com/goccy/go-json" "github.com/spf13/cobra" "github.com/pterodactyl/wings/config" diff --git a/config/config_docker.go b/config/config_docker.go index 7fd2034..8ae11f6 100644 --- a/config/config_docker.go +++ b/config/config_docker.go @@ -2,10 +2,10 @@ package config import ( "encoding/base64" - "encoding/json" "sort" "github.com/docker/docker/api/types" + "github.com/goccy/go-json" ) type dockerNetworkInterfaces struct { diff --git a/environment/docker/container.go b/environment/docker/container.go index c531836..69db61e 100644 --- a/environment/docker/container.go +++ b/environment/docker/container.go @@ -3,7 +3,6 @@ package docker import ( "bufio" "context" - "encoding/json" "fmt" "io" "strconv" @@ -12,6 +11,7 @@ import ( "emperror.dev/errors" "github.com/apex/log" + "github.com/buger/jsonparser" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/mount" @@ -364,11 +364,6 @@ func (e *Environment) scanOutput(reader io.ReadCloser) { go e.followOutput() } -type imagePullStatus struct { - Status string `json:"status"` - Progress string `json:"progress"` -} - // Pulls the image from Docker. If there is an error while pulling the image // from the source but the image already exists locally, we will report that // error to the logger but continue with the process. @@ -454,12 +449,11 @@ func (e *Environment) ensureImageExists(image string) error { scanner := bufio.NewScanner(out) for scanner.Scan() { - s := imagePullStatus{} - fmt.Println(scanner.Text()) + b := scanner.Bytes() + status, _ := jsonparser.GetString(b, "status") + progress, _ := jsonparser.GetString(b, "progress") - if err := json.Unmarshal(scanner.Bytes(), &s); err == nil { - e.Events().Publish(environment.DockerImagePullStatus, s.Status+" "+s.Progress) - } + e.Events().Publish(environment.DockerImagePullStatus, status+" "+progress) } if err := scanner.Err(); err != nil { diff --git a/environment/docker/stats.go b/environment/docker/stats.go index 3e14e32..2815799 100644 --- a/environment/docker/stats.go +++ b/environment/docker/stats.go @@ -2,13 +2,13 @@ package docker import ( "context" - "encoding/json" "io" "math" "time" "emperror.dev/errors" "github.com/docker/docker/api/types" + "github.com/goccy/go-json" "github.com/pterodactyl/wings/environment" ) diff --git a/go.mod b/go.mod index c597687..db0fb9b 100644 --- a/go.mod +++ b/go.mod @@ -45,6 +45,10 @@ require ( gopkg.in/yaml.v2 v2.4.0 ) +require github.com/goccy/go-json v0.9.4 + +require golang.org/x/sys v0.0.0-20211110154304-99a53858aa08 // indirect + require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.5.0 // indirect @@ -102,7 +106,6 @@ require ( go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.7.0 // indirect golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 // indirect - golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect golang.org/x/text v0.3.6 // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect diff --git a/go.sum b/go.sum index f361140..e3569ea 100644 --- a/go.sum +++ b/go.sum @@ -371,6 +371,8 @@ github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn github.com/go-playground/validator/v10 v10.8.0 h1:1kAa0fCrnpv+QYdkdcRzrRM7AyYs5o8+jZdJCz9xj6k= github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/goccy/go-json v0.9.4 h1:L8MLKG2mvVXiQu07qB6hmfqeSYQdOnqPot2GhsIwIaI= +github.com/goccy/go-json v0.9.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= @@ -1111,8 +1113,9 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211110154304-99a53858aa08 h1:WecRHqgE09JBkh/584XIE6PMz5KKE/vER4izNUi30AQ= +golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= diff --git a/parser/parser.go b/parser/parser.go index 577abc2..f5d97f4 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -2,7 +2,6 @@ package parser import ( "bufio" - "encoding/json" "os" "path/filepath" "strconv" @@ -14,6 +13,7 @@ import ( "github.com/buger/jsonparser" "github.com/icza/dyno" "github.com/magiconair/properties" + "github.com/goccy/go-json" "gopkg.in/ini.v1" "gopkg.in/yaml.v2" @@ -80,8 +80,8 @@ func (cp ConfigurationParser) String() string { return string(cp) } -// Defines a configuration file for the server startup. These will be looped over -// and modified before the server finishes booting. +// ConfigurationFile defines a configuration file for the server startup. These +// will be looped over and modified before the server finishes booting. type ConfigurationFile struct { FileName string `json:"file"` Parser ConfigurationParser `json:"parser"` @@ -92,12 +92,10 @@ type ConfigurationFile struct { configuration []byte } -// Custom unmarshaler for configuration files. If there is an error while parsing out the -// replacements, don't fail the entire operation, just log a global warning so someone can -// find the issue, and return an empty array of replacements. -// -// I imagine people will notice configuration replacement isn't working correctly and then -// the logs should help better expose that issue. +// UnmarshalJSON is a custom unmarshaler for configuration files. If there is an +// error while parsing out the replacements, don't fail the entire operation, +// just log a global warning so someone can find the issue, and return an empty +// array of replacements. func (f *ConfigurationFile) UnmarshalJSON(data []byte) error { var m map[string]*json.RawMessage if err := json.Unmarshal(data, &m); err != nil { diff --git a/remote/http.go b/remote/http.go index 1229de2..f5f3063 100644 --- a/remote/http.go +++ b/remote/http.go @@ -3,7 +3,6 @@ package remote import ( "bytes" "context" - "encoding/json" "fmt" "io" "net/http" @@ -14,6 +13,7 @@ import ( "emperror.dev/errors" "github.com/apex/log" "github.com/cenkalti/backoff/v4" + "github.com/goccy/go-json" "github.com/pterodactyl/wings/system" ) diff --git a/remote/types.go b/remote/types.go index b5696bf..37ef462 100644 --- a/remote/types.go +++ b/remote/types.go @@ -1,11 +1,11 @@ package remote import ( - "encoding/json" "regexp" "strings" "github.com/apex/log" + "github.com/goccy/go-json" "github.com/pterodactyl/wings/parser" ) diff --git a/router/downloader/downloader.go b/router/downloader/downloader.go index 2527d46..c7c7788 100644 --- a/router/downloader/downloader.go +++ b/router/downloader/downloader.go @@ -2,7 +2,6 @@ package downloader import ( "context" - "encoding/json" "fmt" "io" "net" @@ -15,6 +14,7 @@ import ( "emperror.dev/errors" "github.com/google/uuid" + "github.com/goccy/go-json" "github.com/pterodactyl/wings/server" ) diff --git a/router/router_server_ws.go b/router/router_server_ws.go index ed44397..5d9b6cc 100644 --- a/router/router_server_ws.go +++ b/router/router_server_ws.go @@ -2,11 +2,11 @@ package router import ( "context" - "encoding/json" "time" "github.com/gin-gonic/gin" ws "github.com/gorilla/websocket" + "github.com/goccy/go-json" "github.com/pterodactyl/wings/router/middleware" "github.com/pterodactyl/wings/router/websocket" diff --git a/router/tokens/websocket.go b/router/tokens/websocket.go index a4c6309..47708ad 100644 --- a/router/tokens/websocket.go +++ b/router/tokens/websocket.go @@ -1,13 +1,13 @@ package tokens import ( - "encoding/json" "strings" "sync" "time" "github.com/apex/log" "github.com/gbrlsnchs/jwt/v3" + "github.com/goccy/go-json" ) // The time at which Wings was booted. No JWT's created before this time are allowed to diff --git a/router/websocket/listeners.go b/router/websocket/listeners.go index e6b1db4..6956551 100644 --- a/router/websocket/listeners.go +++ b/router/websocket/listeners.go @@ -2,11 +2,12 @@ package websocket import ( "context" - "encoding/json" "sync" "time" "emperror.dev/errors" + "github.com/goccy/go-json" + "github.com/pterodactyl/wings/events" "github.com/pterodactyl/wings/server" ) diff --git a/router/websocket/websocket.go b/router/websocket/websocket.go index 92548ef..0d88627 100644 --- a/router/websocket/websocket.go +++ b/router/websocket/websocket.go @@ -2,7 +2,6 @@ package websocket import ( "context" - "encoding/json" "fmt" "net/http" "strings" @@ -14,6 +13,7 @@ import ( "github.com/gbrlsnchs/jwt/v3" "github.com/google/uuid" "github.com/gorilla/websocket" + "github.com/goccy/go-json" "github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/environment" diff --git a/server/filesystem/stat.go b/server/filesystem/stat.go index a255ff6..cc25827 100644 --- a/server/filesystem/stat.go +++ b/server/filesystem/stat.go @@ -1,12 +1,12 @@ package filesystem import ( - "encoding/json" "os" "strconv" "time" "github.com/gabriel-vasile/mimetype" + "github.com/goccy/go-json" ) type Stat struct { diff --git a/server/listeners.go b/server/listeners.go index bc08c26..ea36373 100644 --- a/server/listeners.go +++ b/server/listeners.go @@ -125,7 +125,7 @@ func (s *Server) StartEventListeners() { l.Trigger() } - s.emitProcUsage() + s.Events().Publish(StatsEvent, s.Proc()) }() case e := <-docker: go func() { diff --git a/server/manager.go b/server/manager.go index 0cd50fd..815b362 100644 --- a/server/manager.go +++ b/server/manager.go @@ -2,7 +2,6 @@ package server import ( "context" - "encoding/json" "fmt" "io" "os" @@ -14,6 +13,7 @@ import ( "emperror.dev/errors" "github.com/apex/log" "github.com/gammazero/workerpool" + "github.com/goccy/go-json" "github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/environment" diff --git a/server/resources.go b/server/resources.go index 81c2c87..03f2ae5 100644 --- a/server/resources.go +++ b/server/resources.go @@ -50,7 +50,3 @@ func (ru *ResourceUsage) Reset() { ru.Network.TxBytes = 0 ru.Network.RxBytes = 0 } - -func (s *Server) emitProcUsage() { - s.Events().Publish(StatsEvent, s.Proc()) -} diff --git a/server/server.go b/server/server.go index e6fd66a..47f2f8c 100644 --- a/server/server.go +++ b/server/server.go @@ -2,7 +2,6 @@ package server import ( "context" - "encoding/json" "fmt" "net/http" "os" @@ -12,6 +11,8 @@ import ( "emperror.dev/errors" "github.com/apex/log" "github.com/creasty/defaults" + "github.com/goccy/go-json" + "github.com/pterodactyl/wings/config" "github.com/pterodactyl/wings/environment" "github.com/pterodactyl/wings/events" @@ -312,7 +313,7 @@ func (s *Server) OnStateChange() { // views in the Panel correctly display 0. if st == environment.ProcessOfflineState { s.resources.Reset() - s.emitProcUsage() + s.Events().Publish(StatsEvent, s.Proc()) } // If server was in an online state, and is now in an offline state we should handle diff --git a/system/utils.go b/system/utils.go index 94f00b5..b6a2894 100644 --- a/system/utils.go +++ b/system/utils.go @@ -4,7 +4,6 @@ import ( "bufio" "bytes" "context" - "encoding/json" "fmt" "io" "strconv" @@ -12,6 +11,7 @@ import ( "time" "emperror.dev/errors" + "github.com/goccy/go-json" ) var (