mirror of
https://github.com/openimsdk/open-im-server.git
synced 2026-07-14 18:11:12 +08:00
164 lines
4.1 KiB
Go
164 lines
4.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
"redpacket/config"
|
|
"redpacket/internal/chain"
|
|
"redpacket/internal/handler"
|
|
"redpacket/internal/model"
|
|
"redpacket/internal/repository"
|
|
"redpacket/internal/service"
|
|
"redpacket/router"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/driver/mysql"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func main() {
|
|
// Load configuration
|
|
cfgFile := ""
|
|
if len(os.Args) > 1 {
|
|
cfgFile = os.Args[1]
|
|
}
|
|
config.Load(cfgFile)
|
|
cfg := &config.Cfg
|
|
|
|
// Connect to database
|
|
db, err := openDB(cfg)
|
|
if err != nil {
|
|
log.Fatalf("failed to connect to database: %v", err)
|
|
}
|
|
|
|
// Auto-migrate models
|
|
if err := db.AutoMigrate(
|
|
&model.RedPacket{},
|
|
&model.RedPacketClaim{},
|
|
&model.RedPacketClaimAuth{},
|
|
&model.RedPacketRefund{},
|
|
&model.WalletBindingChallenge{},
|
|
&model.WalletBinding{},
|
|
); err != nil {
|
|
log.Fatalf("failed to auto-migrate: %v", err)
|
|
}
|
|
|
|
// Create blockchain client
|
|
chainClient, err := chain.NewClient(
|
|
cfg.Chain.RPCURL,
|
|
cfg.Chain.ContractAddress,
|
|
cfg.Chain.ChainID,
|
|
cfg.Chain.SignerPrivateKey,
|
|
cfg.Chain.ConfigAdminPrivateKey,
|
|
)
|
|
if err != nil {
|
|
log.Printf("Warning: failed to create chain client: %v (continuing with mock mode)", err)
|
|
// Continue without blockchain for now - can be configured later
|
|
}
|
|
|
|
// Create TRON client if configured
|
|
var tronClient *chain.TronClient
|
|
if cfg.Tron.FullNodeURL != "" {
|
|
abiJSON, err := chain.ExtractABIFromEmbeddedArtifact()
|
|
if err != nil {
|
|
log.Printf("Warning: failed to load ABI for TRON: %v", err)
|
|
} else {
|
|
tronClient, err = chain.NewTronClient(
|
|
cfg.Tron.FullNodeURL,
|
|
cfg.Tron.ContractBase58,
|
|
cfg.Tron.OwnerBase58,
|
|
cfg.Tron.PrivateKeyHex,
|
|
abiJSON,
|
|
cfg.Tron.FeeLimit,
|
|
)
|
|
if err != nil {
|
|
log.Printf("Warning: failed to create TRON client: %v", err)
|
|
tronClient = nil
|
|
} else {
|
|
log.Println("✅ TRON client initialized successfully")
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create repository and service
|
|
repo := repository.New(db)
|
|
rpSvc := service.NewRedPacketService(repo, chainClient, tronClient, cfg.Chain.SignerPrivateKey)
|
|
|
|
// Create admin service and handler
|
|
adminSvc := service.NewAdminService(chainClient, tronClient)
|
|
adminHandler := handler.NewAdminHandler(adminSvc)
|
|
|
|
// Create user handler
|
|
rpHandler := handler.NewRedPacketHandler(rpSvc)
|
|
|
|
// Setup router
|
|
r := gin.Default()
|
|
router.Setup(r, rpHandler, adminHandler)
|
|
|
|
// Start blockchain indexers
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
// ETH Indexer
|
|
if chainClient != nil {
|
|
ethIndexer := chain.NewIndexer(chainClient, repo, cfg.Indexer.PollInterval, 0)
|
|
ethIndexer.Start(ctx)
|
|
log.Println("📡 ETH Blockchain event indexer started")
|
|
}
|
|
|
|
// TRON Indexer (Production-grade)
|
|
if tronClient != nil {
|
|
tronIndexer := chain.NewTronIndexer(tronClient, repo, cfg.Indexer.PollInterval, 0)
|
|
tronIndexer.Start(ctx)
|
|
log.Println("📡 TRON Blockchain event indexer started (Production mode)")
|
|
}
|
|
|
|
// Start HTTP server with graceful shutdown
|
|
srv := &http.Server{
|
|
Addr: fmt.Sprintf(":%d", cfg.Server.Port),
|
|
Handler: r,
|
|
}
|
|
|
|
go func() {
|
|
log.Printf("🚀 RedPacket service listening on :%d", cfg.Server.Port)
|
|
log.Printf("📋 Health check: http://localhost:%d/health", cfg.Server.Port)
|
|
log.Printf("📋 API docs: see backend-api.md")
|
|
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
|
log.Fatalf("listen: %v", err)
|
|
}
|
|
}()
|
|
|
|
quit := make(chan os.Signal, 1)
|
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
|
<-quit
|
|
|
|
log.Println("shutting down server...")
|
|
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
|
|
if err := srv.Shutdown(shutdownCtx); err != nil {
|
|
log.Printf("server forced shutdown: %v", err)
|
|
}
|
|
log.Println("server stopped")
|
|
}
|
|
|
|
func openDB(cfg *config.Config) (*gorm.DB, error) {
|
|
switch cfg.DB.Driver {
|
|
case "mysql":
|
|
return gorm.Open(mysql.Open(cfg.DB.DSN), &gorm.Config{})
|
|
case "sqlite", "":
|
|
return gorm.Open(sqlite.Open(cfg.DB.DSN), &gorm.Config{})
|
|
default:
|
|
return nil, fmt.Errorf("unsupported db.driver: %s", cfg.DB.Driver)
|
|
}
|
|
}
|