Merge pull request #62 from alimy/pr-feature

support composite feature that server supported just by configure file
pull/63/head v0.1.1
ROC 3 years ago committed by GitHub
commit 06c11e2cb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -5,28 +5,33 @@ App: # APP基础设置项
DefaultContextTimeout: 60 DefaultContextTimeout: 60
DefaultPageSize: 10 DefaultPageSize: 10
MaxPageSize: 100 MaxPageSize: 100
SmsJuheKey:
SmsJuheTplID:
SmsJuheTplVal: "#code#=%d&#m#=%d"
AlipayAppID:
AlipayPrivateKey:
Runtime: # App运行时功能调节
DisablePhoneVerify: False # 禁止绑定手机号码时验证短信验证码为true时任意验证码都可以通过验证
Server: # 服务设置 Server: # 服务设置
RunMode: debug RunMode: debug
HttpIp: 0.0.0.0 HttpIp: 0.0.0.0
HttpPort: 8008 HttpPort: 8008
ReadTimeout: 60 ReadTimeout: 60
WriteTimeout: 60 WriteTimeout: 60
Log: # 日志 Features:
LogType: zinc # 可选file或zinc Default: ["Sms", "Alipay", "Zinc", "MySQL", "Redis", "AliOSS", "LoggerZinc"]
LogFileSavePath: storage/logs Develop: ["Zinc", "MySQL", "AliOSS", "LoggerFile"]
LogFileName: app Slim: ["Zinc", "MySQL", "Redis", "AliOSS", "LoggerFile"]
LogFileExt: .log Sms: "SmsJuhe"
LogZincHost: http://127.0.0.1:4080/es/_bulk SmsJuhe:
LogZincIndex: paopao-log Key:
LogZincUser: admin TplID:
LogZincPassword: admin TplVal: "#code#=%d&#m#=%d"
Alipay:
AppID:
PrivateKey:
LoggerFile: # 使用File写日志
SavePath: storage/logs
FileName: app
FileExt: .log
LoggerZinc: # 使用Zinc写日志
Host: http://127.0.0.1:4080/es/_bulk
Index: paopao-log
User: admin
Password: admin
JWT: # 鉴权加密 JWT: # 鉴权加密
Secret: 18a6413dc4fe394c66345ebe501b2f26 Secret: 18a6413dc4fe394c66345ebe501b2f26
Issuer: paopao-api Issuer: paopao-api
@ -36,14 +41,18 @@ Search: # 搜索配置
ZincIndex: paopao-data ZincIndex: paopao-data
ZincUser: admin ZincUser: admin
ZincPassword: admin ZincPassword: admin
Storage: # 阿里云OSS存储配置 Zinc: # Zinc搜索配置
AliossAccessKeyID: Host: http://127.0.0.1:4080
AliossAccessKeySecret: Index: paopao-data
AliossEndpoint: User: admin
AliossBucket: Password: admin
AliossDomain: AliOSS: # 阿里云OSS存储配置
Database: # 数据库 AccessKeyID:
DBType: mysql AccessKeySecret:
Endpoint:
Bucket:
Domain:
MySQL: # MySQL数据库
Username: root # 填写你的数据库账号 Username: root # 填写你的数据库账号
Password: root # 填写你的数据库密码 Password: root # 填写你的数据库密码
Host: 127.0.0.1:3306 Host: 127.0.0.1:3306

@ -8,15 +8,26 @@ import (
) )
var ( var (
Features *setting.FeaturesSettingS
ServerSetting *setting.ServerSettingS ServerSetting *setting.ServerSettingS
AppSetting *setting.AppSettingS AppSetting *setting.AppSettingS
RuntimeSetting *setting.RuntimeSettingS MySQLSetting *setting.MySQLSettingS
DatabaseSetting *setting.DatabaseSettingS
RedisSetting *setting.RedisSettingS RedisSetting *setting.RedisSettingS
SearchSetting *setting.SearchSettingS SmsJuheSetting *setting.SmsJuheSettings
AliossSetting *setting.AliossSettingS AlipaySetting *setting.AlipaySettingS
ZincSetting *setting.ZincSettingS
AliOSSSetting *setting.AliOSSSettingS
JWTSetting *setting.JWTSettingS JWTSetting *setting.JWTSettingS
LoggerSetting *setting.LoggerSettingS LoggerFileSetting *setting.LoggerFileSettingS
LoggerZincSetting *setting.LoggerZincSettingS
Logger *logrus.Logger Logger *logrus.Logger
Mutex *sync.Mutex Mutex *sync.Mutex
) )
func Cfg(key string) (string, bool) {
return Features.Cfg(key)
}
func CfgIf(expression string) bool {
return Features.CfgIf(expression)
}

@ -27,7 +27,7 @@ func init() {
if err != nil { if err != nil {
log.Fatalf("init.setupDBEngine err: %v", err) log.Fatalf("init.setupDBEngine err: %v", err)
} }
client := zinc.NewClient(global.SearchSetting) client := zinc.NewClient(global.ZincSetting)
service.Initialize(global.DBEngine, client) service.Initialize(global.DBEngine, client)
} }
@ -37,40 +37,22 @@ func setupSetting() error {
return err return err
} }
err = setting.ReadSection("Server", &global.ServerSetting) global.Features = setting.FeaturesFrom("Features")
if err != nil {
return err objects := map[string]interface{}{
} "App": &global.AppSetting,
err = setting.ReadSection("App", &global.AppSetting) "Server": &global.ServerSetting,
if err != nil { "Alipay": &global.AlipaySetting,
return err "SmsJuhe": &global.SmsJuheSetting,
} "LoggerFile": &global.LoggerFileSetting,
err = setting.ReadSection("Runtime", &global.RuntimeSetting) "LoggerZinc": &global.LoggerZincSetting,
if err != nil { "MySQL": &global.MySQLSetting,
return err "Zinc": &global.ZincSetting,
} "Redis": &global.RedisSetting,
err = setting.ReadSection("Log", &global.LoggerSetting) "JWT": &global.JWTSetting,
if err != nil { "AliOSS": &global.AliOSSSetting,
return err
}
err = setting.ReadSection("Database", &global.DatabaseSetting)
if err != nil {
return err
}
err = setting.ReadSection("Search", &global.SearchSetting)
if err != nil {
return err
}
err = setting.ReadSection("Redis", &global.RedisSetting)
if err != nil {
return err
}
err = setting.ReadSection("JWT", &global.JWTSetting)
if err != nil {
return err
} }
err = setting.ReadSection("Storage", &global.AliossSetting) if err = setting.Unmarshal(objects); err != nil {
if err != nil {
return err return err
} }
@ -82,7 +64,7 @@ func setupSetting() error {
} }
func setupLogger() error { func setupLogger() error {
logger, err := logger.New(global.LoggerSetting) logger, err := logger.New()
if err != nil { if err != nil {
return err return err
} }
@ -91,9 +73,10 @@ func setupLogger() error {
return nil return nil
} }
// setupDBEngine 暂时只支持MySQL
func setupDBEngine() error { func setupDBEngine() error {
var err error var err error
global.DBEngine, err = model.NewDBEngine(global.DatabaseSetting) global.DBEngine, err = model.NewDBEngine(global.MySQLSetting)
if err != nil { if err != nil {
return err return err
} }

@ -127,9 +127,9 @@ func (d *dataServant) SendPhoneCaptcha(phone string) error {
resp, err := client.R(). resp, err := client.R().
SetFormData(map[string]string{ SetFormData(map[string]string{
"mobile": phone, "mobile": phone,
"tpl_id": global.AppSetting.SmsJuheTplID, "tpl_id": global.SmsJuheSetting.TplID,
"tpl_value": fmt.Sprintf(global.AppSetting.SmsJuheTplVal, captcha, m), "tpl_value": fmt.Sprintf(global.SmsJuheSetting.TplVal, captcha, m),
"key": global.AppSetting.SmsJuheKey, "key": global.SmsJuheSetting.Key,
}).Post(gateway) }).Post(gateway)
if err != nil { if err != nil {
return err return err

@ -25,7 +25,7 @@ type Model struct {
type ConditionsT map[string]interface{} type ConditionsT map[string]interface{}
func NewDBEngine(databaseSetting *setting.DatabaseSettingS) (*gorm.DB, error) { func NewDBEngine(databaseSetting *setting.MySQLSettingS) (*gorm.DB, error) {
newLogger := logger.New( newLogger := logger.New(
global.Logger, // io writer日志输出的目标前缀和日志包含的内容 global.Logger, // io writer日志输出的目标前缀和日志包含的内容
logger.Config{ logger.Config{

@ -97,14 +97,14 @@ func UploadAttachment(c *gin.Context) {
randomPath := uuid.Must(uuid.NewV4()).String() randomPath := uuid.Must(uuid.NewV4()).String()
ossSavePath := uploadType + "/" + GeneratePath(randomPath[:8]) + "/" + randomPath[9:] + fileExt ossSavePath := uploadType + "/" + GeneratePath(randomPath[:8]) + "/" + randomPath[9:] + fileExt
client, err := oss.New(global.AliossSetting.AliossEndpoint, global.AliossSetting.AliossAccessKeyID, global.AliossSetting.AliossAccessKeySecret) client, err := oss.New(global.AliOSSSetting.Endpoint, global.AliOSSSetting.AccessKeyID, global.AliOSSSetting.AccessKeySecret)
if err != nil { if err != nil {
global.Logger.Errorf("oss.New err: %v", err) global.Logger.Errorf("oss.New err: %v", err)
response.ToErrorResponse(errcode.FileUploadFailed) response.ToErrorResponse(errcode.FileUploadFailed)
return return
} }
bucket, err := client.Bucket(global.AliossSetting.AliossBucket) bucket, err := client.Bucket(global.AliOSSSetting.Bucket)
if err != nil { if err != nil {
global.Logger.Errorf("client.Bucket err: %v", err) global.Logger.Errorf("client.Bucket err: %v", err)
response.ToErrorResponse(errcode.FileUploadFailed) response.ToErrorResponse(errcode.FileUploadFailed)
@ -121,7 +121,7 @@ func UploadAttachment(c *gin.Context) {
// 构造附件Model // 构造附件Model
attachment := &model.Attachment{ attachment := &model.Attachment{
FileSize: fileHeader.Size, FileSize: fileHeader.Size,
Content: "https://" + global.AliossSetting.AliossDomain + "/" + ossSavePath, Content: "https://" + global.AliOSSSetting.Domain + "/" + ossSavePath,
} }
if userID, exists := c.Get("UID"); exists { if userID, exists := c.Get("UID"); exists {
@ -256,14 +256,14 @@ func DownloadAttachment(c *gin.Context) {
} }
// 开始构造下载地址 // 开始构造下载地址
client, err := oss.New(global.AliossSetting.AliossEndpoint, global.AliossSetting.AliossAccessKeyID, global.AliossSetting.AliossAccessKeySecret) client, err := oss.New(global.AliOSSSetting.Endpoint, global.AliOSSSetting.AccessKeyID, global.AliOSSSetting.AccessKeySecret)
if err != nil { if err != nil {
global.Logger.Errorf("oss.New err: %v", err) global.Logger.Errorf("oss.New err: %v", err)
response.ToErrorResponse(errcode.DownloadReqError) response.ToErrorResponse(errcode.DownloadReqError)
return return
} }
bucket, err := client.Bucket(global.AliossSetting.AliossBucket) bucket, err := client.Bucket(global.AliOSSSetting.Bucket)
if err != nil { if err != nil {
global.Logger.Errorf("client.Bucket err: %v", err) global.Logger.Errorf("client.Bucket err: %v", err)
response.ToErrorResponse(errcode.DownloadReqError) response.ToErrorResponse(errcode.DownloadReqError)
@ -271,7 +271,7 @@ func DownloadAttachment(c *gin.Context) {
} }
// 签名 // 签名
objectKey := strings.Replace(content.Content, "https://"+global.AliossSetting.AliossDomain+"/", "", -1) objectKey := strings.Replace(content.Content, "https://"+global.AliOSSSetting.Domain+"/", "", -1)
signedURL, err := bucket.SignURL(objectKey, oss.HTTPGet, 60) signedURL, err := bucket.SignURL(objectKey, oss.HTTPGet, 60)
if err != nil { if err != nil {
global.Logger.Errorf("client.SignURL err: %v", err) global.Logger.Errorf("client.SignURL err: %v", err)

@ -204,7 +204,7 @@ func ChangeAvatar(c *gin.Context) {
user = u.(*model.User) user = u.(*model.User)
} }
if strings.Index(param.Avatar, "https://"+global.AliossSetting.AliossDomain) != 0 { if strings.Index(param.Avatar, "https://"+global.AliOSSSetting.Domain) != 0 {
response.ToErrorResponse(errcode.InvalidParams) response.ToErrorResponse(errcode.InvalidParams)
return return
} }
@ -238,14 +238,11 @@ func BindUserPhone(c *gin.Context) {
return return
} }
// 验证短信验证码
if !global.RuntimeSetting.DisablePhoneVerify {
if err := service.CheckPhoneCaptcha(param.Phone, param.Captcha); err != nil { if err := service.CheckPhoneCaptcha(param.Phone, param.Captcha); err != nil {
global.Logger.Errorf("service.CheckPhoneCaptcha err: %v\n", err) global.Logger.Errorf("service.CheckPhoneCaptcha err: %v\n", err)
response.ToErrorResponse(err) response.ToErrorResponse(err)
return return
} }
}
// 执行绑定 // 执行绑定
user.Phone = param.Phone user.Phone = param.Phone
@ -383,7 +380,7 @@ func GetUserRechargeLink(c *gin.Context) {
} }
client, err := alipay.New(global.AppSetting.AlipayAppID, global.AppSetting.AlipayPrivateKey, true) client, err := alipay.New(global.AlipaySetting.AppID, global.AlipaySetting.PrivateKey, true)
// 将 key 的验证调整到初始化阶段 // 将 key 的验证调整到初始化阶段
if err != nil { if err != nil {
global.Logger.Errorf("alipay.New err: %v\n", err) global.Logger.Errorf("alipay.New err: %v\n", err)
@ -462,7 +459,7 @@ func AlipayNotify(c *gin.Context) {
response := app.NewResponse(c) response := app.NewResponse(c)
c.Request.ParseForm() c.Request.ParseForm()
aliClient, err := alipay.New(global.AppSetting.AlipayAppID, global.AppSetting.AlipayPrivateKey, true) aliClient, err := alipay.New(global.AlipaySetting.AppID, global.AlipaySetting.PrivateKey, true)
// 将 key 的验证调整到初始化阶段 // 将 key 的验证调整到初始化阶段
if err != nil { if err != nil {
global.Logger.Errorf("alipay.New err: %v\n", err) global.Logger.Errorf("alipay.New err: %v\n", err)

@ -116,7 +116,7 @@ func CreatePostComment(ctx *gin.Context, userID int64, param CommentCreationReq)
for _, item := range param.Contents { for _, item := range param.Contents {
// 检查附件是否是本站资源 // 检查附件是否是本站资源
if item.Type == model.CONTENT_TYPE_IMAGE || item.Type == model.CONTENT_TYPE_VIDEO || item.Type == model.CONTENT_TYPE_ATTACHMENT { if item.Type == model.CONTENT_TYPE_IMAGE || item.Type == model.CONTENT_TYPE_VIDEO || item.Type == model.CONTENT_TYPE_ATTACHMENT {
if strings.Index(item.Content, "https://"+global.AliossSetting.AliossDomain) != 0 { if strings.Index(item.Content, "https://"+global.AliOSSSetting.Domain) != 0 {
continue continue
} }
} }

@ -68,7 +68,7 @@ func (p *PostContentItem) Check() error {
// 检查附件是否是本站资源 // 检查附件是否是本站资源
if p.Type == model.CONTENT_TYPE_IMAGE || p.Type == model.CONTENT_TYPE_VIDEO || p.Type == model. if p.Type == model.CONTENT_TYPE_IMAGE || p.Type == model.CONTENT_TYPE_VIDEO || p.Type == model.
CONTENT_TYPE_ATTACHMENT { CONTENT_TYPE_ATTACHMENT {
if strings.Index(p.Content, "https://"+global.AliossSetting.AliossDomain) != 0 { if strings.Index(p.Content, "https://"+global.AliOSSSetting.Domain) != 0 {
return fmt.Errorf("附件非本站资源") return fmt.Errorf("附件非本站资源")
} }
} }
@ -377,7 +377,7 @@ func GetPostCount(conditions *model.ConditionsT) (int64, error) {
} }
func GetPostListFromSearch(q *core.QueryT, offset, limit int) ([]*model.PostFormated, int64, error) { func GetPostListFromSearch(q *core.QueryT, offset, limit int) ([]*model.PostFormated, int64, error) {
queryResult, err := ds.QueryAll(q, global.SearchSetting.ZincIndex, offset, limit) queryResult, err := ds.QueryAll(q, global.ZincSetting.Index, offset, limit)
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
@ -391,7 +391,7 @@ func GetPostListFromSearch(q *core.QueryT, offset, limit int) ([]*model.PostForm
} }
func GetPostListFromSearchByQuery(query string, offset, limit int) ([]*model.PostFormated, int64, error) { func GetPostListFromSearchByQuery(query string, offset, limit int) ([]*model.PostFormated, int64, error) {
queryResult, err := ds.QuerySearch(global.SearchSetting.ZincIndex, query, offset, limit) queryResult, err := ds.QuerySearch(global.ZincSetting.Index, query, offset, limit)
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
@ -405,7 +405,7 @@ func GetPostListFromSearchByQuery(query string, offset, limit int) ([]*model.Pos
} }
func PushPostToSearch(post *model.Post) { func PushPostToSearch(post *model.Post) {
indexName := global.SearchSetting.ZincIndex indexName := global.ZincSetting.Index
postFormated := post.Format() postFormated := post.Format()
postFormated.User = &model.UserFormated{ postFormated.User = &model.UserFormated{
@ -456,7 +456,7 @@ func PushPostToSearch(post *model.Post) {
} }
func DeleteSearchPost(post *model.Post) error { func DeleteSearchPost(post *model.Post) error {
indexName := global.SearchSetting.ZincIndex indexName := global.ZincSetting.Index
return ds.DelDoc(indexName, fmt.Sprintf("%d", post.ID)) return ds.DelDoc(indexName, fmt.Sprintf("%d", post.ID))
} }
@ -469,7 +469,7 @@ func PushPostsToSearch(c *gin.Context) {
pages := math.Ceil(float64(totalRows) / float64(splitNum)) pages := math.Ceil(float64(totalRows) / float64(splitNum))
nums := int(pages) nums := int(pages)
indexName := global.SearchSetting.ZincIndex indexName := global.ZincSetting.Index
// 创建索引 // 创建索引
ds.CreateSearchIndex(indexName) ds.CreateSearchIndex(indexName)

@ -1,6 +1,7 @@
package service package service
import ( import (
"github.com/rocboss/paopao-ce/global"
"github.com/rocboss/paopao-ce/internal/core" "github.com/rocboss/paopao-ce/internal/core"
"github.com/rocboss/paopao-ce/internal/dao" "github.com/rocboss/paopao-ce/internal/dao"
"github.com/rocboss/paopao-ce/pkg/zinc" "github.com/rocboss/paopao-ce/pkg/zinc"
@ -9,8 +10,10 @@ import (
var ( var (
ds core.DataService ds core.DataService
DisablePhoneVerify bool
) )
func Initialize(engine *gorm.DB, client *zinc.ZincClient) { func Initialize(engine *gorm.DB, client *zinc.ZincClient) {
ds = dao.NewDataService(engine, client) ds = dao.NewDataService(engine, client)
DisablePhoneVerify = !global.CfgIf("Sms")
} }

@ -136,6 +136,11 @@ func CheckPassword(password string) error {
// CheckPhoneCaptcha 验证手机验证码 // CheckPhoneCaptcha 验证手机验证码
func CheckPhoneCaptcha(phone, captcha string) *errcode.Error { func CheckPhoneCaptcha(phone, captcha string) *errcode.Error {
// 如果禁止phone verify 则允许通过任意验证码
if DisablePhoneVerify {
return nil
}
c, err := ds.GetLatestPhoneCaptcha(phone) c, err := ds.GetLatestPhoneCaptcha(phone)
if err != nil { if err != nil {
return errcode.ErrorPhoneCaptcha return errcode.ErrorPhoneCaptcha

@ -7,7 +7,6 @@ import (
"time" "time"
"github.com/rocboss/paopao-ce/global" "github.com/rocboss/paopao-ce/global"
"github.com/rocboss/paopao-ce/pkg/setting"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"gopkg.in/natefinch/lumberjack.v2" "gopkg.in/natefinch/lumberjack.v2"
"gopkg.in/resty.v1" "gopkg.in/resty.v1"
@ -31,7 +30,7 @@ type ZincLogHook struct {
func (hook *ZincLogHook) Fire(entry *logrus.Entry) error { func (hook *ZincLogHook) Fire(entry *logrus.Entry) error {
index := &ZincLogIndex{ index := &ZincLogIndex{
Index: map[string]string{ Index: map[string]string{
"_index": global.LoggerSetting.LogZincIndex, "_index": global.LoggerZincSetting.Index,
}, },
} }
indexBytes, _ := json.Marshal(index) indexBytes, _ := json.Marshal(index)
@ -49,9 +48,9 @@ func (hook *ZincLogHook) Fire(entry *logrus.Entry) error {
if _, err := client.SetDisableWarn(true).R(). if _, err := client.SetDisableWarn(true).R().
SetHeader("Content-Type", "application/json"). SetHeader("Content-Type", "application/json").
SetBasicAuth(global.LoggerSetting.LogZincUser, global.LoggerSetting.LogZincPassword). SetBasicAuth(global.LoggerZincSetting.User, global.LoggerZincSetting.Password).
SetBody(logStr). SetBody(logStr).
Post(global.LoggerSetting.LogZincHost); err != nil { Post(global.LoggerZincSetting.Host); err != nil {
fmt.Println(err.Error()) fmt.Println(err.Error())
} }
@ -62,19 +61,19 @@ func (hook *ZincLogHook) Levels() []logrus.Level {
return logrus.AllLevels return logrus.AllLevels
} }
func New(s *setting.LoggerSettingS) (*logrus.Logger, error) { func New() (*logrus.Logger, error) {
log := logrus.New() log := logrus.New()
log.Formatter = &logrus.JSONFormatter{} log.Formatter = &logrus.JSONFormatter{}
switch s.LogType { if global.CfgIf("LoggerFile") {
case setting.LogFileType: s := global.LoggerFileSetting
log.Out = &lumberjack.Logger{ log.Out = &lumberjack.Logger{
Filename: s.LogFileSavePath + "/" + s.LogFileName + s.LogFileExt, Filename: s.SavePath + "/" + s.FileName + s.FileExt,
MaxSize: 600, MaxSize: 600,
MaxAge: 10, MaxAge: 10,
LocalTime: true, LocalTime: true,
} }
case setting.LogZincType: } else if global.CfgIf("LoggerZinc") {
log.Out = io.Discard log.Out = io.Discard
log.AddHook(&ZincLogHook{}) log.AddHook(&ZincLogHook{})
} }

@ -0,0 +1,41 @@
package setting
import (
"testing"
)
func TestUseDefault(t *testing.T) {
suites := map[string][]string{
"default": {"Sms", "Alipay", "Zinc", "MySQL", "Redis", "AliOSS", "LogZinc"},
"develop": {"Zinc", "MySQL", "AliOSS", "LogFile"},
"slim": {"Zinc", "MySQL", "Redis", "AliOSS", "LogFile"},
}
kv := map[string]string{
"sms": "SmsJuhe",
}
features := newFeatures(suites, kv)
for _, data := range []struct {
key string
expect string
exist bool
}{
{"Sms", "SmsJuhe", true},
{"Alipay", "", true},
{"Zinc", "", true},
{"Redis", "", true},
{"Database", "", false},
} {
if v, ok := features.Cfg(data.key); ok != data.exist || v != data.expect {
t.Errorf("key: %s expect: %s exist: %t got v: %s ok: %t", data.key, data.expect, data.exist, v, ok)
}
}
for exp, res := range map[string]bool{
"Sms": true,
"Sms = SmsJuhe": true,
"SmsJuhe": false,
} {
if ok := features.CfgIf(exp); res != ok {
t.Errorf("CfgIf(%s) want %t got %t", exp, res, ok)
}
}
}

@ -1,6 +1,7 @@
package setting package setting
import ( import (
"strings"
"time" "time"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -16,6 +17,19 @@ type LogType string
const LogFileType LogType = "file" const LogFileType LogType = "file"
const LogZincType LogType = "zinc" const LogZincType LogType = "zinc"
type LoggerFileSettingS struct {
SavePath string
FileName string
FileExt string
}
type LoggerZincSettingS struct {
Host string
Index string
User string
Password string
}
type LoggerSettingS struct { type LoggerSettingS struct {
LogType LogType LogType LogType
LogFileSavePath string LogFileSavePath string
@ -44,22 +58,30 @@ type AppSettingS struct {
MaxPageSize int MaxPageSize int
IsShastaTestnet bool IsShastaTestnet bool
TronApiKeys []string TronApiKeys []string
SmsJuheKey string
SmsJuheTplID string
SmsJuheTplVal string
AlipayAppID string
AlipayPrivateKey string
} }
type RuntimeSettingS struct { type AlipaySettingS struct {
DisablePhoneVerify bool AppID string
PrivateKey string
}
type SmsJuheSettings struct {
Key string
TplID string
TplVal string
} }
type SearchSettingS struct { type FeaturesSettingS struct {
ZincHost string kv map[string]string
ZincIndex string suites map[string][]string
ZincUser string features map[string]string
ZincPassword string }
type ZincSettingS struct {
Host string
Index string
User string
Password string
} }
type DatabaseSettingS struct { type DatabaseSettingS struct {
@ -75,6 +97,20 @@ type DatabaseSettingS struct {
MaxIdleConns int MaxIdleConns int
MaxOpenConns int MaxOpenConns int
} }
type MySQLSettingS struct {
UserName string
Password string
Host string
DBName string
TablePrefix string
Charset string
ParseTime bool
LogLevel logger.LogLevel
MaxIdleConns int
MaxOpenConns int
}
type AliossSettingS struct { type AliossSettingS struct {
AliossAccessKeyID string AliossAccessKeyID string
AliossAccessKeySecret string AliossAccessKeySecret string
@ -83,6 +119,14 @@ type AliossSettingS struct {
AliossDomain string AliossDomain string
} }
type AliOSSSettingS struct {
AccessKeyID string
AccessKeySecret string
Endpoint string
Bucket string
Domain string
}
type RedisSettingS struct { type RedisSettingS struct {
Host string Host string
Password string Password string
@ -117,3 +161,92 @@ func (s *Setting) ReadSection(k string, v interface{}) error {
return nil return nil
} }
func (s *Setting) Unmarshal(objects map[string]interface{}) error {
for k, v := range objects {
err := s.vp.UnmarshalKey(k, v)
if err != nil {
return err
}
}
return nil
}
func (s *Setting) FeaturesFrom(k string) *FeaturesSettingS {
sub := s.vp.Sub(k)
keys := sub.AllKeys()
suites := make(map[string][]string)
kv := make(map[string]string, len(keys))
for _, key := range sub.AllKeys() {
val := sub.Get(key)
switch v := val.(type) {
case string:
kv[key] = v
case []interface{}:
suites[key] = sub.GetStringSlice(key)
}
}
return newFeatures(suites, kv)
}
func newFeatures(suites map[string][]string, kv map[string]string) *FeaturesSettingS {
features := &FeaturesSettingS{
suites: suites,
kv: kv,
}
features.UseDefault()
return features
}
func (f *FeaturesSettingS) UseDefault() {
defaultSuite := f.suites["default"]
f.Use(defaultSuite, true)
}
func (f *FeaturesSettingS) Use(suite []string, noDefault bool) error {
if noDefault {
f.features = make(map[string]string)
}
features := f.flatFeatures(suite)
for _, feature := range features {
feature = strings.ToLower(feature)
f.features[feature] = f.kv[feature]
}
return nil
}
func (f *FeaturesSettingS) flatFeatures(suite []string) []string {
features := make([]string, 0, len(suite)+10)
for s := suite[:]; len(s) > 0; s = s[:len(s)-1] {
if items, exist := f.suites[s[0]]; exist {
s = append(s, items...)
}
features = append(features, s[0])
s[0] = s[len(s)-1]
}
return features
}
// Cfg get value by key if exsit
func (f *FeaturesSettingS) Cfg(key string) (string, bool) {
key = strings.ToLower(key)
value, exist := f.features[key]
return value, exist
}
// CfgIf check expression is true. if expression just have a string like
// `Sms` is mean `Sms` whether define in suite feature settings. expression like
// `Sms = SmsJuhe` is mean whether `Sms` define in suite feature settings and value
// is `SmsJuhe``
func (f *FeaturesSettingS) CfgIf(expression string) bool {
kv := strings.Split(expression, "=")
key := strings.Trim(strings.ToLower(kv[0]), " ")
v, ok := f.features[key]
if len(kv) == 2 && ok && strings.Trim(kv[1], " ") == v {
return true
} else if len(kv) == 1 && ok {
return true
}
return false
}

@ -71,12 +71,12 @@ type HitItem struct {
} }
// NewClient 获取ZincClient新实例 // NewClient 获取ZincClient新实例
func NewClient(conf *setting.SearchSettingS) *ZincClient { func NewClient(conf *setting.ZincSettingS) *ZincClient {
return &ZincClient{ return &ZincClient{
ZincClientConfig: &ZincClientConfig{ ZincClientConfig: &ZincClientConfig{
ZincHost: conf.ZincHost, ZincHost: conf.Host,
ZincUser: conf.ZincUser, ZincUser: conf.User,
ZincPassword: conf.ZincPassword, ZincPassword: conf.Password,
}, },
} }
} }

Loading…
Cancel
Save