You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cls/config/base_providers.go

274 lines
7.8 KiB
Go

1 month ago
package config
import (
"cls/internal/infrastructure/payment/wechat_pay"
"cls/internal/infrastructure/wechat"
1 month ago
Ihttp "cls/pkg/http"
"cls/pkg/logger"
"cls/pkg/sms"
"cls/pkg/util/security"
"cls/pkg/xorm_engine"
"cls/ui"
1 month ago
"context"
"encoding/json"
1 month ago
"fmt"
_ "github.com/go-sql-driver/mysql"
"net/http"
"time"
auth_middleware "cls/internal/infrastructure/middleware/auth"
"github.com/ClickHouse/clickhouse-go/v2"
"github.com/cenkalti/backoff/v4"
"github.com/redis/go-redis/v9"
"net"
"strings"
middleware "cls/pkg/web/middleware"
"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
"github.com/gin-gonic/gin"
"go.uber.org/fx"
"xorm.io/xorm"
"xorm.io/xorm/names"
)
func NewGinEngine(lc fx.Lifecycle, auth *auth_middleware.AuthMiddleware, appConfig *AppConfig) *gin.Engine {
if strings.ToLower(appConfig.ServerConfig.Mode) == "prod" {
gin.SetMode(gin.ReleaseMode)
}
handler := gin.New()
handler.Use(gin.Recovery())
handler.GET("/MP_verify_dbfX2r5hEeBPV3qp.txt", func(c *gin.Context) {
c.File("MP_verify_dbfX2r5hEeBPV3qp.txt")
})
handler.GET("/callback_test", func(c *gin.Context) {
o := "oC8UY6Tc_qFZ33JDFZPzyqL_ZqnU"
token := auth.HandleCallback(o)
p := fmt.Sprintf("/?token=%s", token)
fmt.Println(p)
c.Redirect(http.StatusFound, p)
})
handler.GET("/callback", func(c *gin.Context) {
code := c.Query("code")
if code == "" {
c.String(http.StatusBadRequest, "Missing code")
return
}
fmt.Println("get code done", code)
url := fmt.Sprintf(
"https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code",
appConfig.WeChatConfig.AppId,
appConfig.WeChatConfig.AppSecret,
code,
)
resp, err := http.Get(url)
if err != nil {
c.String(http.StatusInternalServerError, "Request WeChat failed: %v", err)
return
}
defer resp.Body.Close()
var res struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
OpenID string `json:"openid"`
Scope string `json:"scope"`
ErrCode int `json:"errcode"`
ErrMsg string `json:"errmsg"`
}
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
c.String(http.StatusInternalServerError, "Failed to decode response")
return
}
fmt.Printf("%+v\n", res)
if res.ErrCode != 0 {
c.String(http.StatusInternalServerError, "WeChat error: %s", res.ErrMsg)
return
}
// 🎯 获取到 openid
openid := res.OpenID
fmt.Println("get openid,", openid)
fmt.Println("openid:", openid)
token := auth.HandleCallback(openid)
fmt.Println(token)
c.Redirect(http.StatusFound, fmt.Sprintf("/?token=%s", token))
//c.String(http.StatusFound, token)
})
1 month ago
handler.Use(auth.Handle())
handler.Use(middleware.ServeRoot("/", "dist", &ui.RESOURCE))
1 month ago
handler.NoRoute(func(context *gin.Context) {
if context.Request.RequestURI != "/" {
context.Redirect(http.StatusTemporaryRedirect, "/")
}
})
srv := &http.Server{Addr: fmt.Sprintf(":%d", appConfig.ServerConfig.Port), Handler: handler}
lc.Append(fx.Hook{
OnStart: func(ctx context.Context) error {
ln, err := net.Listen("tcp", srv.Addr)
if err != nil {
return err
}
log.Infof("Web server starting on port %v", srv.Addr)
log.Info("Press Ctrl+C to stop")
go func() {
if err0 := srv.Serve(ln); err0 != nil {
log.Error(err0)
}
}()
return nil
},
OnStop: func(ctx context.Context) error {
return srv.Shutdown(ctx)
},
})
return handler
}
func NewXormEngine(appConfig *AppConfig, l logger.New) *xorm_engine.Engine {
dbConfig := appConfig.MysqlConfig
url := fmt.Sprintf("%s:%s@(%s)/%s", dbConfig.Username, dbConfig.Password, dbConfig.Address, dbConfig.Database)
engine, err := xorm.NewEngineWithParams("mysql", url, dbConfig.Params)
if err != nil {
log.Fatal(err)
}
fmt.Println("done")
engine.SetTableMapper(names.NewPrefixMapper(names.GonicMapper{}, "lc_"))
engine.SetColumnMapper(names.GonicMapper{})
engine.SetLogger(logger.NewXormLogger(l("xorm")))
if dbConfig.ShowSql {
engine.ShowSQL(true)
}
if err = backoff.Retry(engine.Ping, backoff.WithMaxRetries(backoff.NewExponentialBackOff(), 10)); err != nil {
log.Fatal(err)
}
urlCls := fmt.Sprintf("%s:%s@(%s)/%s", dbConfig.Username, dbConfig.Password, dbConfig.Address, dbConfig.DatabaseCls)
engineCls, err := xorm.NewEngineWithParams("mysql", urlCls, dbConfig.Params)
if err != nil {
log.Fatal(err)
}
if err = backoff.Retry(engineCls.Ping, backoff.WithMaxRetries(backoff.NewExponentialBackOff(), 10)); err != nil {
log.Fatal(err)
}
return xorm_engine.NewEngine(engine, engineCls)
}
func NewClickhouseConn(appConfig *AppConfig) driver.Conn {
dbConfig := appConfig.ClickhouseConfig
conn, err := clickhouse.Open(&clickhouse.Options{
Addr: dbConfig.Address,
Auth: clickhouse.Auth{
Database: dbConfig.Database,
Username: dbConfig.Username,
Password: dbConfig.Password,
},
Settings: clickhouse.Settings{
"max_execution_time": 60,
},
Compression: &clickhouse.Compression{
Method: clickhouse.CompressionLZ4,
},
DialTimeout: time.Duration(10) * time.Second,
MaxOpenConns: 5,
MaxIdleConns: 5,
ConnMaxLifetime: time.Duration(10) * time.Minute,
ConnOpenStrategy: clickhouse.ConnOpenInOrder,
BlockBufferSize: 10,
})
if err != nil {
log.Fatal(err)
}
if err = backoff.Retry(func() error {
return conn.Ping(context.Background())
}, backoff.WithMaxRetries(backoff.NewExponentialBackOff(), 10)); err != nil {
log.Fatal(err)
}
if v, err := conn.ServerVersion(); err != nil {
log.Fatal(err)
} else {
log.Info(v)
}
return conn
}
func NewRedisClient(appConfig *AppConfig) redis.Cmdable {
dbConfig := appConfig.RedisConfig
var rdbCli redis.Cmdable
switch dbConfig.Mode {
case "sentinel":
rdbCli = redis.NewFailoverClient(&redis.FailoverOptions{
MasterName: dbConfig.MasterName,
SentinelAddrs: dbConfig.SentinelAddrs,
SentinelUsername: dbConfig.SentinelUsername,
SentinelPassword: dbConfig.SentinelPassword,
Username: dbConfig.Username,
Password: dbConfig.Password,
DB: 0,
})
case "cluster":
rdbCli = redis.NewClusterClient(&redis.ClusterOptions{
Addrs: dbConfig.Addrs,
Username: dbConfig.Username,
Password: dbConfig.Password,
})
default:
rdbCli = redis.NewClient(&redis.Options{
Addr: dbConfig.Addr,
Username: dbConfig.Username,
Password: dbConfig.Password,
DB: dbConfig.DB,
})
}
if err := backoff.Retry(func() error {
return rdbCli.Ping(context.Background()).Err()
}, backoff.WithMaxRetries(backoff.NewExponentialBackOff(), 10)); err != nil {
log.Fatal(err)
}
return rdbCli
}
func NewLoggerFactory(config *AppConfig) logger.New {
return func(name string) logger.Logger {
var options []logger.Option
if v, ok := config.LogConfig.Loggers[strings.ToLower(name)]; ok {
options = append(options, logger.Level(logger.LogLevel(v)))
}
return logger.NewLogger(name, options...)
}
}
func NewPasswordEncoder() security.PasswordEncoder {
return &security.BCryptPasswordEncoder{}
}
func NewSmsService() sms.IsmsService {
return sms.NewSmsService()
1 month ago
}
func NewInternalClient() *Ihttp.Client {
return Ihttp.NewClient()
}
func NewJWTAuthMiddleware(appConfig *AppConfig, log logger.New, redis redis.Cmdable) *auth_middleware.AuthMiddleware {
return auth_middleware.NewAuthMiddleware(appConfig.JwtConfig.Secret, nil, redis, log)
1 month ago
}
func NewPayService(config *AppConfig) *wechat_pay.PayService {
return wechat_pay.NewPayService(config.WeChatConfig.MchId,
config.WeChatConfig.AppId,
config.WeChatConfig.MchCertificateSerialNumber,
config.WeChatConfig.MchAPIv3Key,
config.WeChatConfig.PrivateCertPath,
config.WeChatConfig.PublicCertPath,
)
}
func NewWechatService(config *AppConfig) *wechat.WechatService {
return wechat.NewWechatService(config.WeChatConfig.AppId, config.WeChatConfig.AppSecret)
}