Dunlin is a lightweight, self-hosted CDN for personal projects.
at master 3.2 kB view raw
1package main 2 3import ( 4 "database/sql" 5 "fmt" 6 "log" 7 "net/http" 8 "os" 9 "os/user" 10 "path/filepath" 11 "time" 12 13 "github.com/dinkelspiel/cdn/db" 14 "github.com/dinkelspiel/cdn/routers" 15 routers_user "github.com/dinkelspiel/cdn/routers/user" 16 "github.com/dinkelspiel/cdn/services" 17 "github.com/gin-contrib/cors" 18 "github.com/gin-gonic/gin" 19 _ "github.com/go-sql-driver/mysql" 20 _ "github.com/joho/godotenv/autoload" 21) 22 23type PostStatisticBody struct { 24 ServerId *int64 `json:"serverId"` 25 ServerSecret *string `json:"serverSecret"` 26 27 PlayerCount int `json:"playerCount"` 28 GameVersion string `json:"gameVersion"` 29 ServerEnvironment string `json:"serverEnvironment"` 30 OperatingSystem string `json:"operatingSystem"` 31 Arch string `json:"arch"` 32 JavaVersion string `json:"javaVersion"` 33} 34 35func setupRouter(db *db.DB) *gin.Engine { 36 // Disable Console Color 37 // gin.DisableConsoleColor() 38 r := gin.New() 39 r.Use(gin.Logger()) 40 r.Use(gin.Recovery()) 41 r.HandleMethodNotAllowed = true 42 43 r.Use(cors.New(cors.Config{ 44 AllowMethods: []string{"GET", "HEAD", "POST", "PUT", "PATCH", "OPTIONS"}, 45 AllowHeaders: []string{"Origin", "Content-Type", "Accept"}, 46 ExposeHeaders: []string{"Content-Length"}, 47 AllowCredentials: true, 48 AllowOrigins: []string{"https://files.keii.dev/", "https://github.com", "http://localhost:5173"}, 49 MaxAge: 12 * time.Hour, 50 })) 51 52 // Ping test 53 r.GET("/ping", func(c *gin.Context) { 54 c.String(http.StatusOK, "pong") 55 }) 56 57 api := r.Group("/api") 58 v1 := api.Group("/v1") 59 60 // This route serves all the files 61 routers.FileRouter(r.Group("/"), db) 62 63 routers.AuthRouter(v1, db) 64 routers.SetupRouter(v1, db) 65 routers.TeamsRouter(v1, db) 66 routers.TeamRouter(v1, db) 67 routers.TeamProjectRouter(v1, db) 68 routers.StatisticsRouter(v1, db) 69 routers_user.UserTeamsRouter(v1, db) 70 71 r.Static("/assets", "./frontend/dist/assets") 72 r.StaticFile("/favicon.ico", "./frontend/dist/favicon.ico") 73 74 r.NoRoute(func(c *gin.Context) { 75 indexPath := filepath.Join("./frontend/dist", "index.html") 76 77 if _, err := os.Stat(indexPath); os.IsNotExist(err) { 78 c.String(http.StatusNotFound, "index.html not found") 79 return 80 } 81 82 c.File(indexPath) 83 }) 84 85 return r 86} 87 88func main() { 89 u, err := user.Current() 90 if err != nil { 91 panic(err) 92 } 93 fmt.Println("Running as:", u.Username) 94 95 // Load Config 96 config, err := services.LoadConfig() 97 if err != nil { 98 log.Fatal("Error loading config: ", err) 99 return 100 } 101 102 services.EnsureFoldersExists() 103 104 // Load MariaDB Database 105 dsn := config.MariaDBDatabaseUrl 106 mariaDBClient, err := sql.Open("mysql", dsn) 107 if err != nil { 108 log.Fatal("Error opening mariadb: ", err) 109 return 110 } 111 defer mariaDBClient.Close() 112 if err = mariaDBClient.Ping(); err != nil { 113 log.Fatal("Error pinging mariadb: ", err) 114 return 115 } 116 117 // Load Redis Database 118 // redisClient := redis.NewClient(&redis.Options{ 119 // Addr: config.RedisDatabaseUrl, 120 // }) 121 // defer redisClient.Close() 122 123 // ctx := context.Background() 124 // if err = redisClient.Ping(ctx).Err(); err != nil { 125 // log.Fatal("Error pinging redis: ", err) 126 // return 127 // } 128 129 db := db.DB{ 130 MariaDB: mariaDBClient, 131 // Redis: redisClient, 132 } 133 134 r := setupRouter(&db) 135 136 // Listen and Server in 0.0.0.0:8080 137 r.Run(":8080") 138}