diff options
| -rw-r--r-- | .gitignore | 48 | ||||
| -rw-r--r-- | Makefile | 45 | ||||
| -rw-r--r-- | config/config.go | 70 | ||||
| -rw-r--r-- | go.mod | 5 | ||||
| -rw-r--r-- | go.sum | 2 | ||||
| -rw-r--r-- | metachan/main.go | 17 | ||||
| -rw-r--r-- | types/logger.go | 34 | ||||
| -rw-r--r-- | types/server.go | 16 | ||||
| -rw-r--r-- | utils/logger/logger.go | 95 |
9 files changed, 332 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6c40cb4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,48 @@ +# gitignore for the metachan project +### Go ### + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Vendor directory (for Go modules) +# vendor/ + +# Go workspace file +go.work + +# Binary build artifacts +bin/ + +# Temporary cache and log files +*.tmp +*.temp +*.cache +*.log + +# IDE specific files +.vscode/ +.idea/ +*.iml + +# OS specific files +.DS_Store +Thumbs.db + +# Backup files +*~ +*.bak +*.orig +*.swp + +# Environment files +.env
\ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..18d59ac --- /dev/null +++ b/Makefile @@ -0,0 +1,45 @@ +BINARY_NAME=metachan +BUILD_PATH=bin/$(BINARY_NAME) +MAIN_PATH=$(BINARY_NAME)/main.go +ENV_PATH=.env + +.PHONY: setup clean build run dev all + +define ensure_setup + @if [ ! -f $(ENV_PATH) ]; then \ + echo "Running setup first..."; \ + $(MAKE) -s setup; \ + fi +endef + +setup: + @echo "Setting up environment..." + @go mod download + @if [ ! -f $(ENV_PATH) ]; then cp .env.example $(ENV_PATH); fi + @echo "Environment setup complete." + +clean: + @echo "Cleaning up..." + @rm -rf bin + @echo "Cleanup complete." + +build: + $(call ensure_setup) + @echo "Building..." + @go build -o $(BUILD_PATH) $(MAIN_PATH) || true + @echo "Build complete." + +run: + $(call ensure_setup) + @if [ ! -f $(BUILD_PATH) ]; then echo "Binary not found. Building binary..."; $(MAKE) -s build; fi + @echo "Running..." + @$(BUILD_PATH) || true + +dev: + $(call ensure_setup) + @echo "Running in development mode..." + @go run $(MAIN_PATH) || true + +all: setup clean build run + +.SILENT:
\ No newline at end of file diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..2d1c418 --- /dev/null +++ b/config/config.go @@ -0,0 +1,70 @@ +package config + +import ( + "metachan/types" + "metachan/utils/logger" + "os" + "strconv" + "strings" + + "github.com/joho/godotenv" +) + +var Config *types.ServerConfig + +func init() { + logOptions := types.LogOptions{ + Timestamp: true, + Prefix: "Config", + Level: types.Error, + Fatal: true, + } + + if err := godotenv.Load(); err != nil { + logger.Log("Error loading environment variables", logOptions) + } + + Config = &types.ServerConfig{ + DatabaseDriver: types.DatabaseDriver(getEnv("DB_DRIVER")), + DataSourceName: getEnv("DSN"), + Port: getIntEnv("PORT"), + } + + switch Config.DatabaseDriver { + case types.SQLite, types.MySQL, types.Postgres, types.SQLServer: + default: + logger.Log("Invalid database driver or database driver not set. Valid options are: sqlite, mysql, postgres, sqlserver", logOptions) + } + + if Config.DataSourceName == "" { + logger.Log("Invalid data source name or data source name not set", logOptions) + } + + if Config.Port == 0 { + logger.Log("Invalid port or port not set", logOptions) + } + + logOptions.Level = types.Success + logOptions.Fatal = false + logger.Log("Config initialized successfully", logOptions) +} + +func getEnv(key string) string { + value, exists := os.LookupEnv(key) + if !exists { + return "" + } + return strings.TrimSpace(value) +} + +func getIntEnv(key string) int { + value := getEnv(key) + if value == "" { + return 0 + } + i, err := strconv.Atoi(value) + if err != nil { + return 0 + } + return i +} @@ -0,0 +1,5 @@ +module metachan + +go 1.24.1 + +require github.com/joho/godotenv v1.5.1 @@ -0,0 +1,2 @@ +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= diff --git a/metachan/main.go b/metachan/main.go new file mode 100644 index 0000000..e996ce6 --- /dev/null +++ b/metachan/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "fmt" + "metachan/config" + "metachan/types" + "metachan/utils/logger" +) + +func main() { + logger.Log(fmt.Sprintf("Server started on port %d. Database Driver is: %s. Configured DSN is: %s", config.Config.Port, config.Config.DatabaseDriver, config.Config.DataSourceName), types.LogOptions{ + Timestamp: true, + Prefix: "Main", + Level: types.Info, + Fatal: false, + }) +} diff --git a/types/logger.go b/types/logger.go new file mode 100644 index 0000000..a913312 --- /dev/null +++ b/types/logger.go @@ -0,0 +1,34 @@ +package types + +type LogLevel string + +const ( + Debug LogLevel = "debug" + Info LogLevel = "info" + Warn LogLevel = "warn" + Error LogLevel = "error" + Success LogLevel = "success" + + Reset = "\033[0m" + Cyan = "\033[36m" + Gray = "\033[90m" + + LevelColorInfo = "\033[34mINFO \033[0m" + LevelColorWarn = "\033[33mWARN \033[0m" + LevelColorError = "\033[31mERROR \033[0m" + LevelColorDebug = "\033[35mDEBUG \033[0m" + LevelColorSuccess = "\033[32mSUCCESS\033[0m" + + MessageColorInfo = "\033[97m" + MessageColorWarn = "\033[33m" + MessageColorError = "\033[31m" + MessageColorDebug = "\033[90m" + MessageColorSuccess = "\033[32m" +) + +type LogOptions struct { + Timestamp bool + Prefix string + Level LogLevel + Fatal bool +} diff --git a/types/server.go b/types/server.go new file mode 100644 index 0000000..bc9d8a5 --- /dev/null +++ b/types/server.go @@ -0,0 +1,16 @@ +package types + +type DatabaseDriver string + +const ( + SQLite DatabaseDriver = "sqlite" + MySQL DatabaseDriver = "mysql" + Postgres DatabaseDriver = "postgres" + SQLServer DatabaseDriver = "sqlserver" +) + +type ServerConfig struct { + DatabaseDriver DatabaseDriver + DataSourceName string + Port int +} diff --git a/utils/logger/logger.go b/utils/logger/logger.go new file mode 100644 index 0000000..5fb415f --- /dev/null +++ b/utils/logger/logger.go @@ -0,0 +1,95 @@ +package logger + +import ( + "fmt" + "os" + "strings" + "time" + + "metachan/types" +) + +func getTimestamp() string { + return time.Now().Format(time.RFC3339) +} + +func getLevelColor(level types.LogLevel) string { + switch level { + case types.Info: + return types.LevelColorInfo + case types.Warn: + return types.LevelColorWarn + case types.Error: + return types.LevelColorError + case types.Debug: + return types.LevelColorDebug + case types.Success: + return types.LevelColorSuccess + default: + return types.LevelColorInfo + } +} + +func getMessageColor(level types.LogLevel) string { + switch level { + case types.Info: + return types.MessageColorInfo + case types.Warn: + return types.MessageColorWarn + case types.Error: + return types.MessageColorError + case types.Debug: + return types.MessageColorDebug + case types.Success: + return types.MessageColorSuccess + default: + return types.MessageColorInfo + } +} + +func Log(message interface{}, options types.LogOptions) { + var builder strings.Builder + + if options.Timestamp { + builder.WriteString(types.Gray) + builder.WriteString(getTimestamp()) + builder.WriteString(types.Reset) + builder.WriteString(" ") + } + + builder.WriteString(getLevelColor(options.Level)) + builder.WriteString(" ") + + if options.Prefix != "" { + builder.WriteString(types.Cyan) + builder.WriteString("[") + builder.WriteString(options.Prefix) + builder.WriteString("]") + builder.WriteString(types.Reset) + builder.WriteString(" ") + } + + builder.WriteString(getMessageColor(options.Level)) + + switch msg := message.(type) { + case error: + builder.WriteString(msg.Error()) + case string: + builder.WriteString(msg) + default: + builder.WriteString(fmt.Sprintf("%v", msg)) + } + + builder.WriteString(types.Reset) + builder.WriteString("\n") + + if options.Level == types.Error || options.Level == types.Warn { + os.Stderr.WriteString(builder.String()) + } else { + os.Stdout.WriteString(builder.String()) + } + + if options.Fatal { + os.Exit(1) + } +} |
