feat: 数据库引用变更
This commit is contained in:
209
features/ue/ims_user/service.go
Normal file
209
features/ue/ims_user/service.go
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
package ims_user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"be.ems/src/framework/database/redis"
|
||||||
|
neService "be.ems/src/modules/network_element/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化服务层 Service 结构体
|
||||||
|
var NewVoLTEService = &Service{
|
||||||
|
volteRepository: NewVoLTERepository,
|
||||||
|
}
|
||||||
|
|
||||||
|
// VoLTE用户信息 服务层处理
|
||||||
|
type Service struct {
|
||||||
|
volteRepository *Repository // VoLTE用户信息数据信息
|
||||||
|
}
|
||||||
|
|
||||||
|
// dataByRedis UDM签约用户 db:0 中 volte:*
|
||||||
|
func (r *Service) dataByRedis(imsi, neId string) []VoLTEUser {
|
||||||
|
arr := []VoLTEUser{}
|
||||||
|
key := fmt.Sprintf("volte:%s", imsi)
|
||||||
|
source := fmt.Sprintf("UDM_%s", neId)
|
||||||
|
|
||||||
|
// 网元主机的Redis客户端
|
||||||
|
redisClient, err := neService.NewNeInfo.NeRunRedisClient("UDM", neId)
|
||||||
|
if err != nil {
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
redisClient.Close()
|
||||||
|
redis.ConnectPush(source, nil)
|
||||||
|
}()
|
||||||
|
redis.ConnectPush(source, redisClient.Client)
|
||||||
|
|
||||||
|
udmsdArr, err := redis.GetKeys(source, key)
|
||||||
|
if err != nil {
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
mkv, err := redis.GetHashBatch(source, udmsdArr)
|
||||||
|
if err != nil {
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, m := range mkv {
|
||||||
|
var imsi, msisdn string
|
||||||
|
KeyParts := strings.Split(k, ":")
|
||||||
|
switch len(KeyParts) {
|
||||||
|
case 0, 1:
|
||||||
|
// 处理单个部分的情况
|
||||||
|
continue
|
||||||
|
case 2:
|
||||||
|
// 处理两个部分的情况
|
||||||
|
imsi = KeyParts[1]
|
||||||
|
msisdn = "-"
|
||||||
|
case 3:
|
||||||
|
// 处理三个部分的情况
|
||||||
|
imsi = KeyParts[1]
|
||||||
|
msisdn = KeyParts[2]
|
||||||
|
default:
|
||||||
|
// 处理更多部分的情况
|
||||||
|
imsi = KeyParts[1]
|
||||||
|
msisdn = KeyParts[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
var vni string = "-"
|
||||||
|
impiParts := strings.Split(m["impi"], "@")
|
||||||
|
if len(impiParts) > 1 {
|
||||||
|
vni = impiParts[1] // 输出: ims.mnc001.mcc110.3gppnetwork.org
|
||||||
|
}
|
||||||
|
a := VoLTEUser{
|
||||||
|
NeId: neId,
|
||||||
|
IMSI: imsi, // volte:360000100000130:8612300000130
|
||||||
|
MSISDN: msisdn, // 8612300000130
|
||||||
|
Tag: m["tag"], // volte = tag
|
||||||
|
VNI: vni, // ims.mnc001.mcc110.3gppnetwork.org
|
||||||
|
}
|
||||||
|
arr = append(arr, a)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据
|
||||||
|
func (r *Service) ResetData(neId string) int64 {
|
||||||
|
subArr := r.dataByRedis("*", neId)
|
||||||
|
// 数据清空后添加
|
||||||
|
go r.volteRepository.ClearAndInsert(neId, subArr)
|
||||||
|
return int64(len(subArr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseInfo 解析单个用户imsi签约信息 data从命令MML得到的结果
|
||||||
|
func (r *Service) ParseInfo(imsi, neId string, data map[string]string) VoLTEUser {
|
||||||
|
u := r.volteRepository.SelectByIMSIAndNeID(imsi, neId)
|
||||||
|
|
||||||
|
msisdn := data["msisdn"]
|
||||||
|
if imsMsisdnLen := strings.Index(msisdn, ","); imsMsisdnLen != -1 {
|
||||||
|
msisdn = msisdn[:imsMsisdnLen]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用于更新
|
||||||
|
u.NeId = neId
|
||||||
|
u.IMSI = imsi
|
||||||
|
u.MSISDN = msisdn
|
||||||
|
u.Tag = data["volte_tag"]
|
||||||
|
u.VNI = data["VNI"]
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectPage 分页查询数据库
|
||||||
|
func (r *Service) SelectPage(query map[string]any) map[string]any {
|
||||||
|
return r.volteRepository.SelectPage(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectList 查询数据库
|
||||||
|
func (r *Service) SelectList(u VoLTEUser) []VoLTEUser {
|
||||||
|
return r.volteRepository.SelectList(u)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 从数据中读取后删除imsi再存入数据库
|
||||||
|
// imsi长度15,ki长度32,opc长度0或者32
|
||||||
|
func (r *Service) Insert(neId string, u VoLTEUser) int64 {
|
||||||
|
uArr := r.dataByRedis(u.IMSI, neId)
|
||||||
|
if len(uArr) > 0 {
|
||||||
|
r.volteRepository.Delete(u.IMSI, neId)
|
||||||
|
return r.volteRepository.Inserts(uArr)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertData 导入文件数据 dataType目前两种:txt/csv
|
||||||
|
func (r *Service) InsertData(neId, dataType string, data any) int64 {
|
||||||
|
// imsi截取前缀,重新获取部分数据
|
||||||
|
prefixes := make(map[string]struct{})
|
||||||
|
|
||||||
|
if dataType == "csv" {
|
||||||
|
for _, v := range data.([]map[string]string) {
|
||||||
|
imsi := v["imsi"]
|
||||||
|
if len(imsi) < 6 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
prefix := imsi[:len(imsi)-4]
|
||||||
|
prefixes[prefix] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dataType == "txt" {
|
||||||
|
for _, v := range data.([][]string) {
|
||||||
|
imsi := v[0]
|
||||||
|
if len(imsi) < 6 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
prefix := imsi[:len(imsi)-4]
|
||||||
|
prefixes[prefix] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据前缀重新加载插入
|
||||||
|
var num int64 = 0
|
||||||
|
for prefix := range prefixes {
|
||||||
|
// keys volte:4600001000004*
|
||||||
|
arr := r.dataByRedis(prefix+"*", neId)
|
||||||
|
if len(arr) > 0 {
|
||||||
|
r.volteRepository.DeletePrefixByIMSI(prefix, neId)
|
||||||
|
num += r.volteRepository.Inserts(arr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除单个不重新加载
|
||||||
|
func (r *Service) Delete(neId, imsi string) int64 {
|
||||||
|
return r.volteRepository.Delete(imsi, neId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadData 重新加载从imsi开始num的数据
|
||||||
|
func (r *Service) LoadData(neId, imsi, num string) {
|
||||||
|
startIMSI, _ := strconv.ParseInt(imsi, 10, 64)
|
||||||
|
subNum, _ := strconv.ParseInt(num, 10, 64)
|
||||||
|
var i int64
|
||||||
|
for i = 0; i < subNum; i++ {
|
||||||
|
keyIMSI := fmt.Sprintf("%015d", startIMSI+i)
|
||||||
|
// 删除原数据
|
||||||
|
r.volteRepository.Delete(keyIMSI, neId)
|
||||||
|
arr := r.dataByRedis(keyIMSI, neId)
|
||||||
|
if len(arr) < 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r.volteRepository.Inserts(arr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseCommandParams 解析数据组成命令参数 msisdn=xx,xx=xx,...
|
||||||
|
func (r *Service) ParseCommandParams(item VoLTEUser) string {
|
||||||
|
var conditions []string
|
||||||
|
if item.MSISDN != "" {
|
||||||
|
conditions = append(conditions, fmt.Sprintf("msisdn=%s", item.MSISDN))
|
||||||
|
}
|
||||||
|
|
||||||
|
if item.Tag != "" {
|
||||||
|
conditions = append(conditions, fmt.Sprintf("volte=%s", item.Tag))
|
||||||
|
}
|
||||||
|
if item.VNI != "" {
|
||||||
|
conditions = append(conditions, fmt.Sprintf("vni=%s", item.VNI))
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(conditions, ",")
|
||||||
|
}
|
||||||
234
features/ue/service/ims_user.go
Normal file
234
features/ue/service/ims_user.go
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"be.ems/features/ue/model"
|
||||||
|
"be.ems/features/ue/repository"
|
||||||
|
"be.ems/src/framework/database/redis"
|
||||||
|
neService "be.ems/src/modules/network_element/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化服务层 IMSUserService 结构体
|
||||||
|
var NewIMSUserService = &IMSUserService{
|
||||||
|
imsUserRepository: repository.NewIMSUserRepository,
|
||||||
|
}
|
||||||
|
|
||||||
|
// VoLTE用户信息 服务层处理
|
||||||
|
type IMSUserService struct {
|
||||||
|
imsUserRepository *repository.IMSUserRepository // VoLTE用户信息数据信息
|
||||||
|
}
|
||||||
|
|
||||||
|
// dataByRedis UDM签约用户 db:0 中 volte:*
|
||||||
|
func (r *IMSUserService) dataByRedis(imsi, neId string) []model.IMSUser {
|
||||||
|
arr := []model.IMSUser{}
|
||||||
|
key := fmt.Sprintf("volte:%s", imsi)
|
||||||
|
source := fmt.Sprintf("UDM_%s", neId)
|
||||||
|
|
||||||
|
// 网元主机的Redis客户端
|
||||||
|
redisClient, err := neService.NewNeInfo.NeRunRedisClient("UDM", neId)
|
||||||
|
if err != nil {
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
redisClient.Close()
|
||||||
|
redis.ConnectPush(source, nil)
|
||||||
|
}()
|
||||||
|
redis.ConnectPush(source, redisClient.Client)
|
||||||
|
|
||||||
|
udmsdArr, err := redis.GetKeys(source, key)
|
||||||
|
if err != nil {
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
mkv, err := redis.GetHashBatch(source, udmsdArr)
|
||||||
|
if err != nil {
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, m := range mkv {
|
||||||
|
var imsi, msisdn string
|
||||||
|
KeyParts := strings.Split(k, ":")
|
||||||
|
switch len(KeyParts) {
|
||||||
|
case 0, 1:
|
||||||
|
// 处理单个部分的情况
|
||||||
|
continue
|
||||||
|
case 2:
|
||||||
|
// 处理两个部分的情况
|
||||||
|
imsi = KeyParts[1]
|
||||||
|
msisdn = "-"
|
||||||
|
case 3:
|
||||||
|
// 处理三个部分的情况
|
||||||
|
imsi = KeyParts[1]
|
||||||
|
msisdn = KeyParts[2]
|
||||||
|
default:
|
||||||
|
// 处理更多部分的情况
|
||||||
|
imsi = KeyParts[1]
|
||||||
|
msisdn = KeyParts[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
var vni string = "-"
|
||||||
|
impiParts := strings.Split(m["impi"], "@")
|
||||||
|
if len(impiParts) > 1 {
|
||||||
|
vni = impiParts[1] // 输出: ims.mnc001.mcc110.3gppnetwork.org
|
||||||
|
}
|
||||||
|
a := model.IMSUser{
|
||||||
|
NeId: neId,
|
||||||
|
IMSI: imsi, // volte:360000100000130:8612300000130
|
||||||
|
MSISDN: msisdn, // 8612300000130
|
||||||
|
Tag: model.ParseCallTag(m["tag"]), // volte = tag
|
||||||
|
VNI: vni, // ims.mnc001.mcc110.3gppnetwork.org
|
||||||
|
}
|
||||||
|
arr = append(arr, a)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据
|
||||||
|
func (r *IMSUserService) ResetData(neId string) int64 {
|
||||||
|
subArr := r.dataByRedis("*", neId)
|
||||||
|
// 数据清空后添加
|
||||||
|
go r.imsUserRepository.ClearAndInsert(neId, subArr)
|
||||||
|
return int64(len(subArr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseInfo 解析单个用户imsi签约信息 data从命令MML得到的结果
|
||||||
|
func (r *IMSUserService) ParseInfo(imsi, neId string, data map[string]string) model.IMSUser {
|
||||||
|
u := r.imsUserRepository.SelectByIMSIAndNeID(imsi, neId)
|
||||||
|
|
||||||
|
msisdn := data["msisdn"]
|
||||||
|
if imsMsisdnLen := strings.Index(msisdn, ","); imsMsisdnLen != -1 {
|
||||||
|
msisdn = msisdn[:imsMsisdnLen]
|
||||||
|
}
|
||||||
|
var vni string = "-"
|
||||||
|
impiParts := strings.Split(data["impi"], "@")
|
||||||
|
if len(impiParts) > 1 {
|
||||||
|
vni = impiParts[1] // 输出: ims.mnc001.mcc110.3gppnetwork.org
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用于更新
|
||||||
|
u.NeId = neId
|
||||||
|
u.IMSI = imsi
|
||||||
|
u.MSISDN = msisdn
|
||||||
|
u.Tag = model.ParseCallTag(data["volte_tag"])
|
||||||
|
u.VNI = vni
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectPage 分页查询数据库
|
||||||
|
func (r *IMSUserService) SelectPage(query map[string]any) map[string]any {
|
||||||
|
return r.imsUserRepository.SelectPage(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectList 查询数据库
|
||||||
|
func (r *IMSUserService) SelectList(u model.IMSUser) []model.IMSUser {
|
||||||
|
return r.imsUserRepository.SelectList(u)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 从数据中读取后删除imsi再存入数据库
|
||||||
|
// imsi长度15,ki长度32,opc长度0或者32
|
||||||
|
func (r *IMSUserService) Insert(neId string, u model.IMSUser) int64 {
|
||||||
|
uArr := r.dataByRedis(u.IMSI+":*", neId)
|
||||||
|
if len(uArr) > 0 {
|
||||||
|
r.imsUserRepository.Delete(u.IMSI, neId)
|
||||||
|
return r.imsUserRepository.Inserts(uArr)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertData 导入文件数据 dataType目前两种:txt/csv
|
||||||
|
func (r *IMSUserService) InsertData(neId, dataType string, data any) int64 {
|
||||||
|
// imsi截取前缀,重新获取部分数据
|
||||||
|
prefixes := make(map[string]struct{})
|
||||||
|
|
||||||
|
if dataType == "csv" {
|
||||||
|
for _, v := range data.([]map[string]string) {
|
||||||
|
imsi := v["imsi"]
|
||||||
|
if len(imsi) < 6 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
prefix := imsi[:len(imsi)-4]
|
||||||
|
prefixes[prefix] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dataType == "txt" {
|
||||||
|
for _, v := range data.([][]string) {
|
||||||
|
imsi := v[0]
|
||||||
|
if len(imsi) < 6 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
prefix := imsi[:len(imsi)-4]
|
||||||
|
prefixes[prefix] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据前缀重新加载插入
|
||||||
|
var num int64 = 0
|
||||||
|
for prefix := range prefixes {
|
||||||
|
// keys volte:4600001000004*
|
||||||
|
arr := r.dataByRedis(prefix+"*", neId)
|
||||||
|
if len(arr) > 0 {
|
||||||
|
r.imsUserRepository.DeletePrefixByIMSI(prefix, neId)
|
||||||
|
num += r.imsUserRepository.Inserts(arr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除单个不重新加载
|
||||||
|
func (r *IMSUserService) Delete(neId, imsi string) int64 {
|
||||||
|
return r.imsUserRepository.Delete(imsi, neId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadData 重新加载从imsi开始num的数据
|
||||||
|
func (r *IMSUserService) LoadData(neId, imsi, num string) {
|
||||||
|
startIMSI, _ := strconv.ParseInt(imsi, 10, 64)
|
||||||
|
subNum, _ := strconv.ParseInt(num, 10, 64)
|
||||||
|
var i int64
|
||||||
|
for i = 0; i < subNum; i++ {
|
||||||
|
var keyIMSI string
|
||||||
|
if len(imsi) == model.IMSI_MAX_LENGTH {
|
||||||
|
keyIMSI = fmt.Sprintf("%015d", startIMSI+i)
|
||||||
|
} else {
|
||||||
|
// 处理不满15位的IMSI, tag=TAG_VoIP
|
||||||
|
keyIMSI = fmt.Sprintf("%d", startIMSI+i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除原数据
|
||||||
|
r.imsUserRepository.Delete(keyIMSI, neId)
|
||||||
|
arr := r.dataByRedis(keyIMSI+":*", neId)
|
||||||
|
if len(arr) < 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r.imsUserRepository.Inserts(arr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseCommandParams 解析数据组成命令参数 msisdn=xx,xx=xx,...
|
||||||
|
func (r *IMSUserService) ParseCommandParams(item model.IMSUser) string {
|
||||||
|
var conditions []string
|
||||||
|
if item.MSISDN != "" {
|
||||||
|
conditions = append(conditions, fmt.Sprintf("msisdn=%s", item.MSISDN))
|
||||||
|
}
|
||||||
|
|
||||||
|
if item.Tag != model.ParseCallTag("") {
|
||||||
|
conditions = append(conditions, fmt.Sprintf("volte=%d", item.Tag))
|
||||||
|
}
|
||||||
|
if item.VNI != "" {
|
||||||
|
conditions = append(conditions, fmt.Sprintf("vni=%s", item.VNI))
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(conditions, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetDataWithResult 重置鉴权用户数据,清空数据库重新同步Redis数据
|
||||||
|
// 通过 channel 返回 ClearAndInsert 的执行结果
|
||||||
|
func (r *IMSUserService) ResetDataWithResult(neId string) chan int64 {
|
||||||
|
arr := r.dataByRedis("*", neId)
|
||||||
|
resultCh := make(chan int64, 1)
|
||||||
|
go func() {
|
||||||
|
resultCh <- r.imsUserRepository.ClearAndInsert(neId, arr)
|
||||||
|
}()
|
||||||
|
return resultCh
|
||||||
|
}
|
||||||
186
features/ue/service/voip_auth.go
Normal file
186
features/ue/service/voip_auth.go
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"be.ems/features/ue/model"
|
||||||
|
"be.ems/features/ue/repository"
|
||||||
|
"be.ems/src/framework/database/redis"
|
||||||
|
neService "be.ems/src/modules/network_element/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 实例化服务层 VoIPAuthService 结构体
|
||||||
|
var NewVoIPAuthService = &VoIPAuthService{
|
||||||
|
voipAuthRepository: repository.NewVoIPAuthRepository,
|
||||||
|
}
|
||||||
|
|
||||||
|
// VoLTE用户信息 服务层处理
|
||||||
|
type VoIPAuthService struct {
|
||||||
|
voipAuthRepository *repository.VoIPAuthRepository // VoLTE用户信息数据信息
|
||||||
|
}
|
||||||
|
|
||||||
|
// dataByRedis VoIP鉴权数据 db:0 中 voip:*
|
||||||
|
func (r *VoIPAuthService) dataByRedis(userName, neId string) []model.VoIPAuth {
|
||||||
|
arr := []model.VoIPAuth{}
|
||||||
|
key := fmt.Sprintf("voip:%s", userName)
|
||||||
|
source := fmt.Sprintf("UDM_%s", neId)
|
||||||
|
|
||||||
|
// 网元主机的Redis客户端
|
||||||
|
redisClient, err := neService.NewNeInfo.NeRunRedisClient("UDM", neId)
|
||||||
|
if err != nil {
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
redisClient.Close()
|
||||||
|
redis.ConnectPush(source, nil)
|
||||||
|
}()
|
||||||
|
redis.ConnectPush(source, redisClient.Client)
|
||||||
|
|
||||||
|
udmsdArr, err := redis.GetKeys(source, key)
|
||||||
|
if err != nil {
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
mkv, err := redis.GetHashBatch(source, udmsdArr)
|
||||||
|
if err != nil {
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, m := range mkv {
|
||||||
|
var userName string
|
||||||
|
KeyParts := strings.Split(k, ":")
|
||||||
|
if len(KeyParts) > 1 {
|
||||||
|
userName = KeyParts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
a := model.VoIPAuth{
|
||||||
|
NeId: neId,
|
||||||
|
UserName: userName, // userName
|
||||||
|
Password: m["password"], //
|
||||||
|
}
|
||||||
|
arr = append(arr, a)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetData 重置鉴权用户数据,清空数据库重新同步Redis数据
|
||||||
|
func (r *VoIPAuthService) ResetData(neId string) int64 {
|
||||||
|
subArr := r.dataByRedis("*", neId)
|
||||||
|
// 数据清空后添加
|
||||||
|
go r.voipAuthRepository.ClearAndInsert(neId, subArr)
|
||||||
|
return int64(len(subArr))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseInfo 解析单个用户userName信息 data从命令MML得到的结果
|
||||||
|
func (r *VoIPAuthService) ParseInfo(userName, neId string, data map[string]string) model.VoIPAuth {
|
||||||
|
u := r.voipAuthRepository.SelectByUserNameAndNeID(userName, neId)
|
||||||
|
password := data["password"]
|
||||||
|
|
||||||
|
// 用于更新
|
||||||
|
u.NeId = neId
|
||||||
|
u.UserName = userName
|
||||||
|
u.Password = password
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectPage 分页查询数据库
|
||||||
|
func (r *VoIPAuthService) SelectPage(query map[string]any) map[string]any {
|
||||||
|
return r.voipAuthRepository.SelectPage(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectList 查询数据库
|
||||||
|
func (r *VoIPAuthService) SelectList(u model.VoIPAuth) []model.VoIPAuth {
|
||||||
|
return r.voipAuthRepository.SelectList(u)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert 从数据中读取后删除userName再存入数据库
|
||||||
|
func (r *VoIPAuthService) Insert(neId string, u model.VoIPAuth) int64 {
|
||||||
|
uArr := r.dataByRedis(u.UserName, neId)
|
||||||
|
if len(uArr) > 0 {
|
||||||
|
r.voipAuthRepository.Delete(u.UserName, neId)
|
||||||
|
return r.voipAuthRepository.Inserts(uArr)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertData 导入文件数据 dataType目前两种:txt/csv
|
||||||
|
func (r *VoIPAuthService) InsertData(neId, dataType string, data any) int64 {
|
||||||
|
userNames := make(map[string]struct{})
|
||||||
|
|
||||||
|
if dataType == "csv" {
|
||||||
|
for _, v := range data.([]map[string]string) {
|
||||||
|
userName := v["userName"]
|
||||||
|
// if len(userName) < 6 {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// prefix := userName[:len(userName)-4]
|
||||||
|
userNames[userName] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if dataType == "txt" {
|
||||||
|
for _, v := range data.([][]string) {
|
||||||
|
userName := v[0]
|
||||||
|
// if len(userName) < 6 {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// prefix := userName[:len(userName)-4]
|
||||||
|
userNames[userName] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据前缀重新加载插入
|
||||||
|
var num int64 = 0
|
||||||
|
for userName := range userNames {
|
||||||
|
// keys voip:11111
|
||||||
|
arr := r.dataByRedis(userName, neId)
|
||||||
|
if len(arr) > 0 {
|
||||||
|
r.voipAuthRepository.DeleteByUserName(userName, neId)
|
||||||
|
num += r.voipAuthRepository.Inserts(arr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 删除单个不重新加载
|
||||||
|
func (r *VoIPAuthService) Delete(neId, userName string) int64 {
|
||||||
|
return r.voipAuthRepository.Delete(userName, neId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadData 重新加载从userName开始num的数据
|
||||||
|
func (r *VoIPAuthService) LoadData(neId, userName, num string) {
|
||||||
|
startUserName, _ := strconv.ParseInt(userName, 10, 64)
|
||||||
|
subNum, _ := strconv.ParseInt(num, 10, 64)
|
||||||
|
var i int64
|
||||||
|
for i = 0; i < subNum; i++ {
|
||||||
|
keyUserName := fmt.Sprintf("%d", startUserName+i)
|
||||||
|
// 删除原数据
|
||||||
|
r.voipAuthRepository.Delete(keyUserName, neId)
|
||||||
|
arr := r.dataByRedis(keyUserName, neId)
|
||||||
|
if len(arr) < 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r.voipAuthRepository.Inserts(arr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseCommandParams 解析数据组成命令参数 msisdn=xx,xx=xx,...
|
||||||
|
func (r *VoIPAuthService) ParseCommandParams(item model.VoIPAuth) string {
|
||||||
|
var conditions []string
|
||||||
|
if item.Password != "" {
|
||||||
|
conditions = append(conditions, fmt.Sprintf("password=%s", item.Password))
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(conditions, ",")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetDataWithResult 重置鉴权用户数据,清空数据库重新同步Redis数据
|
||||||
|
// 通过 channel 返回 ClearAndInsert 的执行结果
|
||||||
|
func (r *VoIPAuthService) ResetDataWithResult(neId string) chan int64 {
|
||||||
|
arr := r.dataByRedis("*", neId)
|
||||||
|
resultCh := make(chan int64, 1)
|
||||||
|
go func() {
|
||||||
|
resultCh <- r.voipAuthRepository.ClearAndInsert(neId, arr)
|
||||||
|
}()
|
||||||
|
return resultCh
|
||||||
|
}
|
||||||
@@ -5,9 +5,9 @@ import (
|
|||||||
|
|
||||||
"be.ems/src/framework/config"
|
"be.ems/src/framework/config"
|
||||||
"be.ems/src/framework/cron"
|
"be.ems/src/framework/cron"
|
||||||
"be.ems/src/framework/datasource"
|
"be.ems/src/framework/database/db"
|
||||||
|
"be.ems/src/framework/database/redis"
|
||||||
"be.ems/src/framework/logger"
|
"be.ems/src/framework/logger"
|
||||||
"be.ems/src/framework/redis"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed config/*.yaml
|
//go:embed config/*.yaml
|
||||||
@@ -23,7 +23,7 @@ func ConfigurationInit() {
|
|||||||
// 初始程序日志
|
// 初始程序日志
|
||||||
logger.InitLogger()
|
logger.InitLogger()
|
||||||
// 连接数据库实例
|
// 连接数据库实例
|
||||||
datasource.Connect()
|
db.Connect()
|
||||||
// 连接Redis实例
|
// 连接Redis实例
|
||||||
redis.Connect()
|
redis.Connect()
|
||||||
// 启动调度任务实例
|
// 启动调度任务实例
|
||||||
@@ -37,7 +37,7 @@ func ConfigurationClose() {
|
|||||||
// 关闭Redis实例
|
// 关闭Redis实例
|
||||||
redis.Close()
|
redis.Close()
|
||||||
// 关闭数据库实例
|
// 关闭数据库实例
|
||||||
datasource.Close()
|
db.Close()
|
||||||
// 关闭程序日志
|
// 关闭程序日志
|
||||||
logger.Close()
|
logger.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
207
src/framework/database/db/db.go
Normal file
207
src/framework/database/db/db.go
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
gormLog "gorm.io/gorm/logger"
|
||||||
|
|
||||||
|
"be.ems/src/framework/config"
|
||||||
|
"be.ems/src/framework/logger"
|
||||||
|
"be.ems/src/framework/utils/parse"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 数据库连接实例
|
||||||
|
var dbMap = make(map[string]*gorm.DB)
|
||||||
|
|
||||||
|
type dialectInfo struct {
|
||||||
|
dialectic gorm.Dialector
|
||||||
|
logging bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// 载入数据库连接
|
||||||
|
func loadDialect() map[string]dialectInfo {
|
||||||
|
dialects := make(map[string]dialectInfo)
|
||||||
|
|
||||||
|
// 读取数据源配置
|
||||||
|
datasource := config.Get("gorm.datasource").(map[string]any)
|
||||||
|
for key, value := range datasource {
|
||||||
|
item := value.(map[string]any)
|
||||||
|
// 数据库类型对应的数据库连接
|
||||||
|
switch item["type"] {
|
||||||
|
case "mysql":
|
||||||
|
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
||||||
|
item["username"],
|
||||||
|
item["password"],
|
||||||
|
item["host"],
|
||||||
|
item["port"],
|
||||||
|
item["database"],
|
||||||
|
)
|
||||||
|
dialects[key] = dialectInfo{
|
||||||
|
dialectic: mysql.Open(dsn),
|
||||||
|
logging: parse.Boolean(item["logging"]),
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
logger.Warnf("%s: %v\n Not Load DB Config Type", key, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dialects
|
||||||
|
}
|
||||||
|
|
||||||
|
// 载入连接日志配置
|
||||||
|
func loadLogger() gormLog.Interface {
|
||||||
|
newLogger := gormLog.New(
|
||||||
|
log.New(os.Stdout, "[GORM] ", log.LstdFlags), // 将日志输出到控制台
|
||||||
|
gormLog.Config{
|
||||||
|
SlowThreshold: time.Second, // Slow SQL 阈值
|
||||||
|
LogLevel: gormLog.Info, // 日志级别 Silent不输出任何日志
|
||||||
|
ParameterizedQueries: false, // 参数化查询SQL 用实际值带入?的执行语句
|
||||||
|
Colorful: false, // 彩色日志输出
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return newLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect 连接数据库实例
|
||||||
|
func Connect() {
|
||||||
|
// 遍历进行连接数据库实例
|
||||||
|
for key, info := range loadDialect() {
|
||||||
|
opts := &gorm.Config{
|
||||||
|
Logger: gormLog.Discard,
|
||||||
|
}
|
||||||
|
// 是否需要日志输出
|
||||||
|
if info.logging {
|
||||||
|
opts.Logger = loadLogger()
|
||||||
|
}
|
||||||
|
// 创建连接
|
||||||
|
db, err := gorm.Open(info.dialectic, opts)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("failed error db connect: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// 获取底层 SQL 数据库连接
|
||||||
|
sqlDB, err := db.DB()
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatalf("failed error underlying SQL database: %v", err)
|
||||||
|
}
|
||||||
|
// 测试数据库连接
|
||||||
|
err = sqlDB.Ping()
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatalf("failed error ping database: %v", err)
|
||||||
|
}
|
||||||
|
// SetMaxIdleConns 用于设置连接池中空闲连接的最大数量。
|
||||||
|
sqlDB.SetMaxIdleConns(10)
|
||||||
|
// SetMaxOpenConns 设置打开数据库连接的最大数量。
|
||||||
|
sqlDB.SetMaxOpenConns(100)
|
||||||
|
// SetConnMaxLifetime 设置了连接可复用的最大时间。
|
||||||
|
sqlDB.SetConnMaxLifetime(time.Hour)
|
||||||
|
logger.Infof("database %s connection is successful.", key)
|
||||||
|
dbMap[key] = db
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close 关闭数据库实例
|
||||||
|
func Close() {
|
||||||
|
for _, db := range dbMap {
|
||||||
|
sqlDB, err := db.DB()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := sqlDB.Close(); err != nil {
|
||||||
|
logger.Errorf("fatal error db close: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DB 获取数据源
|
||||||
|
//
|
||||||
|
// source-数据源
|
||||||
|
func DB(source string) *gorm.DB {
|
||||||
|
// 不指定时获取默认实例
|
||||||
|
if source == "" {
|
||||||
|
source = config.Get("gorm.defaultDataSourceName").(string)
|
||||||
|
}
|
||||||
|
db := dbMap[source]
|
||||||
|
if db == nil {
|
||||||
|
logger.Errorf("not database source: %s", source)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
// Names 获取数据源名称列表
|
||||||
|
func Names() []string {
|
||||||
|
var names []string
|
||||||
|
for key := range dbMap {
|
||||||
|
names = append(names, key)
|
||||||
|
}
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
// RawDB 原生语句查询
|
||||||
|
//
|
||||||
|
// source-数据源
|
||||||
|
// sql-预编译的SQL语句
|
||||||
|
// parameters-预编译的SQL语句参数
|
||||||
|
func RawDB(source string, sql string, parameters []any) ([]map[string]any, error) {
|
||||||
|
var rows []map[string]any
|
||||||
|
// 数据源
|
||||||
|
db := DB(source)
|
||||||
|
if db == nil {
|
||||||
|
return rows, fmt.Errorf("not database source")
|
||||||
|
}
|
||||||
|
// 使用正则表达式替换连续的空白字符为单个空格
|
||||||
|
fmtSql := regexp.MustCompile(`\s+`).ReplaceAllString(sql, " ")
|
||||||
|
// 查询结果
|
||||||
|
res := db.Raw(fmtSql, parameters...).Scan(&rows)
|
||||||
|
if res.Error != nil {
|
||||||
|
return nil, res.Error
|
||||||
|
}
|
||||||
|
return rows, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecDB 原生语句执行
|
||||||
|
//
|
||||||
|
// source-数据源
|
||||||
|
// sql-预编译的SQL语句
|
||||||
|
// parameters-预编译的SQL语句参数
|
||||||
|
func ExecDB(source string, sql string, parameters []any) (int64, error) {
|
||||||
|
// 数据源
|
||||||
|
db := DB(source)
|
||||||
|
if db == nil {
|
||||||
|
return 0, fmt.Errorf("not database source")
|
||||||
|
}
|
||||||
|
// 使用正则表达式替换连续的空白字符为单个空格
|
||||||
|
fmtSql := regexp.MustCompile(`\s+`).ReplaceAllString(sql, " ")
|
||||||
|
// 执行结果
|
||||||
|
res := db.Exec(fmtSql, parameters...)
|
||||||
|
if res.Error != nil {
|
||||||
|
return 0, res.Error
|
||||||
|
}
|
||||||
|
return res.RowsAffected, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PageNumSize 分页页码记录数
|
||||||
|
//
|
||||||
|
// pageNum-页码
|
||||||
|
// pageSize-记录数
|
||||||
|
func PageNumSize(pageNum, pageSize any) (int, int) {
|
||||||
|
// 记录起始索引
|
||||||
|
num := parse.Number(pageNum)
|
||||||
|
if num < 1 {
|
||||||
|
num = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示记录数
|
||||||
|
size := parse.Number(pageSize)
|
||||||
|
if size < 0 {
|
||||||
|
size = 10
|
||||||
|
}
|
||||||
|
return int(num - 1), int(size)
|
||||||
|
}
|
||||||
104
src/framework/database/db/expand.go
Normal file
104
src/framework/database/db/expand.go
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"be.ems/src/framework/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImportSQL 导入SQL
|
||||||
|
func ImportSQL() {
|
||||||
|
sqlPath := config.Get("sqlPath").(string)
|
||||||
|
if sqlPath == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sqlSource := config.Get("sqlSource").(string)
|
||||||
|
if sqlSource == "" {
|
||||||
|
sqlSource = config.Get("database.defaultDataSourceName").(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据源
|
||||||
|
db := DB(sqlSource)
|
||||||
|
if db == nil {
|
||||||
|
log.Fatalln("not database source")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取路径信息
|
||||||
|
fileInfo, err := os.Stat(sqlPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理目录或文件
|
||||||
|
if fileInfo.IsDir() {
|
||||||
|
// 处理目录
|
||||||
|
files, err := os.ReadDir(sqlPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
if file.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(file.Name(), ".sql") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
processSQLFile(db, filepath.Join(sqlPath, file.Name()))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 处理单个文件
|
||||||
|
processSQLFile(db, sqlPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("process success")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理单个SQL文件的通用函数
|
||||||
|
func processSQLFile(db *gorm.DB, filePath string) {
|
||||||
|
file, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// 逐行读取 SQL 文件
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
var sqlBuilder strings.Builder
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := strings.TrimSpace(scanner.Text())
|
||||||
|
// 跳过注释和空行
|
||||||
|
if strings.HasPrefix(line, "--") || strings.TrimSpace(line) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// 跳过配置语句
|
||||||
|
if strings.HasPrefix(line, "/*!") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlBuilder.WriteString(line + "\n")
|
||||||
|
|
||||||
|
// 当遇到分号时,执行 SQL 语句
|
||||||
|
if strings.HasSuffix(line, ";") {
|
||||||
|
// 执行 SQL 语句
|
||||||
|
if err := db.Exec(sqlBuilder.String()).Error; err != nil {
|
||||||
|
log.Fatalln(err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlBuilder.Reset()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,35 +2,21 @@ package redis
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
|
||||||
"be.ems/src/framework/config"
|
"be.ems/src/framework/config"
|
||||||
"be.ems/src/framework/logger"
|
"be.ems/src/framework/logger"
|
||||||
|
|
||||||
"github.com/redis/go-redis/v9"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Redis连接实例
|
// Redis连接实例
|
||||||
var rdbMap = make(map[string]*redis.Client)
|
var rdbMap = make(map[string]*redis.Client)
|
||||||
|
|
||||||
// 声明定义限流脚本命令
|
// Connect 连接Redis实例
|
||||||
var rateLimitCommand = redis.NewScript(`
|
|
||||||
local key = KEYS[1]
|
|
||||||
local time = tonumber(ARGV[1])
|
|
||||||
local count = tonumber(ARGV[2])
|
|
||||||
local current = redis.call('get', key);
|
|
||||||
if current and tonumber(current) >= count then
|
|
||||||
return tonumber(current);
|
|
||||||
end
|
|
||||||
current = redis.call('incr', key)
|
|
||||||
if tonumber(current) == 1 then
|
|
||||||
redis.call('expire', key, time)
|
|
||||||
end
|
|
||||||
return tonumber(current);`)
|
|
||||||
|
|
||||||
// 连接Redis实例
|
|
||||||
func Connect() {
|
func Connect() {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
// 读取数据源配置
|
// 读取数据源配置
|
||||||
@@ -47,29 +33,23 @@ func Connect() {
|
|||||||
// 测试数据库连接
|
// 测试数据库连接
|
||||||
pong, err := rdb.Ping(ctx).Result()
|
pong, err := rdb.Ping(ctx).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatalf("Ping redis %s is %v", k, err)
|
logger.Fatalf("failed error redis connect: %s is %v", k, err)
|
||||||
}
|
}
|
||||||
logger.Infof("redis %s %s %d connection is successful.", k, pong, client["db"].(int))
|
logger.Infof("redis %s %d %s connection is successful.", k, client["db"].(int), pong)
|
||||||
rdbMap[k] = rdb
|
rdbMap[k] = rdb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭Redis实例
|
// Close 关闭Redis实例
|
||||||
func Close() {
|
func Close() {
|
||||||
for _, rdb := range rdbMap {
|
for _, rdb := range rdbMap {
|
||||||
if err := rdb.Close(); err != nil {
|
if err := rdb.Close(); err != nil {
|
||||||
logger.Errorf("fatal error db close: %s", err)
|
logger.Errorf("redis db close: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取默认实例
|
// RDB 获取实例
|
||||||
func DefaultRDB() *redis.Client {
|
|
||||||
source := config.Get("redis.defaultDataSourceName").(string)
|
|
||||||
return rdbMap[source]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取实例
|
|
||||||
func RDB(source string) *redis.Client {
|
func RDB(source string) *redis.Client {
|
||||||
// 不指定时获取默认实例
|
// 不指定时获取默认实例
|
||||||
if source == "" {
|
if source == "" {
|
||||||
@@ -80,18 +60,19 @@ func RDB(source string) *redis.Client {
|
|||||||
|
|
||||||
// Info 获取redis服务信息
|
// Info 获取redis服务信息
|
||||||
func Info(source string) map[string]map[string]string {
|
func Info(source string) map[string]map[string]string {
|
||||||
|
infoObj := make(map[string]map[string]string)
|
||||||
// 数据源
|
// 数据源
|
||||||
rdb := DefaultRDB()
|
rdb := RDB(source)
|
||||||
if source != "" {
|
if rdb == nil {
|
||||||
rdb = RDB(source)
|
return infoObj
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
info, err := rdb.Info(ctx).Result()
|
info, err := rdb.Info(ctx).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return map[string]map[string]string{}
|
return infoObj
|
||||||
}
|
}
|
||||||
infoObj := make(map[string]map[string]string)
|
|
||||||
lines := strings.Split(info, "\r\n")
|
lines := strings.Split(info, "\r\n")
|
||||||
label := ""
|
label := ""
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
@@ -114,9 +95,9 @@ func Info(source string) map[string]map[string]string {
|
|||||||
// KeySize 获取redis当前连接可用键Key总数信息
|
// KeySize 获取redis当前连接可用键Key总数信息
|
||||||
func KeySize(source string) int64 {
|
func KeySize(source string) int64 {
|
||||||
// 数据源
|
// 数据源
|
||||||
rdb := DefaultRDB()
|
rdb := RDB(source)
|
||||||
if source != "" {
|
if rdb == nil {
|
||||||
rdb = RDB(source)
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@@ -129,18 +110,19 @@ func KeySize(source string) int64 {
|
|||||||
|
|
||||||
// CommandStats 获取redis命令状态信息
|
// CommandStats 获取redis命令状态信息
|
||||||
func CommandStats(source string) []map[string]string {
|
func CommandStats(source string) []map[string]string {
|
||||||
|
statsObjArr := make([]map[string]string, 0)
|
||||||
// 数据源
|
// 数据源
|
||||||
rdb := DefaultRDB()
|
rdb := RDB(source)
|
||||||
if source != "" {
|
if rdb == nil {
|
||||||
rdb = RDB(source)
|
return statsObjArr
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
commandstats, err := rdb.Info(ctx, "commandstats").Result()
|
commandstats, err := rdb.Info(ctx, "commandstats").Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []map[string]string{}
|
return statsObjArr
|
||||||
}
|
}
|
||||||
statsObjArr := make([]map[string]string, 0)
|
|
||||||
lines := strings.Split(commandstats, "\r\n")
|
lines := strings.Split(commandstats, "\r\n")
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
if !strings.HasPrefix(line, "cmdstat_") {
|
if !strings.HasPrefix(line, "cmdstat_") {
|
||||||
@@ -157,12 +139,12 @@ func CommandStats(source string) []map[string]string {
|
|||||||
return statsObjArr
|
return statsObjArr
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取键的剩余有效时间(秒)
|
// GetExpire 获取键的剩余有效时间(秒)
|
||||||
func GetExpire(source string, key string) (float64, error) {
|
func GetExpire(source string, key string) (int64, error) {
|
||||||
// 数据源
|
// 数据源
|
||||||
rdb := DefaultRDB()
|
rdb := RDB(source)
|
||||||
if source != "" {
|
if rdb == nil {
|
||||||
rdb = RDB(source)
|
return 0, fmt.Errorf("redis not client")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@@ -170,168 +152,195 @@ func GetExpire(source string, key string) (float64, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return ttl.Seconds(), nil
|
return int64(ttl.Seconds()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获得缓存数据的key列表
|
// GetKeys 获得缓存数据的key列表
|
||||||
func GetKeys(source string, match string) ([]string, error) {
|
func GetKeys(source string, pattern string) ([]string, error) {
|
||||||
|
keys := make([]string, 0)
|
||||||
// 数据源
|
// 数据源
|
||||||
rdb := DefaultRDB()
|
rdb := RDB(source)
|
||||||
if source != "" {
|
if rdb == nil {
|
||||||
rdb = RDB(source)
|
return keys, fmt.Errorf("redis not client")
|
||||||
}
|
}
|
||||||
|
|
||||||
keys := make([]string, 0)
|
// 游标
|
||||||
|
var cursor uint64 = 0
|
||||||
|
var count int64 = 100
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
iter := rdb.Scan(ctx, 0, match, 1000).Iterator()
|
// 循环遍历获取匹配的键
|
||||||
if err := iter.Err(); err != nil {
|
for {
|
||||||
logger.Errorf("Failed to scan keys: %v", err)
|
// 使用 SCAN 命令获取匹配的键
|
||||||
return keys, err
|
batchKeys, nextCursor, err := rdb.Scan(ctx, cursor, pattern, count).Result()
|
||||||
}
|
if err != nil {
|
||||||
for iter.Next(ctx) {
|
logger.Errorf("failed to scan keys: %v", err)
|
||||||
keys = append(keys, iter.Val())
|
return keys, err
|
||||||
|
}
|
||||||
|
cursor = nextCursor
|
||||||
|
keys = append(keys, batchKeys...)
|
||||||
|
// 当 cursor 为 0,表示遍历完成
|
||||||
|
if cursor == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return keys, nil
|
return keys, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量获得缓存数据
|
// GetBatch 批量获得缓存数据
|
||||||
func GetBatch(source string, keys []string) ([]any, error) {
|
func GetBatch(source string, keys []string) ([]any, error) {
|
||||||
|
result := make([]any, 0)
|
||||||
if len(keys) == 0 {
|
if len(keys) == 0 {
|
||||||
return []any{}, fmt.Errorf("not keys")
|
return result, fmt.Errorf("not keys")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 数据源
|
// 数据源
|
||||||
rdb := DefaultRDB()
|
rdb := RDB(source)
|
||||||
if source != "" {
|
if rdb == nil {
|
||||||
rdb = RDB(source)
|
return result, fmt.Errorf("redis not client")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取缓存数据
|
// 获取缓存数据
|
||||||
result, err := rdb.MGet(context.Background(), keys...).Result()
|
v, err := rdb.MGet(context.Background(), keys...).Result()
|
||||||
if err != nil {
|
if err != nil || errors.Is(err, redis.Nil) {
|
||||||
logger.Errorf("Failed to get batch data: %v", err)
|
logger.Errorf("failed to get batch data: %v", err)
|
||||||
return []any{}, err
|
return result, err
|
||||||
}
|
}
|
||||||
return result, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获得缓存数据
|
// Get 获得缓存数据
|
||||||
func Get(source, key string) (string, error) {
|
func Get(source, key string) (string, error) {
|
||||||
// 数据源
|
// 数据源
|
||||||
rdb := DefaultRDB()
|
rdb := RDB(source)
|
||||||
if source != "" {
|
if rdb == nil {
|
||||||
rdb = RDB(source)
|
return "", fmt.Errorf("redis not client")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
value, err := rdb.Get(ctx, key).Result()
|
v, err := rdb.Get(ctx, key).Result()
|
||||||
if err == redis.Nil || err != nil {
|
if errors.Is(err, redis.Nil) {
|
||||||
|
return "", fmt.Errorf("no keys")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return value, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断是否存在
|
// Has 判断是否存在
|
||||||
func Has(source string, keys ...string) (bool, error) {
|
func Has(source string, keys ...string) (int64, error) {
|
||||||
// 数据源
|
// 数据源
|
||||||
rdb := DefaultRDB()
|
rdb := RDB(source)
|
||||||
if source != "" {
|
if rdb == nil {
|
||||||
rdb = RDB(source)
|
return 0, fmt.Errorf("redis not client")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
exists, err := rdb.Exists(ctx, keys...).Result()
|
exists, err := rdb.Exists(ctx, keys...).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return exists >= 1, nil
|
return exists, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置缓存数据
|
// Set 设置缓存数据
|
||||||
func Set(source, key string, value any) (bool, error) {
|
func Set(source, key string, value any) error {
|
||||||
// 数据源
|
// 数据源
|
||||||
rdb := DefaultRDB()
|
rdb := RDB(source)
|
||||||
if source != "" {
|
if rdb == nil {
|
||||||
rdb = RDB(source)
|
return fmt.Errorf("redis not client")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := rdb.Set(ctx, key, value, 0).Err()
|
err := rdb.Set(ctx, key, value, 0).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("redis Set err %v", err)
|
logger.Errorf("redis Set err %v", err)
|
||||||
return false, err
|
return err
|
||||||
}
|
}
|
||||||
return true, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置缓存数据与过期时间
|
// SetByExpire 设置缓存数据与过期时间
|
||||||
func SetByExpire(source, key string, value any, expiration time.Duration) (bool, error) {
|
func SetByExpire(source, key string, value any, expiration time.Duration) error {
|
||||||
// 数据源
|
// 数据源
|
||||||
rdb := DefaultRDB()
|
rdb := RDB(source)
|
||||||
if source != "" {
|
if rdb == nil {
|
||||||
rdb = RDB(source)
|
return fmt.Errorf("redis not client")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := rdb.Set(ctx, key, value, expiration).Err()
|
err := rdb.Set(ctx, key, value, expiration).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("redis SetByExpire err %v", err)
|
logger.Errorf("redis SetByExpire err %v", err)
|
||||||
return false, err
|
return err
|
||||||
}
|
}
|
||||||
return true, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除单个
|
// Del 删除单个
|
||||||
func Del(source string, key string) (bool, error) {
|
func Del(source string, key string) error {
|
||||||
// 数据源
|
// 数据源
|
||||||
rdb := DefaultRDB()
|
rdb := RDB(source)
|
||||||
if source != "" {
|
if rdb == nil {
|
||||||
rdb = RDB(source)
|
return fmt.Errorf("redis not client")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := rdb.Del(ctx, key).Err()
|
if err := rdb.Del(ctx, key).Err(); err != nil {
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("redis Del err %v", err)
|
logger.Errorf("redis Del err %v", err)
|
||||||
return false, err
|
return err
|
||||||
}
|
}
|
||||||
return true, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除多个
|
// DelKeys 删除多个
|
||||||
func DelKeys(source string, keys []string) (bool, error) {
|
func DelKeys(source string, keys []string) error {
|
||||||
if len(keys) == 0 {
|
if len(keys) == 0 {
|
||||||
return false, fmt.Errorf("no keys")
|
return fmt.Errorf("no keys")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 数据源
|
// 数据源
|
||||||
rdb := DefaultRDB()
|
rdb := RDB(source)
|
||||||
if source != "" {
|
if rdb == nil {
|
||||||
rdb = RDB(source)
|
return fmt.Errorf("redis not client")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := rdb.Del(ctx, keys...).Err()
|
if err := rdb.Del(ctx, keys...).Err(); err != nil {
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("redis DelKeys err %v", err)
|
logger.Errorf("redis DelKeys err %v", err)
|
||||||
return false, err
|
return err
|
||||||
}
|
}
|
||||||
return true, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 限流查询并记录
|
// RateLimit 限流查询并记录
|
||||||
func RateLimit(source, limitKey string, time, count int64) (int64, error) {
|
func RateLimit(source, limitKey string, time, count int64) (int64, error) {
|
||||||
// 数据源
|
// 数据源
|
||||||
rdb := DefaultRDB()
|
rdb := RDB(source)
|
||||||
if source != "" {
|
if rdb == nil {
|
||||||
rdb = RDB(source)
|
return 0, fmt.Errorf("redis not client")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
result, err := rateLimitCommand.Run(ctx, rdb, []string{limitKey}, time, count).Result()
|
result, err := rateLimitCommand.Run(ctx, rdb, []string{limitKey}, time, count).Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("redis RateLimit err %v", err)
|
logger.Errorf("redis lua script err %v", err)
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
return result.(int64), err
|
return result.(int64), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 声明定义限流脚本命令
|
||||||
|
var rateLimitCommand = redis.NewScript(`
|
||||||
|
local key = KEYS[1]
|
||||||
|
local time = tonumber(ARGV[1])
|
||||||
|
local count = tonumber(ARGV[2])
|
||||||
|
local current = redis.call('get', key);
|
||||||
|
if current and tonumber(current) >= count then
|
||||||
|
return tonumber(current);
|
||||||
|
end
|
||||||
|
current = redis.call('incr', key)
|
||||||
|
if tonumber(current) == 1 then
|
||||||
|
redis.call('expire', key, time)
|
||||||
|
end
|
||||||
|
return tonumber(current);`)
|
||||||
@@ -1,127 +1,22 @@
|
|||||||
package datasource
|
package datasource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"time"
|
|
||||||
|
|
||||||
"be.ems/src/framework/config"
|
"be.ems/src/framework/database/db"
|
||||||
"be.ems/src/framework/logger"
|
|
||||||
"be.ems/src/framework/utils/parse"
|
"be.ems/src/framework/utils/parse"
|
||||||
|
|
||||||
"gorm.io/driver/mysql"
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
gormLog "gorm.io/gorm/logger"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// 数据库连接实例
|
|
||||||
var dbMap = make(map[string]*gorm.DB)
|
|
||||||
|
|
||||||
type dialectInfo struct {
|
|
||||||
dialector gorm.Dialector
|
|
||||||
logging bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// 载入数据库连接
|
|
||||||
func loadDialect() map[string]dialectInfo {
|
|
||||||
dialects := make(map[string]dialectInfo, 0)
|
|
||||||
|
|
||||||
// 读取数据源配置
|
|
||||||
datasource := config.Get("gorm.datasource").(map[string]any)
|
|
||||||
for key, value := range datasource {
|
|
||||||
item := value.(map[string]any)
|
|
||||||
// 数据库类型对应的数据库连接
|
|
||||||
switch item["type"] {
|
|
||||||
case "mysql":
|
|
||||||
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
|
||||||
item["username"],
|
|
||||||
item["password"],
|
|
||||||
item["host"],
|
|
||||||
item["port"],
|
|
||||||
item["database"],
|
|
||||||
)
|
|
||||||
dialects[key] = dialectInfo{
|
|
||||||
dialector: mysql.Open(dsn),
|
|
||||||
logging: item["logging"].(bool),
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
logger.Fatalf("%s: %v\n Not Load DB Config Type", key, item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return dialects
|
|
||||||
}
|
|
||||||
|
|
||||||
// 载入连接日志配置
|
|
||||||
func loadLogger() gormLog.Interface {
|
|
||||||
newLogger := gormLog.New(
|
|
||||||
log.New(os.Stdout, "[GORM] ", log.LstdFlags), // 将日志输出到控制台
|
|
||||||
gormLog.Config{
|
|
||||||
SlowThreshold: time.Second, // Slow SQL 阈值
|
|
||||||
LogLevel: gormLog.Info, // 日志级别 Silent不输出任何日志
|
|
||||||
ParameterizedQueries: false, // 参数化查询SQL 用实际值带入?的执行语句
|
|
||||||
Colorful: false, // 彩色日志输出
|
|
||||||
},
|
|
||||||
)
|
|
||||||
return newLogger
|
|
||||||
}
|
|
||||||
|
|
||||||
// 连接数据库实例
|
|
||||||
func Connect() {
|
|
||||||
// 遍历进行连接数据库实例
|
|
||||||
for key, info := range loadDialect() {
|
|
||||||
opts := &gorm.Config{}
|
|
||||||
// 是否需要日志输出
|
|
||||||
if info.logging {
|
|
||||||
opts.Logger = loadLogger()
|
|
||||||
}
|
|
||||||
// 创建连接
|
|
||||||
db, err := gorm.Open(info.dialector, opts)
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatalf("failed error db connect: %s", err)
|
|
||||||
}
|
|
||||||
// 获取底层 SQL 数据库连接
|
|
||||||
sqlDB, err := db.DB()
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatalf("failed error underlying SQL database: %v", err)
|
|
||||||
}
|
|
||||||
// 测试数据库连接
|
|
||||||
err = sqlDB.Ping()
|
|
||||||
if err != nil {
|
|
||||||
logger.Fatalf("failed error ping database: %v", err)
|
|
||||||
}
|
|
||||||
logger.Infof("database %s connection is successful.", key)
|
|
||||||
dbMap[key] = db
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭数据库实例
|
|
||||||
func Close() {
|
|
||||||
for _, db := range dbMap {
|
|
||||||
sqlDB, err := db.DB()
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err := sqlDB.Close(); err != nil {
|
|
||||||
logger.Errorf("fatal error db close: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取默认数据源
|
// 获取默认数据源
|
||||||
func DefaultDB() *gorm.DB {
|
func DefaultDB() *gorm.DB {
|
||||||
source := config.Get("gorm.defaultDataSourceName").(string)
|
return db.DB("")
|
||||||
return dbMap[source]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取数据源
|
// 获取数据源
|
||||||
func DB(source string) *gorm.DB {
|
func DB(source string) *gorm.DB {
|
||||||
if source == "" {
|
return db.DB(source)
|
||||||
source = config.Get("gorm.defaultDataSourceName").(string)
|
|
||||||
}
|
|
||||||
return dbMap[source]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RawDB 原生查询语句
|
// RawDB 原生查询语句
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"be.ems/src/framework/constants/cachekey"
|
"be.ems/src/framework/constants/cachekey"
|
||||||
|
"be.ems/src/framework/database/redis"
|
||||||
"be.ems/src/framework/i18n"
|
"be.ems/src/framework/i18n"
|
||||||
"be.ems/src/framework/redis"
|
|
||||||
"be.ems/src/framework/utils/ctx"
|
"be.ems/src/framework/utils/ctx"
|
||||||
"be.ems/src/framework/utils/ip2region"
|
"be.ems/src/framework/utils/ip2region"
|
||||||
"be.ems/src/framework/vo/result"
|
"be.ems/src/framework/vo/result"
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"be.ems/src/framework/constants/cachekey"
|
"be.ems/src/framework/constants/cachekey"
|
||||||
|
"be.ems/src/framework/database/redis"
|
||||||
"be.ems/src/framework/logger"
|
"be.ems/src/framework/logger"
|
||||||
"be.ems/src/framework/redis"
|
|
||||||
"be.ems/src/framework/utils/ctx"
|
"be.ems/src/framework/utils/ctx"
|
||||||
"be.ems/src/framework/utils/ip2region"
|
"be.ems/src/framework/utils/ip2region"
|
||||||
"be.ems/src/framework/vo/result"
|
"be.ems/src/framework/vo/result"
|
||||||
|
|||||||
160
src/framework/reqctx/auth.go
Normal file
160
src/framework/reqctx/auth.go
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
package reqctx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
"be.ems/src/framework/config"
|
||||||
|
"be.ems/src/framework/constants"
|
||||||
|
"be.ems/src/framework/vo"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LoginUser 登录用户信息
|
||||||
|
func LoginUser(c *gin.Context) (vo.LoginUser, error) {
|
||||||
|
value, exists := c.Get(constants.CTX_LOGIN_USER)
|
||||||
|
if exists && value != nil {
|
||||||
|
return value.(vo.LoginUser), nil
|
||||||
|
}
|
||||||
|
return vo.LoginUser{}, fmt.Errorf("invalid login user information")
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoginUserToUserID 登录用户信息-用户ID
|
||||||
|
func LoginUserToUserID(c *gin.Context) string {
|
||||||
|
info, err := LoginUser(c)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return info.UserID
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoginUserToUserName 登录用户信息-用户名称
|
||||||
|
func LoginUserToUserName(c *gin.Context) string {
|
||||||
|
info, err := LoginUser(c)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return info.User.UserName
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoginUserByContainRoles 登录用户信息-包含角色KEY
|
||||||
|
func LoginUserByContainRoles(c *gin.Context, target string) bool {
|
||||||
|
info, err := LoginUser(c)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if config.IsAdmin(info.UserID) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
roles := info.User.Roles
|
||||||
|
for _, item := range roles {
|
||||||
|
if item.RoleKey == target {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoginUserByContainPerms 登录用户信息-包含权限标识
|
||||||
|
func LoginUserByContainPerms(c *gin.Context, target string) bool {
|
||||||
|
loginUser, err := LoginUser(c)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if config.IsAdmin(loginUser.UserID) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
perms := loginUser.Permissions
|
||||||
|
for _, str := range perms {
|
||||||
|
if str == target {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoginUserToDataScopeSQL 登录用户信息-角色数据范围过滤SQL字符串
|
||||||
|
func LoginUserToDataScopeSQL(c *gin.Context, deptAlias string, userAlias string) string {
|
||||||
|
dataScopeSQL := ""
|
||||||
|
// 登录用户信息
|
||||||
|
info, err := LoginUser(c)
|
||||||
|
if err != nil {
|
||||||
|
return dataScopeSQL
|
||||||
|
}
|
||||||
|
userInfo := info.User
|
||||||
|
|
||||||
|
// 如果是系统管理员,则不过滤数据
|
||||||
|
if config.IsAdmin(userInfo.UserID) {
|
||||||
|
return dataScopeSQL
|
||||||
|
}
|
||||||
|
// 无用户角色
|
||||||
|
if len(userInfo.Roles) <= 0 {
|
||||||
|
return dataScopeSQL
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录角色权限范围定义添加过, 非自定数据权限不需要重复拼接SQL
|
||||||
|
var scopeKeys []string
|
||||||
|
var conditions []string
|
||||||
|
for _, role := range userInfo.Roles {
|
||||||
|
dataScope := role.DataScope
|
||||||
|
|
||||||
|
if constants.ROLE_SCOPE_ALL == dataScope {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if constants.ROLE_SCOPE_CUSTOM != dataScope {
|
||||||
|
hasKey := false
|
||||||
|
for _, key := range scopeKeys {
|
||||||
|
if key == dataScope {
|
||||||
|
hasKey = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hasKey {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if constants.ROLE_SCOPE_CUSTOM == dataScope {
|
||||||
|
sql := fmt.Sprintf(`%s.dept_id IN
|
||||||
|
( SELECT dept_id FROM sys_role_dept WHERE role_id = %s )
|
||||||
|
AND %s.dept_id NOT IN
|
||||||
|
(
|
||||||
|
SELECT d.parent_id FROM sys_dept d
|
||||||
|
INNER JOIN sys_role_dept rd ON rd.dept_id = d.dept_id
|
||||||
|
AND rd.role_id = %s
|
||||||
|
)`, deptAlias, role.RoleID, deptAlias, role.RoleID)
|
||||||
|
conditions = append(conditions, sql)
|
||||||
|
}
|
||||||
|
|
||||||
|
if constants.ROLE_SCOPE_DEPT == dataScope {
|
||||||
|
sql := fmt.Sprintf("%s.dept_id = %s", deptAlias, userInfo.DeptID)
|
||||||
|
conditions = append(conditions, sql)
|
||||||
|
}
|
||||||
|
|
||||||
|
if constants.ROLE_SCOPE_DEPT_CHILD == dataScope {
|
||||||
|
sql := fmt.Sprintf("%s.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = %s OR find_in_set(%s, ancestors ) )", deptAlias, userInfo.DeptID, userInfo.DeptID)
|
||||||
|
conditions = append(conditions, sql)
|
||||||
|
}
|
||||||
|
|
||||||
|
if constants.ROLE_SCOPE_SELF == dataScope {
|
||||||
|
if userAlias == "" {
|
||||||
|
sql := fmt.Sprintf("%s.dept_id = %s", deptAlias, userInfo.DeptID)
|
||||||
|
conditions = append(conditions, sql)
|
||||||
|
} else {
|
||||||
|
sql := fmt.Sprintf("%s.user_id = %s", userAlias, userInfo.UserID)
|
||||||
|
conditions = append(conditions, sql)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录角色范围
|
||||||
|
scopeKeys = append(scopeKeys, dataScope)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件语句
|
||||||
|
if len(conditions) > 0 {
|
||||||
|
dataScopeSQL = fmt.Sprintf(" ( %s ) ", strings.Join(conditions, " OR "))
|
||||||
|
}
|
||||||
|
return dataScopeSQL
|
||||||
|
}
|
||||||
106
src/framework/reqctx/context.go
Normal file
106
src/framework/reqctx/context.go
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
package reqctx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"golang.org/x/text/language"
|
||||||
|
|
||||||
|
"be.ems/src/framework/constants"
|
||||||
|
)
|
||||||
|
|
||||||
|
// QueryMap Query参数转换Map
|
||||||
|
func QueryMap(c *gin.Context) map[string]string {
|
||||||
|
queryValues := c.Request.URL.Query()
|
||||||
|
queryParams := make(map[string]string, len(queryValues))
|
||||||
|
for key, values := range queryValues {
|
||||||
|
queryParams[key] = values[0]
|
||||||
|
}
|
||||||
|
return queryParams
|
||||||
|
}
|
||||||
|
|
||||||
|
// BodyJSONMap JSON参数转换Map
|
||||||
|
func BodyJSONMap(c *gin.Context) map[string]any {
|
||||||
|
params := make(map[string]any, 0)
|
||||||
|
c.ShouldBindBodyWithJSON(¶ms)
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestParamsMap 请求参数转换Map
|
||||||
|
func RequestParamsMap(c *gin.Context) map[string]any {
|
||||||
|
params := make(map[string]any, 0)
|
||||||
|
// json
|
||||||
|
if strings.HasPrefix(c.ContentType(), "application/json") {
|
||||||
|
c.ShouldBindBodyWithJSON(¶ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表单
|
||||||
|
formParams := c.Request.PostForm
|
||||||
|
for key, value := range formParams {
|
||||||
|
if _, ok := params[key]; !ok {
|
||||||
|
params[key] = value[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询
|
||||||
|
queryParams := c.Request.URL.Query()
|
||||||
|
for key, value := range queryParams {
|
||||||
|
if _, ok := params[key]; !ok {
|
||||||
|
params[key] = value[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authorization 解析请求头
|
||||||
|
func Authorization(c *gin.Context) string {
|
||||||
|
// Query请求查询
|
||||||
|
if authQuery, ok := c.GetQuery(constants.ACCESS_TOKEN); ok && authQuery != "" {
|
||||||
|
return authQuery
|
||||||
|
}
|
||||||
|
// Header请求头
|
||||||
|
if authHeader := c.GetHeader(constants.ACCESS_TOKEN); authHeader != "" {
|
||||||
|
return authHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query请求查询
|
||||||
|
if authQuery, ok := c.GetQuery(constants.ACCESS_TOKEN_QUERY); ok && authQuery != "" {
|
||||||
|
return authQuery
|
||||||
|
}
|
||||||
|
// Header请求头
|
||||||
|
authHeader := c.GetHeader(constants.HEADER_KEY)
|
||||||
|
if authHeader == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
// 拆分 Authorization 请求头,提取 JWT 令牌部分
|
||||||
|
arr := strings.SplitN(authHeader, constants.HEADER_PREFIX, 2)
|
||||||
|
if len(arr) < 2 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return arr[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcceptLanguage 解析客户端接收语言 zh:中文 en: 英文
|
||||||
|
func AcceptLanguage(c *gin.Context) string {
|
||||||
|
preferredLanguage := language.English
|
||||||
|
|
||||||
|
// Query请求查询
|
||||||
|
if v, ok := c.GetQuery("language"); ok && v != "" {
|
||||||
|
tags, _, _ := language.ParseAcceptLanguage(v)
|
||||||
|
if len(tags) > 0 {
|
||||||
|
preferredLanguage = tags[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Header请求头
|
||||||
|
if v := c.GetHeader("Accept-Language"); v != "" {
|
||||||
|
tags, _, _ := language.ParseAcceptLanguage(v)
|
||||||
|
if len(tags) > 0 {
|
||||||
|
preferredLanguage = tags[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只取前缀
|
||||||
|
lang := preferredLanguage.String()
|
||||||
|
arr := strings.Split(lang, "-")
|
||||||
|
return arr[0]
|
||||||
|
}
|
||||||
35
src/framework/reqctx/param.go
Normal file
35
src/framework/reqctx/param.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package reqctx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
"be.ems/src/framework/utils/ip2region"
|
||||||
|
"be.ems/src/framework/utils/ua"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IPAddrLocation 解析ip地址
|
||||||
|
func IPAddrLocation(c *gin.Context) (string, string) {
|
||||||
|
ip := ip2region.ClientIP(c.ClientIP())
|
||||||
|
location := "-" //ip2region.RealAddressByIp(ip)
|
||||||
|
return ip, location
|
||||||
|
}
|
||||||
|
|
||||||
|
// UaOsBrowser 解析请求用户代理信息
|
||||||
|
func UaOsBrowser(c *gin.Context) (string, string) {
|
||||||
|
userAgent := c.GetHeader("user-agent")
|
||||||
|
uaInfo := ua.Info(userAgent)
|
||||||
|
|
||||||
|
browser := "-"
|
||||||
|
if bName, bVersion := uaInfo.Browser(); bName != "" {
|
||||||
|
browser = bName
|
||||||
|
if bVersion != "" {
|
||||||
|
browser = bName + " " + bVersion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
os := "-"
|
||||||
|
if bos := uaInfo.OS(); bos != "" {
|
||||||
|
os = bos
|
||||||
|
}
|
||||||
|
return os, browser
|
||||||
|
}
|
||||||
74
src/framework/resp/api.go
Normal file
74
src/framework/resp/api.go
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package resp
|
||||||
|
|
||||||
|
const (
|
||||||
|
// CODE_ERROR 响应-code错误失败
|
||||||
|
CODE_ERROR = 0
|
||||||
|
// MSG_ERROR 响应-msg错误失败
|
||||||
|
MSG_ERROR = "error"
|
||||||
|
|
||||||
|
// CODE_SUCCESS 响应-msg正常成功
|
||||||
|
CODE_SUCCESS = 1
|
||||||
|
// MSG_SUCCCESS 响应-code正常成功
|
||||||
|
MSG_SUCCCESS = "success"
|
||||||
|
|
||||||
|
// 响应-code加密数据
|
||||||
|
CODE_ENCRYPT = 2
|
||||||
|
// 响应-msg加密数据
|
||||||
|
MSG_ENCRYPT = "encrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Resp 响应结构体
|
||||||
|
type Resp struct {
|
||||||
|
Code int `json:"code"` // 响应状态码
|
||||||
|
Msg string `json:"msg"` // 响应信息
|
||||||
|
Data any `json:"data,omitempty"` // 响应数据
|
||||||
|
}
|
||||||
|
|
||||||
|
// CodeMsg 响应结果
|
||||||
|
func CodeMsg(code int, msg string) Resp {
|
||||||
|
return Resp{Code: code, Msg: msg}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ok 响应成功结果
|
||||||
|
func Ok(v map[string]any) map[string]any {
|
||||||
|
args := make(map[string]any)
|
||||||
|
args["code"] = CODE_SUCCESS
|
||||||
|
args["msg"] = MSG_SUCCCESS
|
||||||
|
// v合并到args
|
||||||
|
for key, value := range v {
|
||||||
|
args[key] = value
|
||||||
|
}
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
// OkMsg 响应成功结果信息
|
||||||
|
func OkMsg(msg string) Resp {
|
||||||
|
return Resp{Code: CODE_SUCCESS, Msg: msg}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OkData 响应成功结果数据
|
||||||
|
func OkData(data any) Resp {
|
||||||
|
return Resp{Code: CODE_SUCCESS, Msg: MSG_SUCCCESS, Data: data}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err 响应失败结果 map[string]any{}
|
||||||
|
func Err(v map[string]any) map[string]any {
|
||||||
|
args := make(map[string]any)
|
||||||
|
args["code"] = CODE_ERROR
|
||||||
|
args["msg"] = MSG_ERROR
|
||||||
|
// v合并到args
|
||||||
|
for key, value := range v {
|
||||||
|
args[key] = value
|
||||||
|
}
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrMsg 响应失败结果信息
|
||||||
|
func ErrMsg(msg string) Resp {
|
||||||
|
return Resp{Code: CODE_ERROR, Msg: msg}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrData 响应失败结果数据
|
||||||
|
func ErrData(data any) Resp {
|
||||||
|
return Resp{Code: CODE_ERROR, Msg: MSG_ERROR, Data: data}
|
||||||
|
}
|
||||||
23
src/framework/resp/error.go
Normal file
23
src/framework/resp/error.go
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package resp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FormatBindError 格式化Gin ShouldBindWith绑定错误
|
||||||
|
//
|
||||||
|
// binding:"required" 验证失败返回: field=id type=string tag=required value=
|
||||||
|
func FormatBindError(err error) string {
|
||||||
|
if errs, ok := err.(validator.ValidationErrors); ok {
|
||||||
|
var errMsgs []string
|
||||||
|
for _, e := range errs {
|
||||||
|
str := fmt.Sprintf("[field=%s, type=%s, tag=%s, param=%s, value=%v]", e.Field(), e.Type().Name(), e.Tag(), e.Param(), e.Value())
|
||||||
|
errMsgs = append(errMsgs, str)
|
||||||
|
}
|
||||||
|
return strings.Join(errMsgs, ", ")
|
||||||
|
}
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
@@ -91,31 +91,16 @@ func ConvertToCamelCase(str string) string {
|
|||||||
return strings.Join(words, "")
|
return strings.Join(words, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bit 比特位为单位
|
// Bit 比特位为单位 1023.00 B --> 1.00 KB
|
||||||
func Bit(bit float64) string {
|
func Bit(bit float64) string {
|
||||||
var GB, MB, KB string
|
units := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
|
||||||
|
for i := 0; i < len(units); i++ {
|
||||||
if bit > float64(1<<30) {
|
if bit < 1024 || i == len(units)-1 {
|
||||||
GB = fmt.Sprintf("%0.2f", bit/(1<<30))
|
return fmt.Sprintf("%.2f %s", bit, units[i])
|
||||||
}
|
}
|
||||||
|
bit /= 1024
|
||||||
if bit > float64(1<<20) && bit < (1<<30) {
|
|
||||||
MB = fmt.Sprintf("%.2f", bit/(1<<20))
|
|
||||||
}
|
|
||||||
|
|
||||||
if bit > float64(1<<10) && bit < (1<<20) {
|
|
||||||
KB = fmt.Sprintf("%.2f", bit/(1<<10))
|
|
||||||
}
|
|
||||||
|
|
||||||
if GB != "" {
|
|
||||||
return GB + "GB"
|
|
||||||
} else if MB != "" {
|
|
||||||
return MB + "MB"
|
|
||||||
} else if KB != "" {
|
|
||||||
return KB + "KB"
|
|
||||||
} else {
|
|
||||||
return fmt.Sprintf("%vB", bit)
|
|
||||||
}
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// CronExpression 解析 Cron 表达式,返回下一次执行的时间戳(毫秒)
|
// CronExpression 解析 Cron 表达式,返回下一次执行的时间戳(毫秒)
|
||||||
@@ -146,11 +131,11 @@ func SafeContent(value string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RemoveDuplicates 数组内字符串去重
|
// RemoveDuplicates 数组内字符串去重
|
||||||
func RemoveDuplicates(ids []string) []string {
|
func RemoveDuplicates(arr []string) []string {
|
||||||
uniqueIDs := make(map[string]bool)
|
uniqueIDs := make(map[string]bool)
|
||||||
uniqueIDSlice := make([]string, 0)
|
uniqueIDSlice := make([]string, 0)
|
||||||
|
|
||||||
for _, id := range ids {
|
for _, id := range arr {
|
||||||
_, ok := uniqueIDs[id]
|
_, ok := uniqueIDs[id]
|
||||||
if !ok && id != "" {
|
if !ok && id != "" {
|
||||||
uniqueIDs[id] = true
|
uniqueIDs[id] = true
|
||||||
@@ -161,6 +146,29 @@ func RemoveDuplicates(ids []string) []string {
|
|||||||
return uniqueIDSlice
|
return uniqueIDSlice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoveDuplicatesToArray 数组内字符串分隔去重转为字符数组
|
||||||
|
func RemoveDuplicatesToArray(keyStr, sep string) []string {
|
||||||
|
arr := make([]string, 0)
|
||||||
|
if keyStr == "" {
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
if strings.Contains(keyStr, sep) {
|
||||||
|
// 处理字符转数组后去重
|
||||||
|
strArr := strings.Split(keyStr, sep)
|
||||||
|
uniqueKeys := make(map[string]bool)
|
||||||
|
for _, str := range strArr {
|
||||||
|
_, ok := uniqueKeys[str]
|
||||||
|
if !ok && str != "" {
|
||||||
|
uniqueKeys[str] = true
|
||||||
|
arr = append(arr, str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
arr = append(arr, keyStr)
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
// Color 解析颜色 #fafafa
|
// Color 解析颜色 #fafafa
|
||||||
func Color(colorStr string) *color.RGBA {
|
func Color(colorStr string) *color.RGBA {
|
||||||
// 去除 # 号
|
// 去除 # 号
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
"be.ems/src/framework/config"
|
"be.ems/src/framework/config"
|
||||||
cachekeyConstants "be.ems/src/framework/constants/cachekey"
|
cachekeyConstants "be.ems/src/framework/constants/cachekey"
|
||||||
tokenConstants "be.ems/src/framework/constants/token"
|
tokenConstants "be.ems/src/framework/constants/token"
|
||||||
|
redisCahe "be.ems/src/framework/database/redis"
|
||||||
"be.ems/src/framework/logger"
|
"be.ems/src/framework/logger"
|
||||||
redisCahe "be.ems/src/framework/redis"
|
|
||||||
"be.ems/src/framework/utils/generate"
|
"be.ems/src/framework/utils/generate"
|
||||||
"be.ems/src/framework/utils/machine"
|
"be.ems/src/framework/utils/machine"
|
||||||
"be.ems/src/framework/vo"
|
"be.ems/src/framework/vo"
|
||||||
@@ -28,7 +28,7 @@ func Remove(tokenStr string) string {
|
|||||||
uuid := claims[tokenConstants.JWT_UUID].(string)
|
uuid := claims[tokenConstants.JWT_UUID].(string)
|
||||||
tokenKey := cachekeyConstants.LOGIN_TOKEN_KEY + uuid
|
tokenKey := cachekeyConstants.LOGIN_TOKEN_KEY + uuid
|
||||||
hasKey, _ := redisCahe.Has("", tokenKey)
|
hasKey, _ := redisCahe.Has("", tokenKey)
|
||||||
if hasKey {
|
if hasKey > 0 {
|
||||||
redisCahe.Del("", tokenKey)
|
redisCahe.Del("", tokenKey)
|
||||||
}
|
}
|
||||||
return claims[tokenConstants.JWT_NAME].(string)
|
return claims[tokenConstants.JWT_NAME].(string)
|
||||||
@@ -141,7 +141,7 @@ func LoginUser(claims jwt.MapClaims) vo.LoginUser {
|
|||||||
tokenKey := cachekeyConstants.LOGIN_TOKEN_KEY + uuid
|
tokenKey := cachekeyConstants.LOGIN_TOKEN_KEY + uuid
|
||||||
hasKey, _ := redisCahe.Has("", tokenKey)
|
hasKey, _ := redisCahe.Has("", tokenKey)
|
||||||
var loginUser vo.LoginUser
|
var loginUser vo.LoginUser
|
||||||
if hasKey {
|
if hasKey > 0 {
|
||||||
loginUserStr, _ := redisCahe.Get("", tokenKey)
|
loginUserStr, _ := redisCahe.Get("", tokenKey)
|
||||||
if loginUserStr == "" {
|
if loginUserStr == "" {
|
||||||
return loginUser
|
return loginUser
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"be.ems/src/framework/config"
|
"be.ems/src/framework/config"
|
||||||
"be.ems/src/framework/constants/cachekey"
|
"be.ems/src/framework/constants/cachekey"
|
||||||
"be.ems/src/framework/constants/captcha"
|
"be.ems/src/framework/constants/captcha"
|
||||||
|
"be.ems/src/framework/database/redis"
|
||||||
"be.ems/src/framework/logger"
|
"be.ems/src/framework/logger"
|
||||||
"be.ems/src/framework/redis"
|
|
||||||
"be.ems/src/framework/utils/parse"
|
"be.ems/src/framework/utils/parse"
|
||||||
"be.ems/src/framework/vo/result"
|
"be.ems/src/framework/vo/result"
|
||||||
systemService "be.ems/src/modules/system/service"
|
systemService "be.ems/src/modules/system/service"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
adminConstants "be.ems/src/framework/constants/admin"
|
adminConstants "be.ems/src/framework/constants/admin"
|
||||||
"be.ems/src/framework/constants/cachekey"
|
"be.ems/src/framework/constants/cachekey"
|
||||||
"be.ems/src/framework/constants/common"
|
"be.ems/src/framework/constants/common"
|
||||||
"be.ems/src/framework/redis"
|
"be.ems/src/framework/database/redis"
|
||||||
"be.ems/src/framework/utils/crypto"
|
"be.ems/src/framework/utils/crypto"
|
||||||
"be.ems/src/framework/utils/parse"
|
"be.ems/src/framework/utils/parse"
|
||||||
"be.ems/src/framework/vo"
|
"be.ems/src/framework/vo"
|
||||||
@@ -131,9 +131,9 @@ func (s *Account) UpdateLoginDateAndIP(loginUser *vo.LoginUser) bool {
|
|||||||
func (s *Account) ClearLoginRecordCache(username string) bool {
|
func (s *Account) ClearLoginRecordCache(username string) bool {
|
||||||
cacheKey := cachekey.PWD_ERR_CNT_KEY + username
|
cacheKey := cachekey.PWD_ERR_CNT_KEY + username
|
||||||
hasKey, _ := redis.Has("", cacheKey)
|
hasKey, _ := redis.Has("", cacheKey)
|
||||||
if hasKey {
|
if hasKey > 0 {
|
||||||
delOk, _ := redis.Del("", cacheKey)
|
err := redis.Del("", cacheKey)
|
||||||
return delOk
|
return err == nil
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
|
|
||||||
"be.ems/src/framework/constants/cachekey"
|
"be.ems/src/framework/constants/cachekey"
|
||||||
"be.ems/src/framework/constants/common"
|
"be.ems/src/framework/constants/common"
|
||||||
"be.ems/src/framework/redis"
|
"be.ems/src/framework/database/redis"
|
||||||
"be.ems/src/framework/utils/parse"
|
"be.ems/src/framework/utils/parse"
|
||||||
systemModel "be.ems/src/modules/system/model"
|
systemModel "be.ems/src/modules/system/model"
|
||||||
systemService "be.ems/src/modules/system/service"
|
systemService "be.ems/src/modules/system/service"
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package controller
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"be.ems/src/framework/constants/cachekey"
|
"be.ems/src/framework/constants/cachekey"
|
||||||
|
"be.ems/src/framework/database/redis"
|
||||||
"be.ems/src/framework/i18n"
|
"be.ems/src/framework/i18n"
|
||||||
"be.ems/src/framework/redis"
|
|
||||||
"be.ems/src/framework/utils/ctx"
|
"be.ems/src/framework/utils/ctx"
|
||||||
"be.ems/src/framework/vo/result"
|
"be.ems/src/framework/vo/result"
|
||||||
"be.ems/src/modules/monitor/model"
|
"be.ems/src/modules/monitor/model"
|
||||||
@@ -116,8 +116,8 @@ func (s *SysCacheController) ClearCacheName(c *gin.Context) {
|
|||||||
c.JSON(200, result.ErrMsg(err.Error()))
|
c.JSON(200, result.ErrMsg(err.Error()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ok, _ := redis.DelKeys("", cacheKeys)
|
err = redis.DelKeys("", cacheKeys)
|
||||||
if ok {
|
if err == nil {
|
||||||
c.JSON(200, result.Ok(nil))
|
c.JSON(200, result.Ok(nil))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -136,8 +136,8 @@ func (s *SysCacheController) ClearCacheKey(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ok, _ := redis.Del("", cacheName+":"+cacheKey)
|
err := redis.Del("", cacheName+":"+cacheKey)
|
||||||
if ok {
|
if err == nil {
|
||||||
c.JSON(200, result.Ok(nil))
|
c.JSON(200, result.Ok(nil))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"be.ems/src/framework/constants/cachekey"
|
"be.ems/src/framework/constants/cachekey"
|
||||||
|
"be.ems/src/framework/database/redis"
|
||||||
"be.ems/src/framework/i18n"
|
"be.ems/src/framework/i18n"
|
||||||
"be.ems/src/framework/redis"
|
|
||||||
"be.ems/src/framework/utils/ctx"
|
"be.ems/src/framework/utils/ctx"
|
||||||
"be.ems/src/framework/vo"
|
"be.ems/src/framework/vo"
|
||||||
"be.ems/src/framework/vo/result"
|
"be.ems/src/framework/vo/result"
|
||||||
@@ -130,8 +130,8 @@ func (s *SysUserOnlineController) ForceLogout(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 删除token
|
// 删除token
|
||||||
ok, _ := redis.Del("", cachekey.LOGIN_TOKEN_KEY+tokenId)
|
err := redis.Del("", cachekey.LOGIN_TOKEN_KEY+tokenId)
|
||||||
if ok {
|
if err == nil {
|
||||||
c.JSON(200, result.Ok(nil))
|
c.JSON(200, result.Ok(nil))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"be.ems/src/framework/constants/cachekey"
|
"be.ems/src/framework/constants/cachekey"
|
||||||
"be.ems/src/framework/redis"
|
"be.ems/src/framework/database/redis"
|
||||||
"be.ems/src/framework/utils/parse"
|
"be.ems/src/framework/utils/parse"
|
||||||
"be.ems/src/modules/network_data/model"
|
"be.ems/src/modules/network_data/model"
|
||||||
"be.ems/src/modules/network_data/repository"
|
"be.ems/src/modules/network_data/repository"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"be.ems/src/framework/redis"
|
"be.ems/src/framework/database/redis"
|
||||||
"be.ems/src/modules/network_data/model"
|
"be.ems/src/modules/network_data/model"
|
||||||
"be.ems/src/modules/network_data/repository"
|
"be.ems/src/modules/network_data/repository"
|
||||||
neService "be.ems/src/modules/network_element/service"
|
neService "be.ems/src/modules/network_element/service"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"be.ems/src/framework/redis"
|
"be.ems/src/framework/database/redis"
|
||||||
"be.ems/src/modules/network_data/model"
|
"be.ems/src/modules/network_data/model"
|
||||||
"be.ems/src/modules/network_data/repository"
|
"be.ems/src/modules/network_data/repository"
|
||||||
neService "be.ems/src/modules/network_element/service"
|
neService "be.ems/src/modules/network_element/service"
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package controller
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"be.ems/src/framework/database/redis"
|
||||||
"be.ems/src/framework/i18n"
|
"be.ems/src/framework/i18n"
|
||||||
"be.ems/src/framework/redis"
|
|
||||||
"be.ems/src/framework/telnet"
|
"be.ems/src/framework/telnet"
|
||||||
"be.ems/src/framework/utils/ctx"
|
"be.ems/src/framework/utils/ctx"
|
||||||
"be.ems/src/framework/utils/parse"
|
"be.ems/src/framework/utils/parse"
|
||||||
|
|||||||
@@ -10,31 +10,10 @@ import (
|
|||||||
"be.ems/src/modules/network_element/model"
|
"be.ems/src/modules/network_element/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NeTraceInfo 网元跟踪任务信息
|
|
||||||
func NeTraceInfo(neInfo model.NeInfo, traceId string) (map[string]any, error) {
|
|
||||||
// 跟踪任务信息
|
|
||||||
neUrl := fmt.Sprintf("http://%s:%d/api/rest/traceManagement/v1/subscriptions?id=%s", neInfo.IP, neInfo.Port, traceId)
|
|
||||||
resBytes, err := fetch.Get(neUrl, nil, 30_000)
|
|
||||||
if err != nil {
|
|
||||||
logger.Warnf("NeTraceInfo Get \"%s\"", neUrl)
|
|
||||||
logger.Errorf("NeTraceInfo %s", err.Error())
|
|
||||||
return nil, fmt.Errorf("NeService Trace Info API Error")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 序列化结果
|
|
||||||
var resData map[string]any
|
|
||||||
err = json.Unmarshal(resBytes, &resData)
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("NeTraceInfo Unmarshal %s", err.Error())
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resData, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NeTraceAdd 网元跟踪任务新增
|
// NeTraceAdd 网元跟踪任务新增
|
||||||
func NeTraceAdd(neInfo model.NeInfo, data map[string]any) (map[string]any, error) {
|
func NeTraceAdd(neInfo model.NeInfo, data any) (map[string]any, error) {
|
||||||
// 跟踪任务创建
|
// 跟踪任务创建
|
||||||
neUrl := fmt.Sprintf("http://%s:%d/api/rest/traceManagement/v1/subscriptions", neInfo.IP, neInfo.Port)
|
neUrl := fmt.Sprintf("http://%s:%d/api/rest/traceManagement/v2/%s/subscriptions", neInfo.IP, neInfo.Port, neInfo.NeType)
|
||||||
resBytes, err := fetch.PostJSON(neUrl, data, nil)
|
resBytes, err := fetch.PostJSON(neUrl, data, nil)
|
||||||
var resData map[string]any
|
var resData map[string]any
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -60,48 +39,17 @@ func NeTraceAdd(neInfo model.NeInfo, data map[string]any) (map[string]any, error
|
|||||||
return resData, nil
|
return resData, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NeTraceEdit 网元跟踪任务编辑
|
|
||||||
func NeTraceEdit(neInfo model.NeInfo, data map[string]any) (map[string]any, error) {
|
|
||||||
// 网元参数配置新增(array)
|
|
||||||
neUrl := fmt.Sprintf("http://%s:%d/api/rest/traceManagement/v1/subscriptions", neInfo.IP, neInfo.Port)
|
|
||||||
resBytes, err := fetch.PutJSON(neUrl, data, nil)
|
|
||||||
var resData map[string]any
|
|
||||||
if err != nil {
|
|
||||||
errStr := err.Error()
|
|
||||||
logger.Warnf("NeTraceEdit PUT \"%s\"", neUrl)
|
|
||||||
if strings.HasPrefix(errStr, "201") || strings.HasPrefix(errStr, "204") {
|
|
||||||
return resData, nil
|
|
||||||
}
|
|
||||||
logger.Errorf("NeTraceEdit %s", errStr)
|
|
||||||
return nil, fmt.Errorf("NeService Trace Edit API Error")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 200 成功无数据时
|
|
||||||
if len(resBytes) == 0 {
|
|
||||||
return resData, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 序列化结果
|
|
||||||
err = json.Unmarshal(resBytes, &resData)
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("NeTraceEdit Unmarshal %s", err.Error())
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resData, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NeTraceDelete 网元跟踪任务删除
|
// NeTraceDelete 网元跟踪任务删除
|
||||||
func NeTraceDelete(neInfo model.NeInfo, traceId string) (map[string]any, error) {
|
func NeTraceDelete(neInfo model.NeInfo, traceId string) (map[string]any, error) {
|
||||||
// 网元参数配置删除(array)
|
neUrl := fmt.Sprintf("http://%s:%d/api/rest/traceManagement/v2/%s/subscriptions?id=%s", neInfo.IP, neInfo.Port, neInfo.NeType, traceId)
|
||||||
neUrl := fmt.Sprintf("http://%s:%d/api/rest/traceManagement/v1/subscriptions?id=%s", neInfo.IP, neInfo.Port, traceId)
|
|
||||||
resBytes, err := fetch.Delete(neUrl, nil)
|
resBytes, err := fetch.Delete(neUrl, nil)
|
||||||
var resData map[string]any
|
var resData map[string]any
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errStr := err.Error()
|
errStr := err.Error()
|
||||||
logger.Warnf("NeTraceDelete Delete \"%s\"", neUrl)
|
|
||||||
if strings.HasPrefix(errStr, "201") || strings.HasPrefix(errStr, "204") {
|
if strings.HasPrefix(errStr, "201") || strings.HasPrefix(errStr, "204") {
|
||||||
return resData, nil
|
return resData, nil
|
||||||
}
|
}
|
||||||
|
logger.Warnf("NeTraceDelete Delete \"%s\"", neUrl)
|
||||||
logger.Errorf("NeTraceDelete %s", errStr)
|
logger.Errorf("NeTraceDelete %s", errStr)
|
||||||
return nil, fmt.Errorf("NeService Trace Delete API Error")
|
return nil, fmt.Errorf("NeService Trace Delete API Error")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"be.ems/src/framework/constants/cachekey"
|
"be.ems/src/framework/constants/cachekey"
|
||||||
"be.ems/src/framework/redis"
|
"be.ems/src/framework/database/redis"
|
||||||
"be.ems/src/modules/network_element/model"
|
"be.ems/src/modules/network_element/model"
|
||||||
"be.ems/src/modules/network_element/repository"
|
"be.ems/src/modules/network_element/repository"
|
||||||
)
|
)
|
||||||
@@ -81,8 +81,8 @@ func (r *NeConfig) ClearNeCacheByNeType(neType string) bool {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
delOk, _ := redis.DelKeys("", keys)
|
err = redis.DelKeys("", keys)
|
||||||
return delOk
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectNeConfigByNeType 查询网元类型参数配置
|
// SelectNeConfigByNeType 查询网元类型参数配置
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"be.ems/src/framework/constants/cachekey"
|
"be.ems/src/framework/constants/cachekey"
|
||||||
"be.ems/src/framework/redis"
|
"be.ems/src/framework/database/redis"
|
||||||
"be.ems/src/modules/system/model"
|
"be.ems/src/modules/system/model"
|
||||||
"be.ems/src/modules/system/repository"
|
"be.ems/src/modules/system/repository"
|
||||||
)
|
)
|
||||||
@@ -154,8 +154,8 @@ func (r *SysConfigImpl) clearConfigCache(configKey string) bool {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
delOk, _ := redis.DelKeys("", keys)
|
err = redis.DelKeys("", keys)
|
||||||
return delOk
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectConfigByKey 查询配置信息BY键
|
// SelectConfigByKey 查询配置信息BY键
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
|
|
||||||
"be.ems/src/framework/constants/cachekey"
|
"be.ems/src/framework/constants/cachekey"
|
||||||
"be.ems/src/framework/constants/common"
|
"be.ems/src/framework/constants/common"
|
||||||
"be.ems/src/framework/redis"
|
"be.ems/src/framework/database/redis"
|
||||||
"be.ems/src/modules/system/model"
|
"be.ems/src/modules/system/model"
|
||||||
"be.ems/src/modules/system/repository"
|
"be.ems/src/modules/system/repository"
|
||||||
)
|
)
|
||||||
@@ -183,8 +183,8 @@ func (r *SysDictType) ClearDictCache(dictType string) bool {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
delOk, _ := redis.DelKeys("", keys)
|
err = redis.DelKeys("", keys)
|
||||||
return delOk
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DictDataCache 获取字典数据缓存数据
|
// DictDataCache 获取字典数据缓存数据
|
||||||
|
|||||||
Reference in New Issue
Block a user