tytanium/init.go

151 lines
4.6 KiB
Go

package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
"github.com/spf13/viper"
"log"
"os"
"time"
"tytanium/constants"
"tytanium/global"
"tytanium/logger"
)
const (
mebibyte = 1 << 20
minute = 60000
characterTagLengthEncoded = 12
)
func init() {
fmt.Printf("[ ⬢ Tytanium v%s ]\n", constants.Version)
initConfiguration()
initLogger()
checkStorage()
initRedis()
log.Println("[init] Initial checks completed")
}
func initConfiguration() {
viper.SetConfigName("config")
viper.AddConfigPath("./conf/")
viper.AutomaticEnv()
viper.SetConfigType("yml")
if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
log.Fatalf("No config file set, %v", err)
} else {
log.Fatalf("Error reading config file, %v", err)
}
}
viper.SetDefault("Storage.Directory", "files")
viper.SetDefault("Storage.MaxSize", 50*mebibyte)
viper.SetDefault("Storage.IDLength", 5)
viper.SetDefault("RateLimit.ResetAfter", minute)
viper.SetDefault("RateLimit.Path.Upload", 10)
viper.SetDefault("RateLimit.Path.Global", 60)
viper.SetDefault("RateLimit.Bandwidth.ResetAfter", 5*minute)
viper.SetDefault("RateLimit.Bandwidth.Download", 500*mebibyte)
viper.SetDefault("RateLimit.Bandwidth.Upload", 1000*mebibyte)
viper.SetDefault("Server.Port", 3030)
viper.SetDefault("Server.Concurrency", 128*4)
viper.SetDefault("Server.ReadTimeout", 5*minute)
viper.SetDefault("Server.WriteTimeout", 5*minute)
viper.SetDefault("StatsCollectionInterval", 30000)
viper.SetDefault("Logging.Enabled", true)
viper.SetDefault("Logging.LogFile", "log.txt")
viper.SetDefault("Encryption.EncryptionKeyLength", 12)
err := viper.Unmarshal(&global.Configuration)
if err != nil {
log.Fatalf("Unable to decode into struct, %v", err)
}
if len(global.Configuration.Domain) == 0 {
log.Fatalf("Domain must be set in the configuration.")
}
if len(global.Configuration.Encryption.Nonce) == 0 {
log.Fatalf("You must set a nonce for encryption purposes. (Under Encryption.Nonce, use any string you want. It does not need to be secret.)")
}
if len(global.Configuration.Security.MasterKey) == 0 {
log.Println("Warning: Master key has not set in your configuration. Anyone on the Internet has permission to upload!")
if !global.Configuration.Security.DisableEmptyMasterKeyWarning {
log.Println("Continuing in 5 seconds... (you can set Security.DisableEmptyMasterKeyWarning to true to disable this in the configuration)")
time.Sleep(time.Second * 5)
}
}
// Domain length + 1 byte for "/"
// ID length * 12 (%00%00%00%00)
// Extension length * 12
// 9 (?enc_key=) * 12
// Encryption key length * 12
constants.PathLengthLimitBytes =
(len(global.Configuration.Domain) + 1) +
(global.Configuration.Storage.IDLength * characterTagLengthEncoded) +
(constants.ExtensionLengthLimit * characterTagLengthEncoded) +
(9 * characterTagLengthEncoded) +
(global.Configuration.Encryption.EncryptionKeyLength * characterTagLengthEncoded)
log.Println("[init] Loaded configuration")
}
func initLogger() {
if !global.Configuration.Logging.Enabled {
return
}
file, err := os.OpenFile(global.Configuration.Logging.LogFile, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0644)
if err != nil {
log.Fatalf("Failed to open log file! %v", err)
}
logger.InfoLogger = log.New(file, "info:", log.Ldate|log.Ltime|log.LUTC|log.Lshortfile)
logger.ErrorLogger = log.New(file, "error:", log.Ldate|log.Ltime|log.LUTC|log.Lshortfile)
log.Println("[init] Loggers initialized, output file: " + global.Configuration.Logging.LogFile)
}
func checkStorage() {
i, err := os.Stat(global.Configuration.Storage.Directory)
if err != nil {
if os.IsNotExist(err) {
log.Fatalf("The storage directory %s doesn't exist. Did you forget to create it?", global.Configuration.Storage.Directory)
} else {
log.Fatalf("Can't stat the files directory, %v", err)
}
}
if i != nil && !i.IsDir() {
log.Fatalf("Specified storage path (%s) is not a directory or not usable.", global.Configuration.Storage.Directory)
}
log.Println("[init] Storage directory is OK")
}
func initRedis() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
global.RedisClient = redis.NewClient(&redis.Options{
Addr: global.Configuration.Redis.URI,
Password: global.Configuration.Redis.Password,
DB: global.Configuration.Redis.DB,
})
status := global.RedisClient.Ping(ctx).Err()
if status != nil {
cancel()
log.Fatalf("Could not ping Redis database, %v", status.Error())
}
cancel()
log.Println("[init] Redis database connection established")
}