2019-04-20 23:20:08 +00:00
|
|
|
package server
|
|
|
|
|
2020-01-18 22:04:26 +00:00
|
|
|
import (
|
|
|
|
"fmt"
|
2020-08-11 04:38:42 +00:00
|
|
|
"sync"
|
|
|
|
"time"
|
2021-01-10 01:22:39 +00:00
|
|
|
|
|
|
|
"github.com/mitchellh/colorstring"
|
2022-10-06 15:58:42 +00:00
|
|
|
|
2021-01-10 01:22:39 +00:00
|
|
|
"github.com/pterodactyl/wings/config"
|
|
|
|
"github.com/pterodactyl/wings/system"
|
2020-01-18 22:04:26 +00:00
|
|
|
)
|
2019-04-20 23:20:08 +00:00
|
|
|
|
2021-04-03 18:11:36 +00:00
|
|
|
// appName is a local cache variable to avoid having to make expensive copies of
|
|
|
|
// the configuration every time we need to send output along to the websocket for
|
|
|
|
// a server.
|
|
|
|
var appName string
|
2021-08-15 23:46:55 +00:00
|
|
|
var appNameSync sync.Once
|
|
|
|
|
2022-01-31 00:31:04 +00:00
|
|
|
// PublishConsoleOutputFromDaemon sends output to the server console formatted
|
|
|
|
// to appear correctly as being sent from Wings.
|
|
|
|
func (s *Server) PublishConsoleOutputFromDaemon(data string) {
|
|
|
|
appNameSync.Do(func() {
|
|
|
|
appName = config.Get().AppName
|
|
|
|
})
|
|
|
|
s.Events().Publish(
|
|
|
|
ConsoleOutputEvent,
|
|
|
|
colorstring.Color(fmt.Sprintf("[yellow][bold][%s Daemon]:[default] %s", appName, data)),
|
|
|
|
)
|
2020-09-18 03:13:04 +00:00
|
|
|
}
|
2020-08-11 04:38:42 +00:00
|
|
|
|
2022-01-31 00:31:04 +00:00
|
|
|
// Throttler returns the throttler instance for the server or creates a new one.
|
|
|
|
func (s *Server) Throttler() *ConsoleThrottle {
|
|
|
|
s.throttleOnce.Do(func() {
|
|
|
|
throttles := config.Get().Throttles
|
|
|
|
period := time.Duration(throttles.Period) * time.Millisecond
|
2019-04-20 23:20:08 +00:00
|
|
|
|
2022-01-31 00:31:04 +00:00
|
|
|
s.throttler = newConsoleThrottle(throttles.Lines, period)
|
|
|
|
s.throttler.strike = func() {
|
|
|
|
s.PublishConsoleOutputFromDaemon(fmt.Sprintf("Server is outputting console data too quickly -- throttling..."))
|
2020-09-18 03:13:04 +00:00
|
|
|
}
|
2022-01-31 00:31:04 +00:00
|
|
|
})
|
|
|
|
return s.throttler
|
2020-09-18 03:13:04 +00:00
|
|
|
}
|
2020-08-11 04:38:42 +00:00
|
|
|
|
2022-01-31 00:31:04 +00:00
|
|
|
type ConsoleThrottle struct {
|
|
|
|
limit *system.Rate
|
|
|
|
lock *system.Locker
|
|
|
|
strike func()
|
2020-08-11 04:38:42 +00:00
|
|
|
}
|
|
|
|
|
2022-01-31 00:31:04 +00:00
|
|
|
func newConsoleThrottle(lines uint64, period time.Duration) *ConsoleThrottle {
|
|
|
|
return &ConsoleThrottle{
|
|
|
|
limit: system.NewRate(lines, period),
|
|
|
|
lock: system.NewLocker(),
|
|
|
|
}
|
2020-01-18 22:04:26 +00:00
|
|
|
}
|
|
|
|
|
2022-01-31 00:31:04 +00:00
|
|
|
// Allow checks if the console is allowed to process more output data, or if too
|
|
|
|
// much has already been sent over the line. If there is too much output the
|
|
|
|
// strike callback function is triggered, but only if it has not already been
|
|
|
|
// triggered at this point in the process.
|
2020-08-11 04:38:42 +00:00
|
|
|
//
|
2022-01-31 00:31:04 +00:00
|
|
|
// If output is allowed, the lock on the throttler is released and the next time
|
|
|
|
// it is triggered the strike function will be re-executed.
|
|
|
|
func (ct *ConsoleThrottle) Allow() bool {
|
|
|
|
if !ct.limit.Try() {
|
|
|
|
if err := ct.lock.Acquire(); err == nil {
|
|
|
|
if ct.strike != nil {
|
|
|
|
ct.strike()
|
|
|
|
}
|
2020-09-18 03:13:04 +00:00
|
|
|
}
|
2022-01-31 00:31:04 +00:00
|
|
|
return false
|
2020-09-18 03:13:04 +00:00
|
|
|
}
|
2022-01-31 00:31:04 +00:00
|
|
|
ct.lock.Release()
|
|
|
|
return true
|
2020-08-11 04:38:42 +00:00
|
|
|
}
|
|
|
|
|
2022-01-31 00:31:04 +00:00
|
|
|
// Reset resets the console throttler internal rate limiter and overage counter.
|
|
|
|
func (ct *ConsoleThrottle) Reset() {
|
|
|
|
ct.limit.Reset()
|
2020-01-18 22:04:26 +00:00
|
|
|
}
|