feat: 接入两端用户名登录和独立学习空间 (#2)

This commit is contained in:
ila
2026-09-10 17:39:57 +08:00
parent 596543b0e2
commit 2c8e9b3ca0
82 changed files with 14148 additions and 30 deletions
+125
View File
@@ -0,0 +1,125 @@
package main
import (
"context"
"errors"
"fmt"
"log"
"net"
"net/http"
"os"
"os/signal"
"strings"
"syscall"
"time"
"github.com/gin-gonic/gin"
driver "github.com/go-sql-driver/mysql"
"go-admin/app/lexgo"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
func openDB() (*gorm.DB, error) {
c := driver.NewConfig()
c.Net = "tcp"
host := os.Getenv("LEXGO_DB_HOST")
if host == "" {
host = "127.0.0.1"
}
port := os.Getenv("LEXGO_DB_PORT")
if port == "" {
port = "3308"
}
c.Addr = net.JoinHostPort(host, port)
c.User = os.Getenv("LEXGO_DB_USER")
c.Passwd = os.Getenv("LEXGO_DB_PASSWORD")
c.DBName = os.Getenv("LEXGO_DB_NAME")
if c.User == "" || c.Passwd == "" || c.DBName == "" {
return nil, errors.New("set LEXGO_DB_USER, LEXGO_DB_PASSWORD and LEXGO_DB_NAME")
}
c.ParseTime = true
c.Loc = time.UTC
c.Timeout = 5 * time.Second
c.ReadTimeout = 10 * time.Second
c.WriteTimeout = 10 * time.Second
c.Params = map[string]string{"charset": "utf8mb4"}
db, err := gorm.Open(mysql.Open(c.FormatDSN()), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)})
if err != nil {
return nil, errors.New("database connection failed; check local configuration")
}
pool, err := db.DB()
if err != nil {
return nil, err
}
pool.SetMaxOpenConns(10)
pool.SetMaxIdleConns(5)
pool.SetConnMaxLifetime(5 * time.Minute)
var version string
if err = db.Raw("SELECT VERSION()").Scan(&version).Error; err != nil || !strings.HasPrefix(version, "8.") {
pool.Close()
return nil, errors.New("MySQL 8 is required")
}
return db, nil
}
func run() error {
if len(os.Args) != 2 {
return errors.New("usage: lexgo migrate|bootstrap|serve")
}
command := os.Args[1]
if command != "migrate" && command != "bootstrap" && command != "serve" {
return errors.New("unknown command")
}
db, err := openDB()
if err != nil {
return err
}
pool, _ := db.DB()
defer pool.Close()
if command == "migrate" {
if err = lexgo.Migrate(db); err != nil {
return err
}
fmt.Println("LexGo schema version 1 ready")
return nil
}
if err = lexgo.CheckSchema(db); err != nil {
return err
}
if command == "bootstrap" {
if err = lexgo.BootstrapAdmin(db, os.Getenv("LEXGO_BOOTSTRAP_USERNAME"), os.Getenv("LEXGO_BOOTSTRAP_PASSWORD")); err != nil {
return err
}
fmt.Println("Initial administrator created; credentials are only in your local configuration")
return nil
}
gin.SetMode(gin.ReleaseMode)
addr := os.Getenv("LEXGO_LISTEN")
if addr == "" {
addr = "127.0.0.1:8000"
}
srv := &http.Server{Addr: addr, Handler: lexgo.Router(db, time.Now), ReadHeaderTimeout: 5 * time.Second, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, IdleTimeout: 60 * time.Second, MaxHeaderBytes: 1 << 20}
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
done := make(chan error, 1)
go func() { done <- srv.ListenAndServe() }()
fmt.Println("LexGo API listening on", addr)
select {
case err = <-done:
if errors.Is(err, http.ErrServerClosed) {
return nil
}
return err
case <-ctx.Done():
shutdown, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
return srv.Shutdown(shutdown)
}
}
func main() {
if err := run(); err != nil {
log.Fatal(err)
}
}