Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51c3807d01 | ||
|
|
c2c42ca2b7 | ||
|
|
2a6db6ebfe | ||
|
|
30d8edbdcf | ||
|
|
177afafe12 | ||
|
|
98765b6e2a | ||
|
|
e4e0aab010 | ||
|
|
ed87b4e2a9 | ||
|
|
337eb36d25 | ||
|
|
c44e40d72d | ||
|
|
2e8ba831a1 | ||
|
|
a706c2a5a5 | ||
|
|
093826222a | ||
|
|
0d7b487afc | ||
|
|
8de17b6d9c | ||
|
|
49d217a883 | ||
|
|
4827555899 |
@@ -2,7 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/installers/helpers"
|
||||
"github.com/iwind/gosock/pkg/gosock"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -51,7 +51,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
unzip := utils.NewUnzip(zipPath, targetPath)
|
||||
unzip := helpers.NewUnzip(zipPath, targetPath)
|
||||
err := unzip.Run()
|
||||
if err != nil {
|
||||
stderr("ERROR: " + err.Error())
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package main
|
||||
|
||||
// 注意这里的依赖文件应该最小化,从而使编译后的文件最小化
|
||||
import (
|
||||
"flag"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/installers/helpers"
|
||||
"github.com/iwind/gosock/pkg/gosock"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -51,7 +52,7 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
unzip := utils.NewUnzip(zipPath, targetPath)
|
||||
unzip := helpers.NewUnzip(zipPath, targetPath)
|
||||
err := unzip.Run()
|
||||
if err != nil {
|
||||
stderr("ERROR: " + err.Error())
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "0.5.3"
|
||||
Version = "0.5.5"
|
||||
|
||||
ProductName = "Edge API"
|
||||
ProcessName = "edge-api"
|
||||
@@ -18,9 +18,9 @@ const (
|
||||
|
||||
// 其他节点版本号,用来检测是否有需要升级的节点
|
||||
|
||||
NodeVersion = "0.5.3"
|
||||
UserNodeVersion = "0.5.0"
|
||||
DNSNodeVersion = "0.2.7"
|
||||
NodeVersion = "0.5.5"
|
||||
UserNodeVersion = "0.5.5"
|
||||
DNSNodeVersion = "0.2.8"
|
||||
AuthorityNodeVersion = "0.0.2"
|
||||
MonitorNodeVersion = "0.0.4"
|
||||
ReportNodeVersion = "0.1.1"
|
||||
|
||||
@@ -13,22 +13,26 @@ type OrderMethod struct {
|
||||
Url string `field:"url"` // URL
|
||||
Secret string `field:"secret"` // 密钥
|
||||
Params dbs.JSON `field:"params"` // 参数
|
||||
ClientType string `field:"clientType"` // 客户端类型
|
||||
QrcodeTitle string `field:"qrcodeTitle"` // 二维码标题
|
||||
Order uint32 `field:"order"` // 排序
|
||||
State uint8 `field:"state"` // 状态
|
||||
}
|
||||
|
||||
type OrderMethodOperator struct {
|
||||
Id interface{} // ID
|
||||
Name interface{} // 名称
|
||||
IsOn interface{} // 是否启用
|
||||
Description interface{} // 描述
|
||||
ParentCode interface{} // 内置的父级代号
|
||||
Code interface{} // 代号
|
||||
Url interface{} // URL
|
||||
Secret interface{} // 密钥
|
||||
Params interface{} // 参数
|
||||
Order interface{} // 排序
|
||||
State interface{} // 状态
|
||||
Id any // ID
|
||||
Name any // 名称
|
||||
IsOn any // 是否启用
|
||||
Description any // 描述
|
||||
ParentCode any // 内置的父级代号
|
||||
Code any // 代号
|
||||
Url any // URL
|
||||
Secret any // 密钥
|
||||
Params any // 参数
|
||||
ClientType any // 客户端类型
|
||||
QrcodeTitle any // 二维码标题
|
||||
Order any // 排序
|
||||
State any // 状态
|
||||
}
|
||||
|
||||
func NewOrderMethodOperator() *OrderMethodOperator {
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type UserAccountDailyStatDAO dbs.DAO
|
||||
|
||||
func NewUserAccountDailyStatDAO() *UserAccountDailyStatDAO {
|
||||
return dbs.NewDAO(&UserAccountDailyStatDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeUserAccountDailyStats",
|
||||
Model: new(UserAccountDailyStat),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*UserAccountDailyStatDAO)
|
||||
}
|
||||
|
||||
var SharedUserAccountDailyStatDAO *UserAccountDailyStatDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedUserAccountDailyStatDAO = NewUserAccountDailyStatDAO()
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateDailyStat 更新当天统计数据
|
||||
func (this *UserAccountDailyStatDAO) UpdateDailyStat(tx *dbs.Tx) error {
|
||||
var day = timeutil.Format("Ymd")
|
||||
var month = timeutil.Format("Ym")
|
||||
income, err := SharedUserAccountLogDAO.SumDailyEventTypes(tx, day, userconfigs.AccountIncomeEventTypes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
expense, err := SharedUserAccountLogDAO.SumDailyEventTypes(tx, day, userconfigs.AccountExpenseEventTypes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if expense < 0 {
|
||||
expense = -expense
|
||||
}
|
||||
|
||||
return this.Query(tx).
|
||||
InsertOrUpdateQuickly(maps.Map{
|
||||
"day": day,
|
||||
"month": month,
|
||||
"income": income,
|
||||
"expense": expense,
|
||||
}, maps.Map{
|
||||
"income": income,
|
||||
"expense": expense,
|
||||
})
|
||||
}
|
||||
|
||||
// FindDailyStats 查看按天统计
|
||||
func (this *UserAccountDailyStatDAO) FindDailyStats(tx *dbs.Tx, dayFrom string, dayTo string) (result []*UserAccountDailyStat, err error) {
|
||||
_, err = this.Query(tx).
|
||||
Between("day", dayFrom, dayTo).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// FindMonthlyStats 查看某月统计
|
||||
func (this *UserAccountDailyStatDAO) FindMonthlyStats(tx *dbs.Tx, dayFrom string, dayTo string) (result []*UserAccountDailyStat, err error) {
|
||||
_, err = this.Query(tx).
|
||||
Result("SUM(income) AS income", "SUM(expense) AS expense", "month").
|
||||
Between("day", dayFrom, dayTo).
|
||||
Group("month").
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
)
|
||||
@@ -1,253 +0,0 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/goman"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
dbs.OnReadyDone(func() {
|
||||
goman.New(func() {
|
||||
// 自动支付账单任务
|
||||
var ticker = time.NewTicker(12 * time.Hour)
|
||||
for range ticker.C {
|
||||
if SharedUserAccountDAO.Instance != nil {
|
||||
err := SharedUserAccountDAO.Instance.RunTx(func(tx *dbs.Tx) error {
|
||||
return SharedUserAccountDAO.PayBills(tx)
|
||||
})
|
||||
if err != nil {
|
||||
remotelogs.Error("USER_ACCOUNT_DAO", "pay bills task failed: "+err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
type UserAccountDAO dbs.DAO
|
||||
|
||||
func NewUserAccountDAO() *UserAccountDAO {
|
||||
return dbs.NewDAO(&UserAccountDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeUserAccounts",
|
||||
Model: new(UserAccount),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*UserAccountDAO)
|
||||
}
|
||||
|
||||
var SharedUserAccountDAO *UserAccountDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedUserAccountDAO = NewUserAccountDAO()
|
||||
})
|
||||
}
|
||||
|
||||
// FindUserAccountWithUserId 根据用户ID查找用户账户
|
||||
func (this *UserAccountDAO) FindUserAccountWithUserId(tx *dbs.Tx, userId int64) (*UserAccount, error) {
|
||||
if userId <= 0 {
|
||||
return nil, errors.New("invalid userId '" + types.String(userId) + "'")
|
||||
}
|
||||
|
||||
// 用户是否存在
|
||||
user, err := models.SharedUserDAO.FindEnabledUser(tx, userId, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if user == nil {
|
||||
return nil, errors.New("invalid userId '" + types.String(userId) + "'")
|
||||
}
|
||||
|
||||
account, err := this.Query(tx).
|
||||
Attr("userId", userId).
|
||||
Find()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if account != nil {
|
||||
return account.(*UserAccount), nil
|
||||
}
|
||||
|
||||
var op = NewUserAccountOperator()
|
||||
op.UserId = userId
|
||||
_, err = this.SaveInt64(tx, op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.FindUserAccountWithUserId(tx, userId)
|
||||
}
|
||||
|
||||
// FindUserAccountWithAccountId 根据ID查找用户账户
|
||||
func (this *UserAccountDAO) FindUserAccountWithAccountId(tx *dbs.Tx, accountId int64) (*UserAccount, error) {
|
||||
one, err := this.Query(tx).
|
||||
Pk(accountId).
|
||||
Find()
|
||||
if one != nil {
|
||||
return one.(*UserAccount), nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// UpdateUserAccount 操作用户账户
|
||||
func (this *UserAccountDAO) UpdateUserAccount(tx *dbs.Tx, accountId int64, delta float32, eventType userconfigs.AccountEventType, description string, params maps.Map) error {
|
||||
account, err := this.FindUserAccountWithAccountId(tx, accountId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if account == nil {
|
||||
return errors.New("invalid account id '" + types.String(accountId) + "'")
|
||||
}
|
||||
var userId = int64(account.UserId)
|
||||
var deltaFloat64 = float64(delta)
|
||||
if deltaFloat64 < 0 && account.Total < -deltaFloat64 {
|
||||
return errors.New("not enough account quota to decrease")
|
||||
}
|
||||
|
||||
// 操作账户
|
||||
err = this.Query(tx).
|
||||
Pk(account.Id).
|
||||
Set("total", dbs.SQL("total+:delta")).
|
||||
Param("delta", delta).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 生成日志
|
||||
err = SharedUserAccountLogDAO.CreateAccountLog(tx, userId, accountId, delta, 0, eventType, description, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateUserAccountFrozen 操作用户账户冻结余额
|
||||
func (this *UserAccountDAO) UpdateUserAccountFrozen(tx *dbs.Tx, userId int64, delta float32, eventType userconfigs.AccountEventType, description string, params maps.Map) error {
|
||||
account, err := this.FindUserAccountWithUserId(tx, userId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var deltaFloat64 = float64(delta)
|
||||
if deltaFloat64 < 0 && account.TotalFrozen < -deltaFloat64 {
|
||||
return errors.New("not enough account frozen quota to decrease")
|
||||
}
|
||||
|
||||
// 操作账户
|
||||
err = this.Query(tx).
|
||||
Pk(account.Id).
|
||||
Set("totalFrozen", dbs.SQL("total+:delta")).
|
||||
Param("delta", delta).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 生成日志
|
||||
err = SharedUserAccountLogDAO.CreateAccountLog(tx, userId, int64(account.Id), 0, delta, eventType, description, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CountAllAccounts 计算所有账户数量
|
||||
func (this *UserAccountDAO) CountAllAccounts(tx *dbs.Tx, keyword string) (int64, error) {
|
||||
var query = this.Query(tx)
|
||||
if len(keyword) > 0 {
|
||||
query.Where("userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword))")
|
||||
query.Param("keyword", keyword)
|
||||
} else {
|
||||
query.Where("userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1)")
|
||||
}
|
||||
return query.Count()
|
||||
}
|
||||
|
||||
// ListAccounts 列出单页账户
|
||||
func (this *UserAccountDAO) ListAccounts(tx *dbs.Tx, keyword string, offset int64, size int64) (result []*UserAccount, err error) {
|
||||
var query = this.Query(tx)
|
||||
if len(keyword) > 0 {
|
||||
query.Where("userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword))")
|
||||
query.Param("keyword", keyword)
|
||||
} else {
|
||||
query.Where("userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1)")
|
||||
}
|
||||
_, err = query.
|
||||
DescPk().
|
||||
Offset(offset).
|
||||
Limit(size).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// PayBills 尝试自动支付账单
|
||||
func (this *UserAccountDAO) PayBills(tx *dbs.Tx) error {
|
||||
bills, err := models.SharedUserBillDAO.FindUnpaidBills(tx, 10000)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 先支付久远的
|
||||
lists.Reverse(bills)
|
||||
|
||||
for _, bill := range bills {
|
||||
if bill.Amount <= 0 {
|
||||
err = models.SharedUserBillDAO.UpdateUserBillIsPaid(tx, int64(bill.Id), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
account, err := SharedUserAccountDAO.FindUserAccountWithUserId(tx, int64(bill.UserId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if account == nil || account.Total < bill.Amount {
|
||||
continue
|
||||
}
|
||||
|
||||
// 扣款
|
||||
err = SharedUserAccountDAO.UpdateUserAccount(tx, int64(account.Id), -float32(bill.Amount), userconfigs.AccountEventTypePayBill, "支付账单"+bill.Code, maps.Map{"billId": bill.Id})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 改为已支付
|
||||
err = models.SharedUserBillDAO.UpdateUserBillIsPaid(tx, int64(bill.Id), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckUserAccount 检查用户账户
|
||||
func (this *UserAccountDAO) CheckUserAccount(tx *dbs.Tx, userId int64, accountId int64) error {
|
||||
exists, err := this.Query(tx).
|
||||
Pk(accountId).
|
||||
Attr("userId", userId).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
return models.ErrNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUserAccountDAO_PayBills(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
err := NewUserAccountDAO().PayBills(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type UserAccountLogDAO dbs.DAO
|
||||
|
||||
func NewUserAccountLogDAO() *UserAccountLogDAO {
|
||||
return dbs.NewDAO(&UserAccountLogDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeUserAccountLogs",
|
||||
Model: new(UserAccountLog),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*UserAccountLogDAO)
|
||||
}
|
||||
|
||||
var SharedUserAccountLogDAO *UserAccountLogDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedUserAccountLogDAO = NewUserAccountLogDAO()
|
||||
})
|
||||
}
|
||||
|
||||
// CreateAccountLog 生成用户账户日志
|
||||
func (this *UserAccountLogDAO) CreateAccountLog(tx *dbs.Tx, userId int64, accountId int64, delta float32, deltaFrozen float32, eventType userconfigs.AccountEventType, description string, params maps.Map) error {
|
||||
var op = NewUserAccountLogOperator()
|
||||
op.UserId = userId
|
||||
op.AccountId = accountId
|
||||
op.Delta = delta
|
||||
op.DeltaFrozen = deltaFrozen
|
||||
|
||||
account, err := SharedUserAccountDAO.FindUserAccountWithAccountId(tx, accountId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if account == nil {
|
||||
return errors.New("invalid account id '" + types.String(accountId) + "'")
|
||||
}
|
||||
op.Total = account.Total
|
||||
op.TotalFrozen = account.TotalFrozen
|
||||
|
||||
op.EventType = eventType
|
||||
op.Description = description
|
||||
|
||||
if params == nil {
|
||||
params = maps.Map{}
|
||||
}
|
||||
op.Params = params.AsJSON()
|
||||
|
||||
op.Day = timeutil.Format("Ymd")
|
||||
err = this.Save(tx, op)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return SharedUserAccountDailyStatDAO.UpdateDailyStat(tx)
|
||||
}
|
||||
|
||||
// CountAccountLogs 计算日志数量
|
||||
func (this *UserAccountLogDAO) CountAccountLogs(tx *dbs.Tx, userId int64, accountId int64, keyword string, eventType string) (int64, error) {
|
||||
var query = this.Query(tx)
|
||||
if userId > 0 {
|
||||
query.Attr("userId", userId)
|
||||
}
|
||||
if accountId > 0 {
|
||||
query.Attr("accountId", accountId)
|
||||
}
|
||||
if len(keyword) > 0 {
|
||||
query.Where("(userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword)) OR description LIKE :keyword)")
|
||||
query.Param("keyword", dbutils.QuoteLike(keyword))
|
||||
}
|
||||
if len(eventType) > 0 {
|
||||
query.Attr("eventType", eventType)
|
||||
}
|
||||
return query.Count()
|
||||
}
|
||||
|
||||
// ListAccountLogs 列出单页日志
|
||||
func (this *UserAccountLogDAO) ListAccountLogs(tx *dbs.Tx, userId int64, accountId int64, keyword string, eventType string, offset int64, size int64) (result []*UserAccountLog, err error) {
|
||||
var query = this.Query(tx)
|
||||
if userId > 0 {
|
||||
query.Attr("userId", userId)
|
||||
}
|
||||
if accountId > 0 {
|
||||
query.Attr("accountId", accountId)
|
||||
}
|
||||
if len(keyword) > 0 {
|
||||
query.Where("(userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword)) OR description LIKE :keyword)")
|
||||
query.Param("keyword", dbutils.QuoteLike(keyword))
|
||||
}
|
||||
if len(eventType) > 0 {
|
||||
query.Attr("eventType", eventType)
|
||||
}
|
||||
_, err = query.
|
||||
DescPk().
|
||||
Offset(offset).
|
||||
Limit(size).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// SumDailyEventTypes 统计某天数据总和
|
||||
func (this *UserAccountLogDAO) SumDailyEventTypes(tx *dbs.Tx, day string, eventTypes []userconfigs.AccountEventType) (float32, error) {
|
||||
if len(eventTypes) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
result, err := this.Query(tx).
|
||||
Attr("day", day).
|
||||
Attr("eventType", eventTypes).
|
||||
Sum("delta", 0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return types.Float32(result), nil
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
)
|
||||
@@ -976,7 +976,7 @@ func (this *NodeDAO) ComposeNodeConfig(tx *dbs.Tx, nodeId int64, cacheMap *utils
|
||||
}
|
||||
|
||||
for _, server := range servers {
|
||||
serverConfig, err := SharedServerDAO.ComposeServerConfig(tx, server, cacheMap, true)
|
||||
serverConfig, err := SharedServerDAO.ComposeServerConfig(tx, server, cacheMap, true, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package models
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
|
||||
)
|
||||
|
||||
@@ -29,47 +28,3 @@ func (this *NSCluster) HasDDoSProtection() bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// DecodeHosts 解析主机地址
|
||||
func (this *NSCluster) DecodeHosts() []string {
|
||||
if IsNull(this.Hosts) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var hosts = []string{}
|
||||
err := json.Unmarshal(this.Hosts, &hosts)
|
||||
if err != nil {
|
||||
remotelogs.Error("NSCluster.DecodeHosts", "decode failed: "+err.Error())
|
||||
}
|
||||
|
||||
return hosts
|
||||
}
|
||||
|
||||
// DecodeSOAConfig 解析SOA设置
|
||||
func (this *NSCluster) DecodeSOAConfig() *dnsconfigs.NSSOAConfig {
|
||||
var config = dnsconfigs.DefaultNSSOAConfig()
|
||||
if IsNull(this.Soa) {
|
||||
return config
|
||||
}
|
||||
err := json.Unmarshal(this.Soa, config)
|
||||
if err != nil {
|
||||
remotelogs.Error("NSCluster.DecodeSOAConfig", "decode failed: "+err.Error())
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
// DecodeAnswerConfig 解析应答设置
|
||||
func (this *NSCluster) DecodeAnswerConfig() *dnsconfigs.NSAnswerConfig {
|
||||
var config = dnsconfigs.DefaultNSAnswerConfig()
|
||||
|
||||
if IsNull(this.Answer) {
|
||||
return config
|
||||
}
|
||||
|
||||
err := json.Unmarshal(this.Answer, config)
|
||||
if err != nil {
|
||||
remotelogs.Error("NSCluster.DecodeAnswerConfig", "decode failed: "+err.Error())
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -1009,12 +1009,12 @@ func (this *ServerDAO) ComposeServerConfigWithServerId(tx *dbs.Tx, serverId int6
|
||||
if server == nil {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
return this.ComposeServerConfig(tx, server, nil, forNode)
|
||||
return this.ComposeServerConfig(tx, server, nil, forNode, false)
|
||||
}
|
||||
|
||||
// ComposeServerConfig 构造服务的Config
|
||||
// forNode 是否是节点请求
|
||||
func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap *utils.CacheMap, forNode bool) (*serverconfigs.ServerConfig, error) {
|
||||
func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap *utils.CacheMap, forNode bool, forList bool) (*serverconfigs.ServerConfig, error) {
|
||||
if server == nil {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
@@ -1039,7 +1039,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
|
||||
|
||||
var groupConfig *serverconfigs.ServerGroupConfig
|
||||
for _, groupId := range server.DecodeGroupIds() {
|
||||
groupConfig1, err := SharedServerGroupDAO.ComposeGroupConfig(tx, groupId, cacheMap)
|
||||
groupConfig1, err := SharedServerGroupDAO.ComposeGroupConfig(tx, groupId, forList, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1062,28 +1062,30 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
|
||||
}
|
||||
|
||||
// CNAME
|
||||
config.SupportCNAME = server.SupportCNAME == 1
|
||||
if server.ClusterId > 0 && len(server.DnsName) > 0 {
|
||||
clusterDNS, err := SharedNodeClusterDAO.FindClusterDNSInfo(tx, int64(server.ClusterId), cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if clusterDNS != nil && clusterDNS.DnsDomainId > 0 {
|
||||
clusterDNSConfig, err := clusterDNS.DecodeDNSConfig()
|
||||
if !forList {
|
||||
config.SupportCNAME = server.SupportCNAME == 1
|
||||
if server.ClusterId > 0 && len(server.DnsName) > 0 {
|
||||
clusterDNS, err := SharedNodeClusterDAO.FindClusterDNSInfo(tx, int64(server.ClusterId), cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if clusterDNS != nil && clusterDNS.DnsDomainId > 0 {
|
||||
clusterDNSConfig, err := clusterDNS.DecodeDNSConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
domain, err := dns.SharedDNSDomainDAO.FindEnabledDNSDomain(tx, int64(clusterDNS.DnsDomainId), cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if domain != nil {
|
||||
var cname = server.DnsName + "." + domain.Name
|
||||
config.CNameDomain = cname
|
||||
if clusterDNSConfig.CNAMEAsDomain {
|
||||
config.CNameAsDomain = true
|
||||
config.AliasServerNames = append(config.AliasServerNames, cname)
|
||||
domain, err := dns.SharedDNSDomainDAO.FindEnabledDNSDomain(tx, int64(clusterDNS.DnsDomainId), cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if domain != nil {
|
||||
var cname = server.DnsName + "." + domain.Name
|
||||
config.CNameDomain = cname
|
||||
if clusterDNSConfig.CNAMEAsDomain {
|
||||
config.CNameAsDomain = true
|
||||
config.AliasServerNames = append(config.AliasServerNames, cname)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1174,61 +1176,71 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
|
||||
}
|
||||
|
||||
// Web
|
||||
if server.WebId > 0 {
|
||||
webConfig, err := SharedHTTPWebDAO.ComposeWebConfig(tx, int64(server.WebId), cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if webConfig != nil {
|
||||
config.Web = webConfig
|
||||
if !forList {
|
||||
if server.WebId > 0 {
|
||||
webConfig, err := SharedHTTPWebDAO.ComposeWebConfig(tx, int64(server.WebId), cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if webConfig != nil {
|
||||
config.Web = webConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ReverseProxy
|
||||
if IsNotNull(server.ReverseProxy) {
|
||||
var reverseProxyRef = &serverconfigs.ReverseProxyRef{}
|
||||
err := json.Unmarshal(server.ReverseProxy, reverseProxyRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.ReverseProxyRef = reverseProxyRef
|
||||
if !forList {
|
||||
if IsNotNull(server.ReverseProxy) {
|
||||
var reverseProxyRef = &serverconfigs.ReverseProxyRef{}
|
||||
err := json.Unmarshal(server.ReverseProxy, reverseProxyRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.ReverseProxyRef = reverseProxyRef
|
||||
|
||||
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if reverseProxyConfig != nil {
|
||||
config.ReverseProxy = reverseProxyConfig
|
||||
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if reverseProxyConfig != nil {
|
||||
config.ReverseProxy = reverseProxyConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WAF策略
|
||||
var clusterId = int64(server.ClusterId)
|
||||
httpFirewallPolicyId, err := SharedNodeClusterDAO.FindClusterHTTPFirewallPolicyId(tx, clusterId, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if httpFirewallPolicyId > 0 {
|
||||
config.HTTPFirewallPolicyId = httpFirewallPolicyId
|
||||
}
|
||||
|
||||
// 缓存策略
|
||||
httpCachePolicyId, err := SharedNodeClusterDAO.FindClusterHTTPCachePolicyId(tx, clusterId, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if httpCachePolicyId > 0 {
|
||||
config.HTTPCachePolicyId = httpCachePolicyId
|
||||
}
|
||||
|
||||
// traffic limit
|
||||
if len(server.TrafficLimit) > 0 {
|
||||
var trafficLimitConfig = &serverconfigs.TrafficLimitConfig{}
|
||||
err = json.Unmarshal(server.TrafficLimit, trafficLimitConfig)
|
||||
if !forList {
|
||||
httpFirewallPolicyId, err := SharedNodeClusterDAO.FindClusterHTTPFirewallPolicyId(tx, clusterId, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.TrafficLimit = trafficLimitConfig
|
||||
if httpFirewallPolicyId > 0 {
|
||||
config.HTTPFirewallPolicyId = httpFirewallPolicyId
|
||||
}
|
||||
}
|
||||
|
||||
// 缓存策略
|
||||
if !forList {
|
||||
httpCachePolicyId, err := SharedNodeClusterDAO.FindClusterHTTPCachePolicyId(tx, clusterId, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if httpCachePolicyId > 0 {
|
||||
config.HTTPCachePolicyId = httpCachePolicyId
|
||||
}
|
||||
}
|
||||
|
||||
// traffic limit
|
||||
if !forList {
|
||||
if len(server.TrafficLimit) > 0 {
|
||||
var trafficLimitConfig = &serverconfigs.TrafficLimitConfig{}
|
||||
err := json.Unmarshal(server.TrafficLimit, trafficLimitConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.TrafficLimit = trafficLimitConfig
|
||||
}
|
||||
}
|
||||
|
||||
// 用户套餐
|
||||
@@ -1271,7 +1283,7 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
|
||||
if config.TrafficLimit != nil && config.TrafficLimit.IsOn && !config.TrafficLimit.IsEmpty() {
|
||||
if len(server.TrafficLimitStatus) > 0 {
|
||||
var status = &serverconfigs.TrafficLimitStatus{}
|
||||
err = json.Unmarshal(server.TrafficLimitStatus, status)
|
||||
err := json.Unmarshal(server.TrafficLimitStatus, status)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1282,14 +1294,16 @@ func (this *ServerDAO) ComposeServerConfig(tx *dbs.Tx, server *Server, cacheMap
|
||||
}
|
||||
|
||||
// UAM
|
||||
if teaconst.IsPlus && IsNotNull(server.Uam) {
|
||||
var uamConfig = &serverconfigs.UAMConfig{}
|
||||
err = json.Unmarshal(server.Uam, uamConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if uamConfig.IsOn {
|
||||
config.UAM = uamConfig
|
||||
if !forList {
|
||||
if teaconst.IsPlus && IsNotNull(server.Uam) {
|
||||
var uamConfig = &serverconfigs.UAMConfig{}
|
||||
err := json.Unmarshal(server.Uam, uamConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if uamConfig.IsOn {
|
||||
config.UAM = uamConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -279,7 +279,7 @@ func (this *ServerGroupDAO) InitGroupWeb(tx *dbs.Tx, groupId int64) (int64, erro
|
||||
}
|
||||
|
||||
// ComposeGroupConfig 组合配置
|
||||
func (this *ServerGroupDAO) ComposeGroupConfig(tx *dbs.Tx, groupId int64, cacheMap *utils.CacheMap) (*serverconfigs.ServerGroupConfig, error) {
|
||||
func (this *ServerGroupDAO) ComposeGroupConfig(tx *dbs.Tx, groupId int64, forList bool, cacheMap *utils.CacheMap) (*serverconfigs.ServerGroupConfig, error) {
|
||||
if cacheMap == nil {
|
||||
cacheMap = utils.NewCacheMap()
|
||||
}
|
||||
@@ -315,65 +315,67 @@ func (this *ServerGroupDAO) ComposeGroupConfig(tx *dbs.Tx, groupId int64, cacheM
|
||||
IsOn: group.IsOn,
|
||||
}
|
||||
|
||||
if IsNotNull(group.HttpReverseProxy) {
|
||||
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
|
||||
err := json.Unmarshal(group.HttpReverseProxy, reverseProxyRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.HTTPReverseProxyRef = reverseProxyRef
|
||||
if !forList {
|
||||
if IsNotNull(group.HttpReverseProxy) {
|
||||
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
|
||||
err := json.Unmarshal(group.HttpReverseProxy, reverseProxyRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.HTTPReverseProxyRef = reverseProxyRef
|
||||
|
||||
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if reverseProxyConfig != nil {
|
||||
config.HTTPReverseProxy = reverseProxyConfig
|
||||
}
|
||||
}
|
||||
if reverseProxyConfig != nil {
|
||||
config.HTTPReverseProxy = reverseProxyConfig
|
||||
}
|
||||
}
|
||||
|
||||
if IsNotNull(group.TcpReverseProxy) {
|
||||
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
|
||||
err := json.Unmarshal(group.TcpReverseProxy, reverseProxyRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.TCPReverseProxyRef = reverseProxyRef
|
||||
if IsNotNull(group.TcpReverseProxy) {
|
||||
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
|
||||
err := json.Unmarshal(group.TcpReverseProxy, reverseProxyRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.TCPReverseProxyRef = reverseProxyRef
|
||||
|
||||
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if reverseProxyConfig != nil {
|
||||
config.TCPReverseProxy = reverseProxyConfig
|
||||
}
|
||||
}
|
||||
if reverseProxyConfig != nil {
|
||||
config.TCPReverseProxy = reverseProxyConfig
|
||||
}
|
||||
}
|
||||
|
||||
if IsNotNull(group.UdpReverseProxy) {
|
||||
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
|
||||
err := json.Unmarshal(group.UdpReverseProxy, reverseProxyRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.UDPReverseProxyRef = reverseProxyRef
|
||||
if IsNotNull(group.UdpReverseProxy) {
|
||||
reverseProxyRef := &serverconfigs.ReverseProxyRef{}
|
||||
err := json.Unmarshal(group.UdpReverseProxy, reverseProxyRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.UDPReverseProxyRef = reverseProxyRef
|
||||
|
||||
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
reverseProxyConfig, err := SharedReverseProxyDAO.ComposeReverseProxyConfig(tx, reverseProxyRef.ReverseProxyId, cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if reverseProxyConfig != nil {
|
||||
config.UDPReverseProxy = reverseProxyConfig
|
||||
}
|
||||
}
|
||||
if reverseProxyConfig != nil {
|
||||
config.UDPReverseProxy = reverseProxyConfig
|
||||
}
|
||||
}
|
||||
|
||||
// web
|
||||
if group.WebId > 0 {
|
||||
webConfig, err := SharedHTTPWebDAO.ComposeWebConfig(tx, int64(group.WebId), cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if webConfig != nil {
|
||||
config.Web = webConfig
|
||||
// web
|
||||
if group.WebId > 0 {
|
||||
webConfig, err := SharedHTTPWebDAO.ComposeWebConfig(tx, int64(group.WebId), cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if webConfig != nil {
|
||||
config.Web = webConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -300,7 +300,7 @@ func (this *UserNodeDAO) CountAllEnabledUserNodesWithSSLPolicyIds(tx *dbs.Tx, ss
|
||||
if len(sslPolicyIds) == 0 {
|
||||
return
|
||||
}
|
||||
policyStringIds := []string{}
|
||||
var policyStringIds = []string{}
|
||||
for _, policyId := range sslPolicyIds {
|
||||
policyStringIds = append(policyStringIds, strconv.FormatInt(policyId, 10))
|
||||
}
|
||||
@@ -310,3 +310,21 @@ func (this *UserNodeDAO) CountAllEnabledUserNodesWithSSLPolicyIds(tx *dbs.Tx, ss
|
||||
Param("policyIds", strings.Join(policyStringIds, ",")).
|
||||
Count()
|
||||
}
|
||||
|
||||
// FindUserNodeAccessAddr 获取用户节点访问地址
|
||||
func (this *UserNodeDAO) FindUserNodeAccessAddr(tx *dbs.Tx) (string, error) {
|
||||
nodes, err := this.ListEnabledUserNodes(tx, 0, 100)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, node := range nodes {
|
||||
addrs, err := node.DecodeAccessAddrStrings()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if len(addrs) > 0 {
|
||||
return addrs[0], nil
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
@@ -22,21 +22,21 @@ type UserNode struct {
|
||||
}
|
||||
|
||||
type UserNodeOperator struct {
|
||||
Id interface{} // ID
|
||||
IsOn interface{} // 是否启用
|
||||
UniqueId interface{} // 唯一ID
|
||||
Secret interface{} // 密钥
|
||||
Name interface{} // 名称
|
||||
Description interface{} // 描述
|
||||
Http interface{} // 监听的HTTP配置
|
||||
Https interface{} // 监听的HTTPS配置
|
||||
AccessAddrs interface{} // 外部访问地址
|
||||
Order interface{} // 排序
|
||||
State interface{} // 状态
|
||||
CreatedAt interface{} // 创建时间
|
||||
AdminId interface{} // 管理员ID
|
||||
Weight interface{} // 权重
|
||||
Status interface{} // 运行状态
|
||||
Id any // ID
|
||||
IsOn any // 是否启用
|
||||
UniqueId any // 唯一ID
|
||||
Secret any // 密钥
|
||||
Name any // 名称
|
||||
Description any // 描述
|
||||
Http any // 监听的HTTP配置
|
||||
Https any // 监听的HTTPS配置
|
||||
AccessAddrs any // 外部访问地址
|
||||
Order any // 排序
|
||||
State any // 状态
|
||||
CreatedAt any // 创建时间
|
||||
AdminId any // 管理员ID
|
||||
Weight any // 权重
|
||||
Status any // 运行状态
|
||||
}
|
||||
|
||||
func NewUserNodeOperator() *UserNodeOperator {
|
||||
|
||||
21
internal/dnsclients/edgeapi/response_base.go
Normal file
21
internal/dnsclients/edgeapi/response_base.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package edgeapi
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
)
|
||||
|
||||
type BaseResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (this *BaseResponse) IsValid() bool {
|
||||
return this.Code == 200
|
||||
}
|
||||
|
||||
func (this *BaseResponse) Error() error {
|
||||
return errors.New("code: " + types.String(this.Code) + ", message: " + this.Message)
|
||||
}
|
||||
11
internal/dnsclients/edgeapi/response_create_ns_record.go
Normal file
11
internal/dnsclients/edgeapi/response_create_ns_record.go
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package edgeapi
|
||||
|
||||
type CreateNSRecordResponse struct {
|
||||
BaseResponse
|
||||
|
||||
Data struct {
|
||||
NSRecordId int64 `json:"nsRecordId"`
|
||||
} `json:"data"`
|
||||
}
|
||||
14
internal/dnsclients/edgeapi/response_find_all_ns_routes.go
Normal file
14
internal/dnsclients/edgeapi/response_find_all_ns_routes.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package edgeapi
|
||||
|
||||
type FindAllNSRoutesResponse struct {
|
||||
BaseResponse
|
||||
|
||||
Data struct {
|
||||
NSRoutes []struct {
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
} `json:"nsRoutes"`
|
||||
} `json:"data"`
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package edgeapi
|
||||
|
||||
type FindDomainWithNameResponse struct {
|
||||
BaseResponse
|
||||
|
||||
Data struct {
|
||||
NSDomain struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
} `json:"data"`
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package edgeapi
|
||||
|
||||
type FindNSRecordWithNameAndTypeResponse struct {
|
||||
BaseResponse
|
||||
|
||||
Data struct {
|
||||
NSRecord struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value"`
|
||||
TTL int32 `json:"ttl"`
|
||||
NSRoutes []struct {
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
} `json:"nsRoutes"`
|
||||
} `json:"nsRecord"`
|
||||
}
|
||||
}
|
||||
12
internal/dnsclients/edgeapi/response_get_api_access_token.go
Normal file
12
internal/dnsclients/edgeapi/response_get_api_access_token.go
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package edgeapi
|
||||
|
||||
type GetAPIAccessToken struct {
|
||||
BaseResponse
|
||||
|
||||
Data struct {
|
||||
Token string `json:"token"`
|
||||
ExpiresAt int64 `json:"expiresAt"`
|
||||
} `json:"data"`
|
||||
}
|
||||
8
internal/dnsclients/edgeapi/response_interface.go
Normal file
8
internal/dnsclients/edgeapi/response_interface.go
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package edgeapi
|
||||
|
||||
type ResponseInterface interface {
|
||||
IsValid() bool
|
||||
Error() error
|
||||
}
|
||||
16
internal/dnsclients/edgeapi/response_list_ns_domains.go
Normal file
16
internal/dnsclients/edgeapi/response_list_ns_domains.go
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package edgeapi
|
||||
|
||||
type ListNSDomainsResponse struct {
|
||||
BaseResponse
|
||||
|
||||
Data struct {
|
||||
NSDomains []struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
IsOn bool `json:"isOn"`
|
||||
IsDeleted bool `json:"isDeleted"`
|
||||
} `json:"nsDomains"`
|
||||
} `json:"data"`
|
||||
}
|
||||
21
internal/dnsclients/edgeapi/response_list_ns_records.go
Normal file
21
internal/dnsclients/edgeapi/response_list_ns_records.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package edgeapi
|
||||
|
||||
type ListNSRecordsResponse struct {
|
||||
BaseResponse
|
||||
|
||||
Data struct {
|
||||
NSRecords []struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
TTL int32 `json:"ttl"`
|
||||
Type string `json:"type"`
|
||||
NSRoutes []struct {
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
} `json:"nsRoutes"`
|
||||
} `json:"nsRecords"`
|
||||
} `json:"data"`
|
||||
}
|
||||
7
internal/dnsclients/edgeapi/response_success.go
Normal file
7
internal/dnsclients/edgeapi/response_success.go
Normal file
@@ -0,0 +1,7 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package edgeapi
|
||||
|
||||
type SuccessResponse struct {
|
||||
BaseResponse
|
||||
}
|
||||
7
internal/dnsclients/edgeapi/response_update_ns_record.go
Normal file
7
internal/dnsclients/edgeapi/response_update_ns_record.go
Normal file
@@ -0,0 +1,7 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package edgeapi
|
||||
|
||||
type UpdateNSRecordResponse struct {
|
||||
BaseResponse
|
||||
}
|
||||
1
internal/installers/helpers/README.md
Normal file
1
internal/installers/helpers/README.md
Normal file
@@ -0,0 +1 @@
|
||||
远程安装依赖文件,单独放在一个目录防止安装包过大
|
||||
91
internal/installers/helpers/unzip.go
Normal file
91
internal/installers/helpers/unzip.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Unzip struct {
|
||||
zipFile string
|
||||
targetDir string
|
||||
}
|
||||
|
||||
func NewUnzip(zipFile string, targetDir string) *Unzip {
|
||||
return &Unzip{
|
||||
zipFile: zipFile,
|
||||
targetDir: targetDir,
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Unzip) Run() error {
|
||||
if len(this.zipFile) == 0 {
|
||||
return errors.New("zip file should not be empty")
|
||||
}
|
||||
if len(this.targetDir) == 0 {
|
||||
return errors.New("target dir should not be empty")
|
||||
}
|
||||
|
||||
reader, err := zip.OpenReader(this.zipFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = reader.Close()
|
||||
}()
|
||||
|
||||
for _, file := range reader.File {
|
||||
info := file.FileInfo()
|
||||
target := this.targetDir + "/" + file.Name
|
||||
|
||||
// 目录
|
||||
if info.IsDir() {
|
||||
stat, err := os.Stat(target)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
} else {
|
||||
err = os.MkdirAll(target, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else if !stat.IsDir() {
|
||||
err = os.MkdirAll(target, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// 文件
|
||||
err := func(file *zip.File, target string) error {
|
||||
fileReader, err := file.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = fileReader.Close()
|
||||
}()
|
||||
|
||||
fileWriter, err := os.OpenFile(target, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, file.FileInfo().Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = fileWriter.Close()
|
||||
}()
|
||||
|
||||
_, err = io.Copy(fileWriter, fileReader)
|
||||
return err
|
||||
}(file, target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
17
internal/installers/helpers/unzip_test.go
Normal file
17
internal/installers/helpers/unzip_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package helpers_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/installers/helpers"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUnzip_Run(t *testing.T) {
|
||||
var unzip = helpers.NewUnzip(Tea.Root+"/deploy/edge-node-v0.0.1.zip", Tea.Root+"/deploy/")
|
||||
err := unzip.Run()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("OK")
|
||||
}
|
||||
@@ -147,7 +147,7 @@ func (this *BaseInstaller) LookupLatestInstaller(filePrefix string) (string, err
|
||||
|
||||
// InstallHelper 上传安装助手
|
||||
func (this *BaseInstaller) InstallHelper(targetDir string, role nodeconfigs.NodeRole) (env *Env, err error) {
|
||||
uname, _, err := this.client.Exec("uname -a")
|
||||
uname, _, err := this.client.Exec("/usr/bin/uname -a")
|
||||
if err != nil {
|
||||
return env, err
|
||||
}
|
||||
|
||||
@@ -366,7 +366,7 @@ func (this *NodeQueue) StopNode(nodeId int64) error {
|
||||
}
|
||||
|
||||
// 我们先尝试Systemd停止
|
||||
_, _, _ = installer.client.Exec("systemctl stop edge-node")
|
||||
_, _, _ = installer.client.Exec("/usr/bin/systemctl stop edge-node")
|
||||
|
||||
// 执行stop
|
||||
_, stderr, err := installer.client.Exec(exe + " stop")
|
||||
|
||||
@@ -130,14 +130,16 @@ func (this *APINode) Start() {
|
||||
}
|
||||
|
||||
// 数据库通知启动
|
||||
this.setProgress("DATABASE", "正在建立数据库模型")
|
||||
logs.Println("[API_NODE]notify ready ...")
|
||||
dbs.NotifyReady()
|
||||
|
||||
// 设置时区
|
||||
this.setProgress("TIMEZONE", "正在设置时区")
|
||||
this.setupTimeZone()
|
||||
|
||||
// 读取配置
|
||||
this.setProgress("DATABASE", "加载API配置")
|
||||
this.setProgress("DATABASE", "正在加载API配置")
|
||||
logs.Println("[API_NODE]reading api config ...")
|
||||
config, err := configs.SharedAPIConfig()
|
||||
if err != nil {
|
||||
@@ -384,6 +386,19 @@ func (this *APINode) setupDB() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// 检查是否为root用户
|
||||
config, _ := db.Config()
|
||||
if config == nil {
|
||||
return nil
|
||||
}
|
||||
dsnConfig, err := mysql.ParseDSN(config.Dsn)
|
||||
if err != nil || dsnConfig == nil {
|
||||
return err
|
||||
}
|
||||
if dsnConfig.User != "root" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 设置Innodb事务提交模式
|
||||
{
|
||||
result, err := db.FindOne("SHOW VARIABLES WHERE variable_name='innodb_flush_log_at_trx_commit'")
|
||||
|
||||
@@ -357,21 +357,6 @@ func (this *APINode) registerServices(server *grpc.Server) {
|
||||
pb.RegisterServerDailyStatServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
{
|
||||
var instance = this.serviceInstance(&services.UserBillService{}).(*services.UserBillService)
|
||||
pb.RegisterUserBillServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
{
|
||||
var instance = this.serviceInstance(&services.ServerBillService{}).(*services.ServerBillService)
|
||||
pb.RegisterServerBillServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
{
|
||||
var instance = this.serviceInstance(&services.UserNodeService{}).(*services.UserNodeService)
|
||||
pb.RegisterUserNodeServiceServer(server, instance)
|
||||
this.rest(instance)
|
||||
}
|
||||
{
|
||||
var instance = this.serviceInstance(&services.LoginService{}).(*services.LoginService)
|
||||
pb.RegisterLoginServiceServer(server, instance)
|
||||
|
||||
@@ -840,21 +840,38 @@ func (this *ServerService) ListEnabledServersMatch(ctx context.Context, req *pb.
|
||||
}
|
||||
|
||||
// 配置
|
||||
config, err := models.SharedServerDAO.ComposeServerConfig(tx, server, nil, false)
|
||||
config, err := models.SharedServerDAO.ComposeServerConfig(tx, server, nil, false, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var countServerNames int32 = 0
|
||||
for _, serverName := range config.ServerNames {
|
||||
if len(serverName.SubNames) > 0 {
|
||||
countServerNames += int32(len(serverName.SubNames))
|
||||
} else {
|
||||
countServerNames++
|
||||
}
|
||||
}
|
||||
if req.IgnoreServerNames && len(config.ServerNames) > 0 {
|
||||
config.ServerNames = config.ServerNames[:1]
|
||||
}
|
||||
configJSON, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 忽略信息
|
||||
if req.IgnoreServerNames {
|
||||
server.ServerNames = nil
|
||||
}
|
||||
|
||||
result = append(result, &pb.Server{
|
||||
Id: int64(server.Id),
|
||||
IsOn: server.IsOn,
|
||||
Type: server.Type,
|
||||
Config: configJSON,
|
||||
Name: server.Name,
|
||||
CountServerNames: countServerNames,
|
||||
Description: server.Description,
|
||||
HttpJSON: server.Http,
|
||||
HttpsJSON: server.Https,
|
||||
@@ -986,7 +1003,7 @@ func (this *ServerService) FindEnabledServer(ctx context.Context, req *pb.FindEn
|
||||
}
|
||||
|
||||
// 配置
|
||||
config, err := models.SharedServerDAO.ComposeServerConfig(tx, server, nil, userId > 0)
|
||||
config, err := models.SharedServerDAO.ComposeServerConfig(tx, server, nil, userId > 0, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
)
|
||||
|
||||
// ServerBillService 服务账单相关服务
|
||||
type ServerBillService struct {
|
||||
BaseService
|
||||
}
|
||||
|
||||
// CountAllServerBills 查询服务账单数量
|
||||
func (this *ServerBillService) CountAllServerBills(ctx context.Context, req *pb.CountAllServerBillsRequest) (*pb.RPCCountResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if userId > 0 {
|
||||
req.UserId = userId
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
count, err := models.SharedServerBillDAO.CountServerBills(tx, req.UserId, req.Month)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.SuccessCount(count)
|
||||
}
|
||||
|
||||
// ListServerBills 查询服务账单列表
|
||||
func (this *ServerBillService) ListServerBills(ctx context.Context, req *pb.ListServerBillsRequest) (*pb.ListServerBillsResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if userId > 0 {
|
||||
req.UserId = userId
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
serverBills, err := models.SharedServerBillDAO.ListServerBills(tx, req.UserId, req.Month, req.Offset, req.Size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var pbServerBills = []*pb.ServerBill{}
|
||||
var cacheMap = utils.NewCacheMap()
|
||||
for _, bill := range serverBills {
|
||||
// user
|
||||
user, err := models.SharedUserDAO.FindBasicUserWithoutState(tx, int64(bill.UserId))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var pbUser = &pb.User{Id: int64(bill.UserId)}
|
||||
if user != nil {
|
||||
pbUser = &pb.User{
|
||||
Id: int64(bill.UserId),
|
||||
Username: user.Username,
|
||||
Fullname: user.Fullname,
|
||||
}
|
||||
}
|
||||
|
||||
// plan
|
||||
var pbPlan *pb.Plan
|
||||
if bill.PlanId > 0 {
|
||||
plan, err := models.SharedPlanDAO.FindEnabledPlan(tx, int64(bill.PlanId))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if plan != nil {
|
||||
pbPlan = &pb.Plan{
|
||||
Id: int64(plan.Id),
|
||||
Name: plan.Name,
|
||||
PriceType: plan.PriceType,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// user plan
|
||||
var pbUserPlan *pb.UserPlan
|
||||
if bill.UserPlanId > 0 {
|
||||
userPlan, err := models.SharedUserPlanDAO.FindEnabledUserPlan(tx, int64(bill.UserPlanId), cacheMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if userPlan != nil {
|
||||
pbUserPlan = &pb.UserPlan{
|
||||
Id: int64(userPlan.Id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// server
|
||||
var pbServer *pb.Server
|
||||
if bill.ServerId > 0 {
|
||||
server, err := models.SharedServerDAO.FindEnabledServerBasic(tx, int64(bill.ServerId))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if server != nil {
|
||||
pbServer = &pb.Server{Id: int64(bill.ServerId), Name: server.Name}
|
||||
}
|
||||
}
|
||||
|
||||
pbServerBills = append(pbServerBills, &pb.ServerBill{
|
||||
Id: int64(bill.Id),
|
||||
UserId: int64(bill.UserId),
|
||||
ServerId: int64(bill.ServerId),
|
||||
Amount: float32(bill.Amount),
|
||||
PriceType: bill.PriceType,
|
||||
CreatedAt: int64(bill.CreatedAt),
|
||||
UserPlanId: int64(bill.UserPlanId),
|
||||
PlanId: int64(bill.PlanId),
|
||||
TotalTrafficBytes: int64(bill.TotalTrafficBytes),
|
||||
BandwidthPercentileBytes: int64(bill.BandwidthPercentileBytes),
|
||||
BandwidthPercentile: int32(bill.BandwidthPercentile),
|
||||
User: pbUser,
|
||||
Plan: pbPlan,
|
||||
UserPlan: pbUserPlan,
|
||||
Server: pbServer,
|
||||
})
|
||||
}
|
||||
|
||||
return &pb.ListServerBillsResponse{ServerBills: pbServerBills}, nil
|
||||
}
|
||||
@@ -463,7 +463,7 @@ func (this *ServerGroupService) FindEnabledServerGroupConfigInfo(ctx context.Con
|
||||
result.HasUDPReverseProxy = ref.IsPrior
|
||||
}
|
||||
|
||||
config, err := models.SharedServerGroupDAO.ComposeGroupConfig(tx, int64(group.Id), nil)
|
||||
config, err := models.SharedServerGroupDAO.ComposeGroupConfig(tx, int64(group.Id), false, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,255 +0,0 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/accounts"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// UserBillService 账单相关服务
|
||||
type UserBillService struct {
|
||||
BaseService
|
||||
}
|
||||
|
||||
// GenerateAllUserBills 手工生成订单
|
||||
func (this *UserBillService) GenerateAllUserBills(ctx context.Context, req *pb.GenerateAllUserBillsRequest) (*pb.RPCSuccess, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 校验Month
|
||||
if !regexp.MustCompile(`^\d{6}$`).MatchString(req.Month) {
|
||||
return nil, errors.New("invalid month '" + req.Month + "'")
|
||||
}
|
||||
if req.Month >= timeutil.Format("Ym") {
|
||||
return nil, errors.New("invalid month '" + req.Month + "'")
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
err = models.SharedUserBillDAO.GenerateBills(tx, req.Month)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// CountAllUserBills 计算所有账单数量
|
||||
func (this *UserBillService) CountAllUserBills(ctx context.Context, req *pb.CountAllUserBillsRequest) (*pb.RPCCountResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
if userId > 0 {
|
||||
req.UserId = userId
|
||||
}
|
||||
|
||||
count, err := models.SharedUserBillDAO.CountAllUserBills(tx, req.PaidFlag, req.UserId, req.Month)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.SuccessCount(count)
|
||||
}
|
||||
|
||||
// ListUserBills 列出单页账单
|
||||
func (this *UserBillService) ListUserBills(ctx context.Context, req *pb.ListUserBillsRequest) (*pb.ListUserBillsResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
if userId > 0 {
|
||||
req.UserId = userId
|
||||
}
|
||||
|
||||
bills, err := models.SharedUserBillDAO.ListUserBills(tx, req.PaidFlag, req.UserId, req.Month, req.Offset, req.Size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := []*pb.UserBill{}
|
||||
for _, bill := range bills {
|
||||
user, err := models.SharedUserDAO.FindBasicUserWithoutState(tx, int64(bill.UserId))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if user == nil {
|
||||
user = &models.User{Id: bill.UserId}
|
||||
}
|
||||
|
||||
result = append(result, &pb.UserBill{
|
||||
Id: int64(bill.Id),
|
||||
User: &pb.User{
|
||||
Id: int64(bill.UserId),
|
||||
Fullname: user.Fullname,
|
||||
Username: user.Username,
|
||||
IsDeleted: user.State == models.UserStateDisabled,
|
||||
},
|
||||
Type: bill.Type,
|
||||
TypeName: models.SharedUserBillDAO.BillTypeName(bill.Type),
|
||||
Description: bill.Description,
|
||||
Amount: float32(bill.Amount),
|
||||
Month: bill.Month,
|
||||
CanPay: bill.CanPay,
|
||||
IsPaid: bill.IsPaid,
|
||||
PaidAt: int64(bill.PaidAt),
|
||||
Code: bill.Code,
|
||||
})
|
||||
}
|
||||
return &pb.ListUserBillsResponse{UserBills: result}, nil
|
||||
}
|
||||
|
||||
// FindUserBill 查找账单信息
|
||||
func (this *UserBillService) FindUserBill(ctx context.Context, req *pb.FindUserBillRequest) (*pb.FindUserBillResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
// 检查用户
|
||||
if userId > 0 {
|
||||
err = models.SharedUserBillDAO.CheckUserBill(tx, userId, req.UserBillId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
bill, err := models.SharedUserBillDAO.FindUserBill(tx, req.UserBillId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if bill == nil {
|
||||
return &pb.FindUserBillResponse{UserBill: nil}, nil
|
||||
}
|
||||
|
||||
// 用户
|
||||
var pbUser = &pb.User{Id: int64(bill.UserId)}
|
||||
user, err := models.SharedUserDAO.FindEnabledUser(tx, int64(bill.UserId), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if user != nil {
|
||||
pbUser = &pb.User{
|
||||
Id: int64(user.Id),
|
||||
Username: user.Username,
|
||||
Fullname: user.Fullname,
|
||||
}
|
||||
}
|
||||
|
||||
return &pb.FindUserBillResponse{
|
||||
UserBill: &pb.UserBill{
|
||||
Id: int64(bill.Id),
|
||||
User: pbUser,
|
||||
Type: bill.Type,
|
||||
TypeName: models.SharedUserBillDAO.BillTypeName(bill.Type),
|
||||
Description: bill.Description,
|
||||
Amount: float32(bill.Amount),
|
||||
Month: bill.Month,
|
||||
CanPay: bill.CanPay,
|
||||
IsPaid: bill.IsPaid,
|
||||
PaidAt: int64(bill.PaidAt),
|
||||
Code: bill.Code,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// PayUserBill 支付账单
|
||||
func (this *UserBillService) PayUserBill(ctx context.Context, req *pb.PayUserBillRequest) (*pb.RPCSuccess, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = this.RunTx(func(tx *dbs.Tx) error {
|
||||
// 检查用户
|
||||
if userId > 0 {
|
||||
err = models.SharedUserBillDAO.CheckUserBill(tx, userId, req.UserBillId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 是否存在
|
||||
bill, err := models.SharedUserBillDAO.FindUserBill(tx, req.UserBillId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if bill == nil {
|
||||
return nil
|
||||
}
|
||||
userId = int64(bill.UserId)
|
||||
|
||||
// 是否已支付
|
||||
if bill.IsPaid {
|
||||
return nil
|
||||
}
|
||||
|
||||
if bill.Amount <= 0 {
|
||||
// 直接修改为已支付
|
||||
return models.SharedUserBillDAO.UpdateUserBillIsPaid(tx, req.UserBillId, true)
|
||||
}
|
||||
|
||||
if !bill.CanPay {
|
||||
return errors.New("can not pay now")
|
||||
}
|
||||
|
||||
// 余额是否足够
|
||||
account, err := accounts.SharedUserAccountDAO.FindUserAccountWithUserId(tx, userId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if account == nil {
|
||||
return errors.New("can not find user account")
|
||||
}
|
||||
|
||||
if account.Total < bill.Amount {
|
||||
return errors.New("not enough balance to pay")
|
||||
}
|
||||
|
||||
err = accounts.SharedUserAccountDAO.UpdateUserAccount(tx, int64(account.Id), -float32(bill.Amount), userconfigs.AccountEventTypePayBill, "支付账单"+bill.Code, maps.Map{"billId": bill.Id})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 修改为已支付
|
||||
return models.SharedUserBillDAO.UpdateUserBillIsPaid(tx, req.UserBillId, true)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// SumUserUnpaidBills 计算用户所有未支付账单总额
|
||||
func (this *UserBillService) SumUserUnpaidBills(ctx context.Context, req *pb.SumUserUnpaidBillsRequest) (*pb.SumUserUnpaidBillsResponse, error) {
|
||||
_, userId, err := this.ValidateAdminAndUser(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
if userId > 0 {
|
||||
req.UserId = userId
|
||||
}
|
||||
|
||||
sum, err := models.SharedUserBillDAO.SumUnpaidUserBill(tx, userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.SumUserUnpaidBillsResponse{Amount: sum}, nil
|
||||
}
|
||||
@@ -1,304 +0,0 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
rpcutils "github.com/TeaOSLab/EdgeAPI/internal/rpc/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UserNodeService struct {
|
||||
BaseService
|
||||
}
|
||||
|
||||
// CreateUserNode 创建用户节点
|
||||
func (this *UserNodeService) CreateUserNode(ctx context.Context, req *pb.CreateUserNodeRequest) (*pb.CreateUserNodeResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
nodeId, err := models.SharedUserNodeDAO.CreateUserNode(tx, req.Name, req.Description, req.HttpJSON, req.HttpsJSON, req.AccessAddrsJSON, req.IsOn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.CreateUserNodeResponse{UserNodeId: nodeId}, nil
|
||||
}
|
||||
|
||||
// UpdateUserNode 修改用户节点
|
||||
func (this *UserNodeService) UpdateUserNode(ctx context.Context, req *pb.UpdateUserNodeRequest) (*pb.RPCSuccess, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
err = models.SharedUserNodeDAO.UpdateUserNode(tx, req.UserNodeId, req.Name, req.Description, req.HttpJSON, req.HttpsJSON, req.AccessAddrsJSON, req.IsOn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// DeleteUserNode 删除用户节点
|
||||
func (this *UserNodeService) DeleteUserNode(ctx context.Context, req *pb.DeleteUserNodeRequest) (*pb.RPCSuccess, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
err = models.SharedUserNodeDAO.DisableUserNode(tx, req.UserNodeId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// FindAllEnabledUserNodes 列出所有可用用户节点
|
||||
func (this *UserNodeService) FindAllEnabledUserNodes(ctx context.Context, req *pb.FindAllEnabledUserNodesRequest) (*pb.FindAllEnabledUserNodesResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
nodes, err := models.SharedUserNodeDAO.FindAllEnabledUserNodes(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := []*pb.UserNode{}
|
||||
for _, node := range nodes {
|
||||
accessAddrs, err := node.DecodeAccessAddrStrings()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result = append(result, &pb.UserNode{
|
||||
Id: int64(node.Id),
|
||||
IsOn: node.IsOn,
|
||||
UniqueId: node.UniqueId,
|
||||
Secret: node.Secret,
|
||||
Name: node.Name,
|
||||
Description: node.Description,
|
||||
HttpJSON: node.Http,
|
||||
HttpsJSON: node.Https,
|
||||
AccessAddrsJSON: node.AccessAddrs,
|
||||
AccessAddrs: accessAddrs,
|
||||
})
|
||||
}
|
||||
|
||||
return &pb.FindAllEnabledUserNodesResponse{UserNodes: result}, nil
|
||||
}
|
||||
|
||||
// CountAllEnabledUserNodes 计算用户节点数量
|
||||
func (this *UserNodeService) CountAllEnabledUserNodes(ctx context.Context, req *pb.CountAllEnabledUserNodesRequest) (*pb.RPCCountResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
count, err := models.SharedUserNodeDAO.CountAllEnabledUserNodes(tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return this.SuccessCount(count)
|
||||
}
|
||||
|
||||
// ListEnabledUserNodes 列出单页的用户节点
|
||||
func (this *UserNodeService) ListEnabledUserNodes(ctx context.Context, req *pb.ListEnabledUserNodesRequest) (*pb.ListEnabledUserNodesResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
nodes, err := models.SharedUserNodeDAO.ListEnabledUserNodes(tx, req.Offset, req.Size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := []*pb.UserNode{}
|
||||
for _, node := range nodes {
|
||||
accessAddrs, err := node.DecodeAccessAddrStrings()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result = append(result, &pb.UserNode{
|
||||
Id: int64(node.Id),
|
||||
IsOn: node.IsOn,
|
||||
UniqueId: node.UniqueId,
|
||||
Secret: node.Secret,
|
||||
Name: node.Name,
|
||||
Description: node.Description,
|
||||
HttpJSON: node.Http,
|
||||
HttpsJSON: node.Https,
|
||||
AccessAddrsJSON: node.AccessAddrs,
|
||||
AccessAddrs: accessAddrs,
|
||||
StatusJSON: node.Status,
|
||||
})
|
||||
}
|
||||
|
||||
return &pb.ListEnabledUserNodesResponse{UserNodes: result}, nil
|
||||
}
|
||||
|
||||
// FindEnabledUserNode 根据ID查找节点
|
||||
func (this *UserNodeService) FindEnabledUserNode(ctx context.Context, req *pb.FindEnabledUserNodeRequest) (*pb.FindEnabledUserNodeResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
node, err := models.SharedUserNodeDAO.FindEnabledUserNode(tx, req.UserNodeId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if node == nil {
|
||||
return &pb.FindEnabledUserNodeResponse{UserNode: nil}, nil
|
||||
}
|
||||
|
||||
accessAddrs, err := node.DecodeAccessAddrStrings()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &pb.UserNode{
|
||||
Id: int64(node.Id),
|
||||
IsOn: node.IsOn,
|
||||
UniqueId: node.UniqueId,
|
||||
Secret: node.Secret,
|
||||
Name: node.Name,
|
||||
Description: node.Description,
|
||||
HttpJSON: node.Http,
|
||||
HttpsJSON: node.Https,
|
||||
AccessAddrsJSON: node.AccessAddrs,
|
||||
AccessAddrs: accessAddrs,
|
||||
}
|
||||
return &pb.FindEnabledUserNodeResponse{UserNode: result}, nil
|
||||
}
|
||||
|
||||
// FindCurrentUserNode 获取当前用户节点的版本
|
||||
func (this *UserNodeService) FindCurrentUserNode(ctx context.Context, req *pb.FindCurrentUserNodeRequest) (*pb.FindCurrentUserNodeResponse, error) {
|
||||
_, err := this.ValidateUserNode(ctx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
md, ok := metadata.FromIncomingContext(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New("context: need 'nodeId'")
|
||||
}
|
||||
nodeIds := md.Get("nodeid")
|
||||
if len(nodeIds) == 0 {
|
||||
return nil, errors.New("invalid 'nodeId'")
|
||||
}
|
||||
nodeId := nodeIds[0]
|
||||
node, err := models.SharedUserNodeDAO.FindEnabledUserNodeWithUniqueId(tx, nodeId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if node == nil {
|
||||
return &pb.FindCurrentUserNodeResponse{UserNode: nil}, nil
|
||||
}
|
||||
|
||||
accessAddrs, err := node.DecodeAccessAddrStrings()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &pb.UserNode{
|
||||
Id: int64(node.Id),
|
||||
IsOn: node.IsOn,
|
||||
UniqueId: node.UniqueId,
|
||||
Secret: node.Secret,
|
||||
Name: node.Name,
|
||||
Description: node.Description,
|
||||
HttpJSON: node.Http,
|
||||
HttpsJSON: node.Https,
|
||||
AccessAddrsJSON: node.AccessAddrs,
|
||||
AccessAddrs: accessAddrs,
|
||||
}
|
||||
return &pb.FindCurrentUserNodeResponse{UserNode: result}, nil
|
||||
}
|
||||
|
||||
// UpdateUserNodeStatus 更新节点状态
|
||||
func (this *UserNodeService) UpdateUserNodeStatus(ctx context.Context, req *pb.UpdateUserNodeStatusRequest) (*pb.RPCSuccess, error) {
|
||||
// 校验节点
|
||||
_, nodeId, err := this.ValidateNodeId(ctx, rpcutils.UserTypeUser)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if req.UserNodeId > 0 {
|
||||
nodeId = req.UserNodeId
|
||||
}
|
||||
|
||||
if nodeId <= 0 {
|
||||
return nil, errors.New("'nodeId' should be greater than 0")
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
|
||||
// 修改时间戳
|
||||
var nodeStatus = &nodeconfigs.NodeStatus{}
|
||||
err = json.Unmarshal(req.StatusJSON, nodeStatus)
|
||||
if err != nil {
|
||||
return nil, errors.New("decode node status json failed: " + err.Error())
|
||||
}
|
||||
nodeStatus.UpdatedAt = time.Now().Unix()
|
||||
|
||||
// 保存
|
||||
err = models.SharedUserNodeDAO.UpdateNodeStatus(tx, nodeId, nodeStatus)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.Success()
|
||||
}
|
||||
|
||||
// CountAllEnabledUserNodesWithSSLCertId 计算使用某个SSL证书的用户节点数量
|
||||
func (this *UserNodeService) CountAllEnabledUserNodesWithSSLCertId(ctx context.Context, req *pb.CountAllEnabledUserNodesWithSSLCertIdRequest) (*pb.RPCCountResponse, error) {
|
||||
_, err := this.ValidateAdmin(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx = this.NullTx()
|
||||
policyIds, err := models.SharedSSLPolicyDAO.FindAllEnabledPolicyIdsWithCertId(tx, req.SslCertId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(policyIds) == 0 {
|
||||
return this.SuccessCount(0)
|
||||
}
|
||||
|
||||
count, err := models.SharedUserNodeDAO.CountAllEnabledUserNodesWithSSLPolicyIds(tx, policyIds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.SuccessCount(count)
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -3,6 +3,7 @@ package setup
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
@@ -137,12 +138,22 @@ func (this *SQLDump) Dump(db *dbs.DB) (result *SQLDumpResult, err error) {
|
||||
func (this *SQLDump) Apply(db *dbs.DB, newResult *SQLDumpResult, showLog bool) (ops []string, err error) {
|
||||
// 设置Innodb事务提交模式
|
||||
{
|
||||
|
||||
result, err := db.FindOne("SHOW VARIABLES WHERE variable_name='innodb_flush_log_at_trx_commit'")
|
||||
if err == nil && result != nil {
|
||||
var oldValue = result.GetInt("Value")
|
||||
if oldValue == 1 {
|
||||
_, _ = db.Exec("SET GLOBAL innodb_flush_log_at_trx_commit=2")
|
||||
// 检查是否为root用户
|
||||
config, _ := db.Config()
|
||||
if config == nil {
|
||||
return nil, nil
|
||||
}
|
||||
dsnConfig, err := mysql.ParseDSN(config.Dsn)
|
||||
if err != nil || dsnConfig == nil {
|
||||
return nil, err
|
||||
}
|
||||
if dsnConfig.User == "root" {
|
||||
result, err := db.FindOne("SHOW VARIABLES WHERE variable_name='innodb_flush_log_at_trx_commit'")
|
||||
if err == nil && result != nil {
|
||||
var oldValue = result.GetInt("Value")
|
||||
if oldValue == 1 {
|
||||
_, _ = db.Exec("SET GLOBAL innodb_flush_log_at_trx_commit=2")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ func TestSQLDump_Apply(t *testing.T) {
|
||||
|
||||
db2, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
|
||||
Driver: "mysql",
|
||||
Dsn: "root:123456@tcp(192.168.2.60:3306)/db_edge_new?charset=utf8mb4&timeout=30s",
|
||||
Dsn: "edge:123456@tcp(192.168.2.60:3306)/db_edge_new?charset=utf8mb4&timeout=30s",
|
||||
Prefix: "edge",
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -111,7 +111,8 @@ func (this *ServiceManager) installSystemdService(systemd, exePath string, args
|
||||
shortName := teaconst.SystemdServiceName
|
||||
longName := "GoEdge API" // TODO 将来可以修改
|
||||
|
||||
desc := `# Provides: ` + shortName + `
|
||||
desc := `### BEGIN INIT INFO
|
||||
# Provides: ` + shortName + `
|
||||
# Required-Start: $all
|
||||
# Required-Stop:
|
||||
# Default-Start: 2 3 4 5
|
||||
|
||||
Reference in New Issue
Block a user