Refactor: Rename NanoKVM to BatchuKVM and update server URL
This commit is contained in:
122
server/config/config.go
Normal file
122
server/config/config.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var (
|
||||
instance Config
|
||||
once sync.Once
|
||||
)
|
||||
|
||||
func GetInstance() *Config {
|
||||
once.Do(initialize)
|
||||
|
||||
return &instance
|
||||
}
|
||||
|
||||
func initialize() {
|
||||
if err := readByFile(); err != nil {
|
||||
if errors.As(err, &viper.ConfigFileNotFoundError{}) {
|
||||
create()
|
||||
}
|
||||
|
||||
if err = readByDefault(); err != nil {
|
||||
log.Fatalf("Failed to read default configuration!")
|
||||
}
|
||||
|
||||
log.Println("using default configuration")
|
||||
}
|
||||
|
||||
if err := validate(); err != nil {
|
||||
log.Fatalf("Failed to validate configuration!")
|
||||
}
|
||||
|
||||
if err := viper.Unmarshal(&instance); err != nil {
|
||||
log.Fatalf("Failed to parse configuration: %s", err)
|
||||
}
|
||||
|
||||
checkDefaultValue()
|
||||
|
||||
if instance.Authentication == "disable" {
|
||||
log.Println("NOTICE: Authentication is disabled! Please ensure your service is secure!")
|
||||
}
|
||||
|
||||
log.Println("config loaded successfully")
|
||||
}
|
||||
|
||||
func readByFile() error {
|
||||
viper.SetConfigName("server")
|
||||
viper.SetConfigType("yaml")
|
||||
viper.AddConfigPath("/etc/kvm/")
|
||||
|
||||
return viper.ReadInConfig()
|
||||
}
|
||||
|
||||
func readByDefault() error {
|
||||
data, err := yaml.Marshal(defaultConfig)
|
||||
if err != nil {
|
||||
log.Printf("failed to marshal default config: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return viper.ReadConfig(bytes.NewBuffer(data))
|
||||
}
|
||||
|
||||
// Create configuration file.
|
||||
func create() {
|
||||
var (
|
||||
file *os.File
|
||||
data []byte
|
||||
err error
|
||||
)
|
||||
|
||||
_ = os.MkdirAll("/etc/kvm", 0o644)
|
||||
|
||||
file, err = os.OpenFile("/etc/kvm/server.yaml", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644)
|
||||
if err != nil {
|
||||
log.Printf("open config failed: %s", err)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
_ = file.Close()
|
||||
}()
|
||||
|
||||
if data, err = yaml.Marshal(defaultConfig); err != nil {
|
||||
log.Printf("failed to marshal default config: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = file.Write(data); err != nil {
|
||||
log.Printf("failed to save config: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = file.Sync(); err != nil {
|
||||
log.Printf("failed to sync config: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("create file /etc/kvm/server.yaml with default configuration")
|
||||
}
|
||||
|
||||
// Validate the configuration. This is to ensure compatibility with earlier versions.
|
||||
func validate() error {
|
||||
if viper.GetInt("port.http") > 0 && viper.GetInt("port.https") > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
_ = os.Remove("/etc/kvm/server.yaml")
|
||||
log.Println("delete empty configuration file")
|
||||
|
||||
create()
|
||||
|
||||
return readByDefault()
|
||||
}
|
||||
50
server/config/default.go
Normal file
50
server/config/default.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package config
|
||||
|
||||
var defaultConfig = &Config{
|
||||
Proto: "http",
|
||||
Port: Port{
|
||||
Http: 80,
|
||||
Https: 443,
|
||||
},
|
||||
Cert: Cert{
|
||||
Crt: "server.crt",
|
||||
Key: "server.key",
|
||||
},
|
||||
Logger: Logger{
|
||||
Level: "info",
|
||||
File: "stdout",
|
||||
},
|
||||
JWT: JWT{
|
||||
SecretKey: "",
|
||||
RefreshTokenDuration: 2678400,
|
||||
RevokeTokensOnLogout: true,
|
||||
},
|
||||
Stun: "stun.l.google.com:19302",
|
||||
Turn: Turn{
|
||||
TurnAddr: "",
|
||||
TurnUser: "",
|
||||
TurnCred: "",
|
||||
},
|
||||
Authentication: "enable",
|
||||
}
|
||||
|
||||
func checkDefaultValue() {
|
||||
if instance.JWT.SecretKey == "" {
|
||||
instance.JWT.SecretKey = generateRandomSecretKey()
|
||||
instance.JWT.RevokeTokensOnLogout = true
|
||||
}
|
||||
|
||||
if instance.JWT.RefreshTokenDuration == 0 {
|
||||
instance.JWT.RefreshTokenDuration = 2678400
|
||||
}
|
||||
|
||||
if instance.Stun == "" {
|
||||
instance.Stun = "stun.l.google.com:19302"
|
||||
}
|
||||
|
||||
if instance.Authentication == "" {
|
||||
instance.Authentication = "enable"
|
||||
}
|
||||
|
||||
instance.Hardware = getHardware()
|
||||
}
|
||||
45
server/config/file.go
Normal file
45
server/config/file.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const ConfigurationFile = "/etc/kvm/server.yaml"
|
||||
|
||||
func Read() (*Config, error) {
|
||||
data, err := os.ReadFile(ConfigurationFile)
|
||||
if err != nil {
|
||||
log.Errorf("failed to read config: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var conf Config
|
||||
|
||||
if err := yaml.Unmarshal(data, &conf); err != nil {
|
||||
log.Fatalf("failed to unmarshal config: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugf("read %s successfully", ConfigurationFile)
|
||||
return &conf, nil
|
||||
}
|
||||
|
||||
func Write(conf *Config) error {
|
||||
data, err := yaml.Marshal(&conf)
|
||||
if err != nil {
|
||||
log.Errorf("failed to marshal config: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.WriteFile(ConfigurationFile, data, 0644)
|
||||
if err != nil {
|
||||
log.Errorf("failed to write config: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugf("write to %s successfully", ConfigurationFile)
|
||||
return nil
|
||||
}
|
||||
95
server/config/hardware.go
Normal file
95
server/config/hardware.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type HWVersion int
|
||||
|
||||
const (
|
||||
HWVersionAlpha HWVersion = iota
|
||||
HWVersionBeta
|
||||
HWVersionPcie
|
||||
|
||||
HWVersionFile = "/etc/kvm/hw"
|
||||
)
|
||||
|
||||
var HWAlpha = Hardware{
|
||||
Version: HWVersionAlpha,
|
||||
GPIOReset: "/sys/class/gpio/gpio507/value",
|
||||
GPIOPower: "/sys/class/gpio/gpio503/value",
|
||||
GPIOPowerLED: "/sys/class/gpio/gpio504/value",
|
||||
GPIOHDDLed: "/sys/class/gpio/gpio505/value",
|
||||
}
|
||||
|
||||
var HWBeta = Hardware{
|
||||
Version: HWVersionBeta,
|
||||
GPIOReset: "/sys/class/gpio/gpio505/value",
|
||||
GPIOPower: "/sys/class/gpio/gpio503/value",
|
||||
GPIOPowerLED: "/sys/class/gpio/gpio504/value",
|
||||
GPIOHDDLed: "",
|
||||
}
|
||||
|
||||
var HWPcie = Hardware{
|
||||
Version: HWVersionPcie,
|
||||
GPIOReset: "/sys/class/gpio/gpio505/value",
|
||||
GPIOPower: "/sys/class/gpio/gpio503/value",
|
||||
GPIOPowerLED: "/sys/class/gpio/gpio504/value",
|
||||
GPIOHDDLed: "",
|
||||
}
|
||||
|
||||
func (h HWVersion) String() string {
|
||||
switch h {
|
||||
case HWVersionAlpha:
|
||||
return "Alpha"
|
||||
case HWVersionBeta:
|
||||
return "Beta"
|
||||
case HWVersionPcie:
|
||||
return "PCIE"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func GetHwVersion() HWVersion {
|
||||
content, err := os.ReadFile(HWVersionFile)
|
||||
if err != nil {
|
||||
return HWVersionAlpha
|
||||
}
|
||||
|
||||
version := strings.ReplaceAll(string(content), "\n", "")
|
||||
switch version {
|
||||
case "alpha":
|
||||
return HWVersionAlpha
|
||||
case "beta":
|
||||
return HWVersionBeta
|
||||
case "pcie":
|
||||
return HWVersionPcie
|
||||
default:
|
||||
return HWVersionAlpha
|
||||
}
|
||||
}
|
||||
|
||||
func getHardware() (h Hardware) {
|
||||
version := GetHwVersion()
|
||||
|
||||
switch version {
|
||||
case HWVersionAlpha:
|
||||
h = HWAlpha
|
||||
|
||||
case HWVersionBeta:
|
||||
h = HWBeta
|
||||
|
||||
case HWVersionPcie:
|
||||
h = HWPcie
|
||||
|
||||
default:
|
||||
h = HWAlpha
|
||||
log.Errorf("Unsupported hardware version: %s", version)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
28
server/config/jwt.go
Normal file
28
server/config/jwt.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// RegenerateSecretKey regenerate secret key when logout
|
||||
func RegenerateSecretKey() {
|
||||
if instance.JWT.RevokeTokensOnLogout {
|
||||
instance.JWT.SecretKey = generateRandomSecretKey()
|
||||
}
|
||||
}
|
||||
|
||||
// Generate random string for secret key.
|
||||
func generateRandomSecretKey() string {
|
||||
b := make([]byte, 64)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
currentTime := time.Now().UnixNano()
|
||||
timeString := fmt.Sprintf("%d", currentTime)
|
||||
return fmt.Sprintf("%064s", timeString)
|
||||
}
|
||||
|
||||
return base64.URLEncoding.EncodeToString(b)
|
||||
}
|
||||
49
server/config/types.go
Normal file
49
server/config/types.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package config
|
||||
|
||||
type Config struct {
|
||||
Proto string `yaml:"proto"`
|
||||
Port Port `yaml:"port"`
|
||||
Cert Cert `yaml:"cert"`
|
||||
Logger Logger `yaml:"logger"`
|
||||
Authentication string `yaml:"authentication"`
|
||||
JWT JWT `yaml:"jwt"`
|
||||
Stun string `yaml:"stun"`
|
||||
Turn Turn `yaml:"turn"`
|
||||
|
||||
Hardware Hardware `yaml:"-"`
|
||||
}
|
||||
|
||||
type Logger struct {
|
||||
Level string `yaml:"level"`
|
||||
File string `yaml:"file"`
|
||||
}
|
||||
|
||||
type Port struct {
|
||||
Http int `yaml:"http"`
|
||||
Https int `yaml:"https"`
|
||||
}
|
||||
|
||||
type Cert struct {
|
||||
Crt string `yaml:"crt"`
|
||||
Key string `yaml:"key"`
|
||||
}
|
||||
|
||||
type JWT struct {
|
||||
SecretKey string `yaml:"secretKey"`
|
||||
RefreshTokenDuration uint64 `yaml:"refreshTokenDuration"`
|
||||
RevokeTokensOnLogout bool `yaml:"revokeTokensOnLogout"`
|
||||
}
|
||||
|
||||
type Turn struct {
|
||||
TurnAddr string `yaml:"turnAddr"`
|
||||
TurnUser string `yaml:"turnUser"`
|
||||
TurnCred string `yaml:"turnCred"`
|
||||
}
|
||||
|
||||
type Hardware struct {
|
||||
Version HWVersion `yaml:"-"`
|
||||
GPIOReset string `yaml:"-"`
|
||||
GPIOPower string `yaml:"-"`
|
||||
GPIOPowerLED string `yaml:"-"`
|
||||
GPIOHDDLed string `yaml:"-"`
|
||||
}
|
||||
Reference in New Issue
Block a user