mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-03-01 01:20:49 +03:00
revert group management (#2656)
* Revert "json post base path bug fixed (#2647)" This reverts commit04cf250a54
. * Revert "Group Management of Subscription Clients" * Revert "fix getSubGroupClients for enable/disable and edit clients." * Revert "Enhance database initialization in db.go (#2645)" This reverts commit66fe84181b
. * Revert "Add checkpoint handling in CloseDB function (#2646)" This reverts commit4dd40f6f19
. * Revert "Improved database model migration and added indexing (#2655)" This reverts commitb922d986d6
.
This commit is contained in:
parent
04c6b2722b
commit
d18a1a37ce
@ -26,35 +26,20 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func initModels() error {
|
func initModels() error {
|
||||||
// Order matters: first create tables without dependencies
|
models := []interface{}{
|
||||||
baseModels := []interface{}{
|
|
||||||
&model.User{},
|
&model.User{},
|
||||||
&model.Setting{},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Migrate base models
|
|
||||||
for _, model := range baseModels {
|
|
||||||
if err := db.AutoMigrate(model); err != nil {
|
|
||||||
log.Printf("Error auto migrating base model: %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then migrate models with dependencies
|
|
||||||
dependentModels := []interface{}{
|
|
||||||
&model.Inbound{},
|
&model.Inbound{},
|
||||||
&model.OutboundTraffics{},
|
&model.OutboundTraffics{},
|
||||||
|
&model.Setting{},
|
||||||
&model.InboundClientIps{},
|
&model.InboundClientIps{},
|
||||||
&xray.ClientTraffic{},
|
&xray.ClientTraffic{},
|
||||||
}
|
}
|
||||||
|
for _, model := range models {
|
||||||
for _, model := range dependentModels {
|
|
||||||
if err := db.AutoMigrate(model); err != nil {
|
if err := db.AutoMigrate(model); err != nil {
|
||||||
log.Printf("Error auto migrating dependent model: %v", err)
|
log.Printf("Error auto migrating model: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,31 +82,9 @@ func InitDB(dbPath string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c := &gorm.Config{
|
c := &gorm.Config{
|
||||||
Logger: gormLogger,
|
Logger: gormLogger,
|
||||||
SkipDefaultTransaction: true,
|
|
||||||
PrepareStmt: true,
|
|
||||||
}
|
}
|
||||||
|
db, err = gorm.Open(sqlite.Open(dbPath), c)
|
||||||
dsn := dbPath + "?cache=shared&_journal_mode=WAL&_synchronous=NORMAL"
|
|
||||||
db, err = gorm.Open(sqlite.Open(dsn), c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlDB, err := db.DB()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = sqlDB.Exec("PRAGMA cache_size = -64000;")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = sqlDB.Exec("PRAGMA temp_store = MEMORY;")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = sqlDB.Exec("PRAGMA foreign_keys = ON;")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -138,11 +101,6 @@ func InitDB(dbPath string) error {
|
|||||||
|
|
||||||
func CloseDB() error {
|
func CloseDB() error {
|
||||||
if db != nil {
|
if db != nil {
|
||||||
|
|
||||||
if err := Checkpoint(); err != nil {
|
|
||||||
log.Printf("error executing checkpoint: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlDB, err := db.DB()
|
sqlDB, err := db.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -29,14 +29,14 @@ type User struct {
|
|||||||
|
|
||||||
type Inbound struct {
|
type Inbound struct {
|
||||||
Id int `json:"id" form:"id" gorm:"primaryKey;autoIncrement"`
|
Id int `json:"id" form:"id" gorm:"primaryKey;autoIncrement"`
|
||||||
UserId int `json:"-" gorm:"index"`
|
UserId int `json:"-"`
|
||||||
Up int64 `json:"up" form:"up"`
|
Up int64 `json:"up" form:"up"`
|
||||||
Down int64 `json:"down" form:"down"`
|
Down int64 `json:"down" form:"down"`
|
||||||
Total int64 `json:"total" form:"total"`
|
Total int64 `json:"total" form:"total"`
|
||||||
Remark string `json:"remark" form:"remark"`
|
Remark string `json:"remark" form:"remark"`
|
||||||
Enable bool `json:"enable" form:"enable"`
|
Enable bool `json:"enable" form:"enable"`
|
||||||
ExpiryTime int64 `json:"expiryTime" form:"expiryTime"`
|
ExpiryTime int64 `json:"expiryTime" form:"expiryTime"`
|
||||||
ClientStats []xray.ClientTraffic `gorm:"foreignKey:InboundId;references:Id;constraint:OnDelete:CASCADE" json:"clientStats"`
|
ClientStats []xray.ClientTraffic `gorm:"foreignKey:InboundId;references:Id" json:"clientStats" form:"clientStats"`
|
||||||
|
|
||||||
// config part
|
// config part
|
||||||
Listen string `json:"listen" form:"listen"`
|
Listen string `json:"listen" form:"listen"`
|
||||||
|
@ -26,7 +26,6 @@ class AllSetting {
|
|||||||
this.xrayTemplateConfig = "";
|
this.xrayTemplateConfig = "";
|
||||||
this.secretEnable = false;
|
this.secretEnable = false;
|
||||||
this.subEnable = false;
|
this.subEnable = false;
|
||||||
this.subSyncEnable = true;
|
|
||||||
this.subListen = "";
|
this.subListen = "";
|
||||||
this.subPort = 2096;
|
this.subPort = 2096;
|
||||||
this.subPath = "/sub/";
|
this.subPath = "/sub/";
|
||||||
|
@ -70,41 +70,6 @@ class HttpUtil {
|
|||||||
}
|
}
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async jsonPost(url, data) {
|
|
||||||
let msg;
|
|
||||||
try {
|
|
||||||
const requestOptions = {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
};
|
|
||||||
const resp = await fetch(basePath + url.replace(/^\/+|\/+$/g, ''), requestOptions);
|
|
||||||
const response = await resp.json();
|
|
||||||
|
|
||||||
msg = this._respToMsg({data : response});
|
|
||||||
} catch (e) {
|
|
||||||
msg = new Msg(false, e.toString());
|
|
||||||
}
|
|
||||||
this._handleMsg(msg);
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
static async postWithModalJson(url, data, modal) {
|
|
||||||
if (modal) {
|
|
||||||
modal.loading(true);
|
|
||||||
}
|
|
||||||
const msg = await this.jsonPost(url, data);
|
|
||||||
if (modal) {
|
|
||||||
modal.loading(false);
|
|
||||||
if (msg instanceof Msg && msg.success) {
|
|
||||||
modal.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class PromiseUtil {
|
class PromiseUtil {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"x-ui/database/model"
|
"x-ui/database/model"
|
||||||
"x-ui/web/service"
|
"x-ui/web/service"
|
||||||
"x-ui/web/session"
|
"x-ui/web/session"
|
||||||
@ -33,13 +33,9 @@ func (a *InboundController) initRouter(g *gin.RouterGroup) {
|
|||||||
g.POST("/clientIps/:email", a.getClientIps)
|
g.POST("/clientIps/:email", a.getClientIps)
|
||||||
g.POST("/clearClientIps/:email", a.clearClientIps)
|
g.POST("/clearClientIps/:email", a.clearClientIps)
|
||||||
g.POST("/addClient", a.addInboundClient)
|
g.POST("/addClient", a.addInboundClient)
|
||||||
g.POST("/addGroupClient", a.addGroupInboundClient)
|
|
||||||
g.POST("/:id/delClient/:clientId", a.delInboundClient)
|
g.POST("/:id/delClient/:clientId", a.delInboundClient)
|
||||||
g.POST("/delGroupClients", a.delGroupClients)
|
|
||||||
g.POST("/updateClient/:clientId", a.updateInboundClient)
|
g.POST("/updateClient/:clientId", a.updateInboundClient)
|
||||||
g.POST("/updateClients", a.updateGroupInboundClient)
|
|
||||||
g.POST("/:id/resetClientTraffic/:email", a.resetClientTraffic)
|
g.POST("/:id/resetClientTraffic/:email", a.resetClientTraffic)
|
||||||
g.POST("/resetGroupClientTraffic", a.resetGroupClientTraffic)
|
|
||||||
g.POST("/resetAllTraffics", a.resetAllTraffics)
|
g.POST("/resetAllTraffics", a.resetAllTraffics)
|
||||||
g.POST("/resetAllClientTraffics/:id", a.resetAllClientTraffics)
|
g.POST("/resetAllClientTraffics/:id", a.resetAllClientTraffics)
|
||||||
g.POST("/delDepletedClients/:id", a.delDepletedClients)
|
g.POST("/delDepletedClients/:id", a.delDepletedClients)
|
||||||
@ -194,34 +190,6 @@ func (a *InboundController) addInboundClient(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *InboundController) addGroupInboundClient(c *gin.Context) {
|
|
||||||
var requestData []model.Inbound
|
|
||||||
|
|
||||||
err := c.ShouldBindJSON(&requestData)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.update"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
needRestart := true
|
|
||||||
|
|
||||||
for _, data := range requestData {
|
|
||||||
|
|
||||||
needRestart, err = a.inboundService.AddInboundClient(&data)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, "Something went wrong!", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonMsg(c, "Client(s) added", nil)
|
|
||||||
if err == nil && needRestart {
|
|
||||||
a.xrayService.SetToNeedRestart()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *InboundController) delInboundClient(c *gin.Context) {
|
func (a *InboundController) delInboundClient(c *gin.Context) {
|
||||||
id, err := strconv.Atoi(c.Param("id"))
|
id, err := strconv.Atoi(c.Param("id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -243,38 +211,6 @@ func (a *InboundController) delInboundClient(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *InboundController) delGroupClients(c *gin.Context) {
|
|
||||||
var requestData []struct {
|
|
||||||
InboundID int `json:"inboundId"`
|
|
||||||
ClientID string `json:"clientId"`
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.ShouldBindJSON(&requestData); err != nil {
|
|
||||||
jsonMsg(c, "Invalid request data", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
needRestart := false
|
|
||||||
|
|
||||||
for _, req := range requestData {
|
|
||||||
needRestartTmp, err := a.inboundService.DelInboundClient(req.InboundID, req.ClientID)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, "Failed to delete client", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if needRestartTmp {
|
|
||||||
needRestart = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonMsg(c, "Clients deleted successfully", nil)
|
|
||||||
|
|
||||||
if needRestart {
|
|
||||||
a.xrayService.SetToNeedRestart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *InboundController) updateInboundClient(c *gin.Context) {
|
func (a *InboundController) updateInboundClient(c *gin.Context) {
|
||||||
clientId := c.Param("clientId")
|
clientId := c.Param("clientId")
|
||||||
|
|
||||||
@ -298,56 +234,6 @@ func (a *InboundController) updateInboundClient(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *InboundController) updateGroupInboundClient(c *gin.Context) {
|
|
||||||
var requestData []map[string]interface{}
|
|
||||||
|
|
||||||
if err := c.ShouldBindJSON(&requestData); err != nil {
|
|
||||||
jsonMsg(c, I18nWeb(c, "pages.inbounds.update"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
needRestart := false
|
|
||||||
|
|
||||||
for _, item := range requestData {
|
|
||||||
|
|
||||||
inboundMap, ok := item["inbound"].(map[string]interface{})
|
|
||||||
if !ok {
|
|
||||||
jsonMsg(c, "Something went wrong!", errors.New("Failed to convert 'inbound' to map"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
clientId, ok := item["clientId"].(string)
|
|
||||||
if !ok {
|
|
||||||
jsonMsg(c, "Something went wrong!", errors.New("Failed to convert 'clientId' to string"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
inboundJSON, err := json.Marshal(inboundMap)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, "Something went wrong!", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var inboundModel model.Inbound
|
|
||||||
if err := json.Unmarshal(inboundJSON, &inboundModel); err != nil {
|
|
||||||
jsonMsg(c, "Something went wrong!", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if restart, err := a.inboundService.UpdateInboundClient(&inboundModel, clientId); err != nil {
|
|
||||||
jsonMsg(c, "Something went wrong!", err)
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
needRestart = needRestart || restart
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonMsg(c, "Client updated", nil)
|
|
||||||
if needRestart {
|
|
||||||
a.xrayService.SetToNeedRestart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *InboundController) resetClientTraffic(c *gin.Context) {
|
func (a *InboundController) resetClientTraffic(c *gin.Context) {
|
||||||
id, err := strconv.Atoi(c.Param("id"))
|
id, err := strconv.Atoi(c.Param("id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -367,44 +253,6 @@ func (a *InboundController) resetClientTraffic(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *InboundController) resetGroupClientTraffic(c *gin.Context) {
|
|
||||||
var requestData []struct {
|
|
||||||
InboundID int `json:"inboundId"` // Map JSON "inboundId" to struct field "InboundID"
|
|
||||||
Email string `json:"email"` // Map JSON "email" to struct field "Email"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse JSON body directly using ShouldBindJSON
|
|
||||||
if err := c.ShouldBindJSON(&requestData); err != nil {
|
|
||||||
jsonMsg(c, "Invalid request data", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
needRestart := false
|
|
||||||
|
|
||||||
// Process each request data
|
|
||||||
for _, req := range requestData {
|
|
||||||
needRestartTmp, err := a.inboundService.ResetClientTraffic(req.InboundID, req.Email)
|
|
||||||
if err != nil {
|
|
||||||
jsonMsg(c, "Failed to reset client traffic", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// If any request requires a restart, set needRestart to true
|
|
||||||
if needRestartTmp {
|
|
||||||
needRestart = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send response back to the client
|
|
||||||
jsonMsg(c, "Traffic reset for all clients", nil)
|
|
||||||
|
|
||||||
// Restart the service if required
|
|
||||||
if needRestart {
|
|
||||||
a.xrayService.SetToNeedRestart()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func (a *InboundController) resetAllTraffics(c *gin.Context) {
|
func (a *InboundController) resetAllTraffics(c *gin.Context) {
|
||||||
err := a.inboundService.ResetAllTraffics()
|
err := a.inboundService.ResetAllTraffics()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -40,7 +40,6 @@ type AllSetting struct {
|
|||||||
TimeLocation string `json:"timeLocation" form:"timeLocation"`
|
TimeLocation string `json:"timeLocation" form:"timeLocation"`
|
||||||
SecretEnable bool `json:"secretEnable" form:"secretEnable"`
|
SecretEnable bool `json:"secretEnable" form:"secretEnable"`
|
||||||
SubEnable bool `json:"subEnable" form:"subEnable"`
|
SubEnable bool `json:"subEnable" form:"subEnable"`
|
||||||
SubSyncEnable bool `json:"subSyncEnable" form:"subSyncEnable"`
|
|
||||||
SubListen string `json:"subListen" form:"subListen"`
|
SubListen string `json:"subListen" form:"subListen"`
|
||||||
SubPort int `json:"subPort" form:"subPort"`
|
SubPort int `json:"subPort" form:"subPort"`
|
||||||
SubPath string `json:"subPath" form:"subPath"`
|
SubPath string `json:"subPath" form:"subPath"`
|
||||||
|
@ -23,15 +23,13 @@
|
|||||||
</tr-qr-bg>
|
</tr-qr-bg>
|
||||||
</tr-qr-box>
|
</tr-qr-box>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="!isJustSub">
|
<template v-for="(row, index) in qrModal.qrcodes">
|
||||||
<template v-for="(row, index) in qrModal.qrcodes">
|
<tr-qr-box class="qr-box">
|
||||||
<tr-qr-box class="qr-box">
|
<a-tag color="green" class="qr-tag"><span>[[ row.remark ]]</span></a-tag>
|
||||||
<a-tag color="green" class="qr-tag"><span>[[ row.remark ]]</span></a-tag>
|
<tr-qr-bg class="qr-bg">
|
||||||
<tr-qr-bg class="qr-bg">
|
<canvas @click="copyToClipboard('qrCode-'+index, row.link)" :id="'qrCode-'+index" class="qr-cv"></canvas>
|
||||||
<canvas @click="copyToClipboard('qrCode-'+index, row.link)" :id="'qrCode-'+index" class="qr-cv"></canvas>
|
</tr-qr-bg>
|
||||||
</tr-qr-bg>
|
</tr-qr-box>
|
||||||
</tr-qr-box>
|
|
||||||
</template>
|
|
||||||
</template>
|
</template>
|
||||||
</tr-qr-modal>
|
</tr-qr-modal>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
@ -45,14 +43,12 @@
|
|||||||
qrcodes: [],
|
qrcodes: [],
|
||||||
clipboard: null,
|
clipboard: null,
|
||||||
visible: false,
|
visible: false,
|
||||||
isJustSub: false,
|
|
||||||
subId: '',
|
subId: '',
|
||||||
show: function(title = '', dbInbound, client, isJustSub = false) {
|
show: function(title = '', dbInbound, client) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.dbInbound = dbInbound;
|
this.dbInbound = dbInbound;
|
||||||
this.inbound = dbInbound.toInbound();
|
this.inbound = dbInbound.toInbound();
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.isJustSub = isJustSub;
|
|
||||||
this.subId = '';
|
this.subId = '';
|
||||||
this.qrcodes = [];
|
this.qrcodes = [];
|
||||||
if (this.inbound.protocol == Protocols.WIREGUARD) {
|
if (this.inbound.protocol == Protocols.WIREGUARD) {
|
||||||
@ -80,9 +76,7 @@
|
|||||||
delimiters: ['[[', ']]'],
|
delimiters: ['[[', ']]'],
|
||||||
el: '#qrcode-modal',
|
el: '#qrcode-modal',
|
||||||
data: {
|
data: {
|
||||||
qrModal: qrModal,get isJustSub(){
|
qrModal: qrModal,
|
||||||
return qrModal.isJustSub
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
copyToClipboard(elementId, content) {
|
copyToClipboard(elementId, content) {
|
||||||
|
@ -16,16 +16,7 @@
|
|||||||
title: '',
|
title: '',
|
||||||
okText: '',
|
okText: '',
|
||||||
isEdit: false,
|
isEdit: false,
|
||||||
group: {
|
|
||||||
canGroup: true,
|
|
||||||
isGroup: false,
|
|
||||||
currentClient: null,
|
|
||||||
inbounds: [],
|
|
||||||
clients: [],
|
|
||||||
editIds: []
|
|
||||||
},
|
|
||||||
dbInbound: new DBInbound(),
|
dbInbound: new DBInbound(),
|
||||||
dbInbounds: null,
|
|
||||||
inbound: new Inbound(),
|
inbound: new Inbound(),
|
||||||
clients: [],
|
clients: [],
|
||||||
clientStats: [],
|
clientStats: [],
|
||||||
@ -34,126 +25,33 @@
|
|||||||
clientIps: null,
|
clientIps: null,
|
||||||
delayedStart: false,
|
delayedStart: false,
|
||||||
ok() {
|
ok() {
|
||||||
if (app.subSettings.enable && clientModal.group.isGroup && clientModal.group.canGroup) {
|
if (clientModal.isEdit) {
|
||||||
const currentClient = clientModal.group.currentClient;
|
ObjectUtil.execute(clientModal.confirm, clientModalApp.client, clientModal.dbInbound.id, clientModal.oldClientId);
|
||||||
const { limitIp, comment, totalGB, expiryTime, reset, enable, subId, tgId, flow } = currentClient;
|
|
||||||
const uniqueEmails = clientModalApp.makeGroupEmailsUnique(clientModal.dbInbounds, currentClient.email, clientModal.group.clients);
|
|
||||||
|
|
||||||
clientModal.group.clients.forEach((client, index) => {
|
|
||||||
client.email = uniqueEmails[index];
|
|
||||||
client.limitIp = limitIp;
|
|
||||||
client.comment = comment;
|
|
||||||
client.totalGB = totalGB;
|
|
||||||
client.expiryTime = expiryTime;
|
|
||||||
client.reset = reset;
|
|
||||||
client.enable = enable;
|
|
||||||
|
|
||||||
if (subId) {
|
|
||||||
client.subId = subId;
|
|
||||||
}
|
|
||||||
if (tgId) {
|
|
||||||
client.tgId = tgId;
|
|
||||||
}
|
|
||||||
if (flow) {
|
|
||||||
client.flow = flow;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (clientModal.isEdit) {
|
|
||||||
ObjectUtil.execute(clientModal.confirm, clientModal.group.clients, clientModal.group.inbounds, clientModal.group.editIds);
|
|
||||||
} else {
|
|
||||||
ObjectUtil.execute(clientModal.confirm, clientModal.group.clients, clientModal.group.inbounds);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (clientModal.isEdit) {
|
ObjectUtil.execute(clientModal.confirm, clientModalApp.client, clientModal.dbInbound.id);
|
||||||
ObjectUtil.execute(clientModal.confirm, clientModalApp.client, clientModal.dbInbound.id, clientModal.oldClientId);
|
|
||||||
} else {
|
|
||||||
ObjectUtil.execute(clientModal.confirm, clientModalApp.client, clientModal.dbInbound.id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
show({
|
show({ title = '', okText = '{{ i18n "sure" }}', index = null, dbInbound = null, confirm = () => { }, isEdit = false }) {
|
||||||
title = '',
|
|
||||||
okText = '{{ i18n "sure" }}',
|
|
||||||
index = null,
|
|
||||||
dbInbound = null,
|
|
||||||
dbInbounds = null,
|
|
||||||
confirm = () => {
|
|
||||||
},
|
|
||||||
isEdit = false
|
|
||||||
}) {
|
|
||||||
this.group = {
|
|
||||||
canGroup: true,
|
|
||||||
isGroup: false,
|
|
||||||
currentClient: null,
|
|
||||||
inbounds: [],
|
|
||||||
clients: [],
|
|
||||||
editIds: []
|
|
||||||
}
|
|
||||||
this.dbInbounds = dbInbounds;
|
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.okText = okText;
|
this.okText = okText;
|
||||||
this.isEdit = isEdit;
|
this.isEdit = isEdit;
|
||||||
if (app.subSettings.enable && dbInbounds !== null && Array.isArray(dbInbounds)) {
|
this.dbInbound = new DBInbound(dbInbound);
|
||||||
if (isEdit) {
|
this.inbound = dbInbound.toInbound();
|
||||||
this.showProcess(dbInbound, index);
|
this.clients = this.inbound.clients;
|
||||||
let processSingleEdit = true
|
this.index = index === null ? this.clients.length : index;
|
||||||
if (this.group.canGroup) {
|
this.delayedStart = false;
|
||||||
this.group.currentClient = this.clients[this.index]
|
if (isEdit) {
|
||||||
const response = app.getSubGroupClients(dbInbounds, this.group.currentClient)
|
if (this.clients[index].expiryTime < 0) {
|
||||||
if (response.clients.length > 1) {
|
this.delayedStart = true;
|
||||||
this.group.isGroup = true;
|
|
||||||
this.group.inbounds = response.inbounds
|
|
||||||
this.group.clients = response.clients
|
|
||||||
this.group.editIds = response.editIds
|
|
||||||
if (this.clients[index].expiryTime < 0) {
|
|
||||||
this.delayedStart = true;
|
|
||||||
}
|
|
||||||
processSingleEdit = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (processSingleEdit) {
|
|
||||||
this.singleEditClientProcess(index)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.group.isGroup = true;
|
|
||||||
dbInbounds.forEach((dbInboundItem) => {
|
|
||||||
this.showProcess(dbInboundItem);
|
|
||||||
if (this.dbInbound.isMultiUser()) {
|
|
||||||
this.addClient(this.inbound.protocol, this.clients);
|
|
||||||
this.group.inbounds.push(dbInboundItem.id)
|
|
||||||
this.group.clients.push(this.clients[this.index])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.group.currentClient = this.clients[this.index]
|
|
||||||
}
|
}
|
||||||
|
this.oldClientId = this.getClientId(dbInbound.protocol, clients[index]);
|
||||||
} else {
|
} else {
|
||||||
this.showProcess(dbInbound, index);
|
this.addClient(this.inbound.protocol, this.clients);
|
||||||
if (isEdit) {
|
|
||||||
this.singleEditClientProcess(index)
|
|
||||||
} else {
|
|
||||||
this.addClient(this.inbound.protocol, this.clients);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.clientStats = this.dbInbound.clientStats.find(row => row.email === this.clients[this.index].email);
|
this.clientStats = this.dbInbound.clientStats.find(row => row.email === this.clients[this.index].email);
|
||||||
this.confirm = confirm;
|
this.confirm = confirm;
|
||||||
},
|
},
|
||||||
showProcess(dbInbound, index = null) {
|
|
||||||
this.dbInbound = new DBInbound(dbInbound);
|
|
||||||
this.inbound = dbInbound.toInbound();
|
|
||||||
if (this.dbInbound.isMultiUser()) {
|
|
||||||
this.clients = this.inbound.clients;
|
|
||||||
this.index = index === null ? this.clients.length : index;
|
|
||||||
this.delayedStart = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
singleEditClientProcess(index) {
|
|
||||||
if (this.clients[index].expiryTime < 0) {
|
|
||||||
this.delayedStart = true;
|
|
||||||
}
|
|
||||||
this.oldClientId = this.getClientId(this.dbInbound.protocol, this.clients[index]);
|
|
||||||
},
|
|
||||||
getClientId(protocol, client) {
|
getClientId(protocol, client) {
|
||||||
switch (protocol) {
|
switch (protocol) {
|
||||||
case Protocols.TROJAN: return client.password;
|
case Protocols.TROJAN: return client.password;
|
||||||
@ -174,7 +72,7 @@
|
|||||||
clientModal.visible = false;
|
clientModal.visible = false;
|
||||||
clientModal.loading(false);
|
clientModal.loading(false);
|
||||||
},
|
},
|
||||||
loading(loading = true) {
|
loading(loading=true) {
|
||||||
clientModal.confirmLoading = loading;
|
clientModal.confirmLoading = loading;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -196,18 +94,6 @@
|
|||||||
get isEdit() {
|
get isEdit() {
|
||||||
return this.clientModal.isEdit;
|
return this.clientModal.isEdit;
|
||||||
},
|
},
|
||||||
get isGroup() {
|
|
||||||
return this.clientModal.group.isGroup;
|
|
||||||
},
|
|
||||||
get isGroupEdit() {
|
|
||||||
return this.clientModal.group.canGroup;
|
|
||||||
},
|
|
||||||
set isGroupEdit(value) {
|
|
||||||
this.clientModal.group.canGroup = value;
|
|
||||||
if (!value) {
|
|
||||||
this.clientModal.singleEditClientProcess(this.clientModal.index)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
get datepicker() {
|
get datepicker() {
|
||||||
return app.datepicker;
|
return app.datepicker;
|
||||||
},
|
},
|
||||||
@ -234,36 +120,6 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
makeGroupEmailsUnique(dbInbounds, baseEmail, groupClients) {
|
|
||||||
// Extract the base part of the email (before the "__" if present)
|
|
||||||
const match = baseEmail.match(/^(.*?)__/);
|
|
||||||
const base = match ? match[1] : baseEmail;
|
|
||||||
|
|
||||||
// Generate initial emails for each client in the group
|
|
||||||
const generatedEmails = groupClients.map((_, index) => `${base}__${index + 1}`);
|
|
||||||
|
|
||||||
// Function to check if an email already exists in dbInbounds but belongs to a different subId
|
|
||||||
const isDuplicate = (emailToCheck, clientSubId) => {
|
|
||||||
return dbInbounds.some((dbInbound) => {
|
|
||||||
const settings = JSON.parse(dbInbound.settings);
|
|
||||||
const clients = settings && settings.clients ? settings.clients : [];
|
|
||||||
return clients.some(client => client.email === emailToCheck && client.subId !== clientSubId);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check if any of the generated emails are duplicates
|
|
||||||
const hasDuplicates = generatedEmails.some((email, index) => {
|
|
||||||
return isDuplicate(email, groupClients[index].subId);
|
|
||||||
});
|
|
||||||
|
|
||||||
// If duplicates exist, add a random string to the base email to ensure uniqueness
|
|
||||||
if (hasDuplicates) {
|
|
||||||
const randomString = `-${RandomUtil.randomLowerAndNum(4)}`;
|
|
||||||
return groupClients.map((_, index) => `${base}${randomString}__${index + 1}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return generatedEmails;
|
|
||||||
},
|
|
||||||
async getDBClientIps(email) {
|
async getDBClientIps(email) {
|
||||||
const msg = await HttpUtil.post(`/panel/inbound/clientIps/${email}`);
|
const msg = await HttpUtil.post(`/panel/inbound/clientIps/${email}`);
|
||||||
if (!msg.success) {
|
if (!msg.success) {
|
||||||
@ -291,22 +147,7 @@
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async resetClientTrafficHandler(client, dbInboundId, clients = []) {
|
resetClientTraffic(email, dbInboundId, iconElement) {
|
||||||
if (clients.length > 0) {
|
|
||||||
const resetRequests = clients
|
|
||||||
.filter(client => {
|
|
||||||
const inbound = clientModal.dbInbounds.find(inbound => inbound.id === client.inboundId);
|
|
||||||
return inbound && app.hasClientStats(inbound, client.email);
|
|
||||||
}).map(client => ({ inboundId: client.inboundId, email: client.email}));
|
|
||||||
|
|
||||||
return HttpUtil.postWithModalJson('/panel/inbound/resetGroupClientTraffic', resetRequests, null)
|
|
||||||
} else {
|
|
||||||
return HttpUtil.postWithModal('/panel/inbound/' + dbInboundId + '/resetClientTraffic/' + client.email)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
resetClientTraffic(client, dbInboundId, iconElement) {
|
|
||||||
const subGroup = app.subSettings.enable && clientModal.group.isGroup && clientModal.group.canGroup && clientModal.dbInbounds && clientModal.dbInbounds.length > 0 ? app.getSubGroupClients(clientModal.dbInbounds, client) : [];
|
|
||||||
const clients = subGroup && subGroup.clients && subGroup.clients.length > 1 ? subGroup.clients : [];
|
|
||||||
this.$confirm({
|
this.$confirm({
|
||||||
title: '{{ i18n "pages.inbounds.resetTraffic"}}',
|
title: '{{ i18n "pages.inbounds.resetTraffic"}}',
|
||||||
content: '{{ i18n "pages.inbounds.resetTrafficContent"}}',
|
content: '{{ i18n "pages.inbounds.resetTrafficContent"}}',
|
||||||
@ -315,8 +156,8 @@
|
|||||||
cancelText: '{{ i18n "cancel"}}',
|
cancelText: '{{ i18n "cancel"}}',
|
||||||
onOk: async () => {
|
onOk: async () => {
|
||||||
iconElement.disabled = true;
|
iconElement.disabled = true;
|
||||||
const msg = await this.resetClientTrafficHandler(client, dbInboundId, clients);
|
const msg = await HttpUtil.postWithModal('/panel/inbound/' + dbInboundId + '/resetClientTraffic/' + email);
|
||||||
if (msg && msg.success) {
|
if (msg.success) {
|
||||||
this.clientModal.clientStats.up = 0;
|
this.clientModal.clientStats.up = 0;
|
||||||
this.clientModal.clientStats.down = 0;
|
this.clientModal.clientStats.down = 0;
|
||||||
}
|
}
|
||||||
|
@ -3,18 +3,6 @@
|
|||||||
<a-form-item label='{{ i18n "pages.inbounds.enable" }}'>
|
<a-form-item label='{{ i18n "pages.inbounds.enable" }}'>
|
||||||
<a-switch v-model="client.enable"></a-switch>
|
<a-switch v-model="client.enable"></a-switch>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item v-if="isEdit && app.subSettings.enable && isGroup">
|
|
||||||
<template slot="label">
|
|
||||||
<a-tooltip>
|
|
||||||
<template slot="title">
|
|
||||||
<span>{{ i18n "pages.client.isGroupEditDesc" }}</span>
|
|
||||||
</template>
|
|
||||||
{{ i18n "pages.client.isGroupEdit" }}
|
|
||||||
<a-icon type="question-circle"></a-icon>
|
|
||||||
</a-tooltip>
|
|
||||||
</template>
|
|
||||||
<a-switch v-model="isGroupEdit"></a-switch>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<template slot="label">
|
<template slot="label">
|
||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
@ -146,7 +134,7 @@
|
|||||||
<a-tooltip>
|
<a-tooltip>
|
||||||
<template slot="title">{{ i18n "pages.inbounds.resetTraffic" }}</template>
|
<template slot="title">{{ i18n "pages.inbounds.resetTraffic" }}</template>
|
||||||
<a-icon type="retweet"
|
<a-icon type="retweet"
|
||||||
@click="resetClientTraffic(client,clientStats.inboundId,$event.target)"
|
@click="resetClientTraffic(client.email,clientStats.inboundId,$event.target)"
|
||||||
v-if="client.email.length > 0"></a-icon>
|
v-if="client.email.length > 0"></a-icon>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<template slot="title">{{ i18n "info" }}</template>
|
<template slot="title">{{ i18n "info" }}</template>
|
||||||
<a-icon style="font-size: 24px;" class="normal-icon" type="info-circle" @click="showInfo(record.id,client);"></a-icon>
|
<a-icon style="font-size: 24px;" class="normal-icon" type="info-circle" @click="showInfo(record.id,client);"></a-icon>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-tooltip v-if="hasClientStats(record, client.email)">
|
<a-tooltip>
|
||||||
<template slot="title">{{ i18n "pages.inbounds.resetTraffic" }}</template>
|
<template slot="title">{{ i18n "pages.inbounds.resetTraffic" }}</template>
|
||||||
<a-popconfirm @confirm="resetClientTraffic(client,record.id,false)" title='{{ i18n "pages.inbounds.resetTrafficContent"}}' :overlay-class-name="themeSwitcher.currentTheme" ok-text='{{ i18n "reset"}}' cancel-text='{{ i18n "cancel"}}'>
|
<a-popconfirm @confirm="resetClientTraffic(client,record.id,false)" title='{{ i18n "pages.inbounds.resetTrafficContent"}}' :overlay-class-name="themeSwitcher.currentTheme" ok-text='{{ i18n "reset"}}' cancel-text='{{ i18n "cancel"}}'>
|
||||||
<a-icon slot="icon" type="question-circle-o" :style="themeSwitcher.isDarkTheme ? 'color: var(--color-primary-100)' : 'color: var(--color-primary-100)'"></a-icon>
|
<a-icon slot="icon" type="question-circle-o" :style="themeSwitcher.isDarkTheme ? 'color: var(--color-primary-100)' : 'color: var(--color-primary-100)'"></a-icon>
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
confirmLoading: false,
|
confirmLoading: false,
|
||||||
okText: '{{ i18n "sure" }}',
|
okText: '{{ i18n "sure" }}',
|
||||||
isEdit: false,
|
isEdit: false,
|
||||||
isGroup: false,
|
|
||||||
confirm: null,
|
confirm: null,
|
||||||
inbound: new Inbound(),
|
inbound: new Inbound(),
|
||||||
dbInbound: new DBInbound(),
|
dbInbound: new DBInbound(),
|
||||||
@ -62,9 +61,6 @@
|
|||||||
get isEdit() {
|
get isEdit() {
|
||||||
return inModal.isEdit;
|
return inModal.isEdit;
|
||||||
},
|
},
|
||||||
get isGroup() {
|
|
||||||
return inModal.isGroup;
|
|
||||||
},
|
|
||||||
get client() {
|
get client() {
|
||||||
return inModal.inbound.clients[0];
|
return inModal.inbound.clients[0];
|
||||||
},
|
},
|
||||||
|
@ -224,10 +224,6 @@
|
|||||||
<a-icon type="rest"></a-icon>
|
<a-icon type="rest"></a-icon>
|
||||||
{{ i18n "pages.inbounds.delDepletedClients" }}
|
{{ i18n "pages.inbounds.delDepletedClients" }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item v-if="subSettings.enable && dbInbounds.length > 0" key="addGroupClient">
|
|
||||||
<a-icon type="usergroup-add"></a-icon>
|
|
||||||
{{ i18n "pages.client.groupAdd"}}
|
|
||||||
</a-menu-item>
|
|
||||||
</a-menu>
|
</a-menu>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
</a-col>
|
</a-col>
|
||||||
@ -863,9 +859,6 @@
|
|||||||
case "delDepletedClients":
|
case "delDepletedClients":
|
||||||
this.delDepletedClients(-1)
|
this.delDepletedClients(-1)
|
||||||
break;
|
break;
|
||||||
case "addGroupClient":
|
|
||||||
this.openGroupAddClient()
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
clickAction(action, dbInbound) {
|
clickAction(action, dbInbound) {
|
||||||
@ -1011,21 +1004,6 @@
|
|||||||
|
|
||||||
await this.submit(`/panel/inbound/update/${dbInbound.id}`, data, inModal);
|
await this.submit(`/panel/inbound/update/${dbInbound.id}`, data, inModal);
|
||||||
},
|
},
|
||||||
openGroupAddClient() {
|
|
||||||
clientModal.show({
|
|
||||||
title: '{{ i18n "pages.client.groupAdd"}}',
|
|
||||||
okText: '{{ i18n "pages.client.submitAdd"}}',
|
|
||||||
dbInbounds: this.dbInbounds,
|
|
||||||
confirm: async (clients, dbInboundIds) => {
|
|
||||||
await this.addGroupClient(clients, dbInboundIds, clientModal).then((res) => {
|
|
||||||
if(res){
|
|
||||||
this.showQrcode(dbInboundIds[0],clients[0], true)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
isEdit: false
|
|
||||||
});
|
|
||||||
},
|
|
||||||
openAddClient(dbInboundId) {
|
openAddClient(dbInboundId) {
|
||||||
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||||
clientModal.show({
|
clientModal.show({
|
||||||
@ -1033,11 +1011,7 @@
|
|||||||
okText: '{{ i18n "pages.client.submitAdd"}}',
|
okText: '{{ i18n "pages.client.submitAdd"}}',
|
||||||
dbInbound: dbInbound,
|
dbInbound: dbInbound,
|
||||||
confirm: async (clients, dbInboundId) => {
|
confirm: async (clients, dbInboundId) => {
|
||||||
await this.addClient(clients, dbInboundId, clientModal).then((res) => {
|
await this.addClient(clients, dbInboundId, clientModal);
|
||||||
if(res){
|
|
||||||
this.showQrcode(dbInboundId,clients)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
isEdit: false
|
isEdit: false
|
||||||
});
|
});
|
||||||
@ -1060,7 +1034,6 @@
|
|||||||
clientModal.show({
|
clientModal.show({
|
||||||
title: '{{ i18n "pages.client.edit"}}',
|
title: '{{ i18n "pages.client.edit"}}',
|
||||||
okText: '{{ i18n "pages.client.submitEdit"}}',
|
okText: '{{ i18n "pages.client.submitEdit"}}',
|
||||||
dbInbounds: this.dbInbounds,
|
|
||||||
dbInbound: dbInbound,
|
dbInbound: dbInbound,
|
||||||
index: index,
|
index: index,
|
||||||
confirm: async (client, dbInboundId, clientId) => {
|
confirm: async (client, dbInboundId, clientId) => {
|
||||||
@ -1086,36 +1059,12 @@
|
|||||||
};
|
};
|
||||||
await this.submit(`/panel/inbound/addClient`, data, modal);
|
await this.submit(`/panel/inbound/addClient`, data, modal);
|
||||||
},
|
},
|
||||||
async addGroupClient(clients, dbInboundIds, modal) {
|
|
||||||
const data = []
|
|
||||||
dbInboundIds.forEach((dbInboundId, index) => {
|
|
||||||
data.push({
|
|
||||||
id: dbInboundId,
|
|
||||||
settings: '{"clients": [' + clients[index].toString() + ']}',
|
|
||||||
})
|
|
||||||
})
|
|
||||||
return await this.submit(`/panel/inbound/addGroupClient`, data, modal, true)
|
|
||||||
},
|
|
||||||
async updateClient(client, dbInboundId, clientId) {
|
async updateClient(client, dbInboundId, clientId) {
|
||||||
if (Array.isArray(client) && Array.isArray(dbInboundId) && Array.isArray(clientId)){
|
const data = {
|
||||||
const data = []
|
id: dbInboundId,
|
||||||
client.forEach((client, index) => {
|
settings: '{"clients": [' + client.toString() + ']}',
|
||||||
data.push({
|
};
|
||||||
clientId: clientId[index],
|
await this.submit(`/panel/inbound/updateClient/${clientId}`, data, clientModal);
|
||||||
inbound: {
|
|
||||||
id: dbInboundId[index],
|
|
||||||
settings: '{"clients": [' + client.toString() + ']}',
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
await this.submit(`/panel/inbound/updateClients`, data, clientModal, true);
|
|
||||||
}else{
|
|
||||||
const data = {
|
|
||||||
id: dbInboundId,
|
|
||||||
settings: '{"clients": [' + client.toString() + ']}',
|
|
||||||
};
|
|
||||||
await this.submit(`/panel/inbound/updateClient/${clientId}`, data, clientModal);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
resetTraffic(dbInboundId) {
|
resetTraffic(dbInboundId) {
|
||||||
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||||
@ -1143,100 +1092,52 @@
|
|||||||
onOk: () => this.submit('/panel/inbound/del/' + dbInboundId),
|
onOk: () => this.submit('/panel/inbound/del/' + dbInboundId),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async delClientHandler(dbInboundId, currentClient, clients = []) {
|
delClient(dbInboundId, client,confirmation = true) {
|
||||||
if (clients.length > 0) {
|
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||||
const deleteRequestData = [];
|
clientId = this.getClientId(dbInbound.protocol, client);
|
||||||
|
|
||||||
for (const client of clients) {
|
|
||||||
const dbInbound = this.dbInbounds.find(inbound => inbound.id === client.inboundId);
|
|
||||||
if (dbInbound) {
|
|
||||||
const inbound = dbInbound.toInbound();
|
|
||||||
if (inbound && inbound.clients && inbound.clients.length === 1) {
|
|
||||||
let newClient = Inbound.Settings.getSettings(inbound.protocol).toString();
|
|
||||||
newClient = JSON.parse(newClient);
|
|
||||||
newClient = newClient && newClient.clients && newClient.clients.length > 0 ? JSON.stringify(newClient.clients[0], null, 2) : null;
|
|
||||||
if (newClient) {
|
|
||||||
const data = {
|
|
||||||
id: client.inboundId,
|
|
||||||
settings: '{"clients": [' + newClient + ']}',
|
|
||||||
};
|
|
||||||
await this.submit(`/panel/inbound/addClient`, data, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteRequestData.push({
|
|
||||||
inboundId: client.inboundId,
|
|
||||||
clientId: client.clientId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await this.submit('/panel/inbound/delGroupClients', deleteRequestData, null, true);
|
|
||||||
} else {
|
|
||||||
const dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
|
||||||
const clientId = this.getClientId(dbInbound.protocol, currentClient);
|
|
||||||
await this.submit(`/panel/inbound/${dbInboundId}/delClient/${clientId}`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
delClient(dbInboundId, currentClient, confirmation = true) {
|
|
||||||
const subGroup = this.subSettings.enable ? this.getSubGroupClients(this.dbInbounds, currentClient) : [];
|
|
||||||
const clients = subGroup && subGroup.clients && subGroup.clients.length > 1 ? subGroup.clients : [];
|
|
||||||
if (confirmation){
|
if (confirmation){
|
||||||
const clientEmails = clients.length > 0 ? clients.map(item => item.email) : currentClient.email
|
|
||||||
this.$confirm({
|
this.$confirm({
|
||||||
title: '{{ i18n "pages.inbounds.deleteClient"}}' + ' ' + clientEmails,
|
title: '{{ i18n "pages.inbounds.deleteClient"}}' + ' ' + client.email,
|
||||||
content: '{{ i18n "pages.inbounds.deleteClientContent"}}',
|
content: '{{ i18n "pages.inbounds.deleteClientContent"}}',
|
||||||
class: themeSwitcher.currentTheme,
|
class: themeSwitcher.currentTheme,
|
||||||
okText: '{{ i18n "delete"}}',
|
okText: '{{ i18n "delete"}}',
|
||||||
cancelText: '{{ i18n "cancel"}}',
|
cancelText: '{{ i18n "cancel"}}',
|
||||||
onOk: () => this.delClientHandler(dbInboundId, currentClient, clients),
|
onOk: () => this.submit(`/panel/inbound/${dbInboundId}/delClient/${clientId}`),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.delClientHandler(dbInboundId, currentClient, clients)
|
this.submit(`/panel/inbound/${dbInboundId}/delClient/${clientId}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getSubGroupClients(dbInbounds, currentClient) {
|
getSubGroupClients(dbInbounds, currentClient) {
|
||||||
const response = {
|
const response = {
|
||||||
inbounds: [],
|
inbounds: [],
|
||||||
clients: [],
|
clients: [],
|
||||||
editIds: [],
|
editIds: []
|
||||||
};
|
|
||||||
|
|
||||||
if (!Array.isArray(dbInbounds) || dbInbounds.length === 0) {
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
if (!currentClient || !currentClient.subId) {
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
dbInbounds.forEach((dbInboundItem) => {
|
|
||||||
try {
|
|
||||||
const dbInbound = new DBInbound(dbInboundItem);
|
|
||||||
if (!dbInbound) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
if (dbInbounds && dbInbounds.length > 0 && currentClient) {
|
||||||
const inbound = dbInbound.toInbound();
|
dbInbounds.forEach((dbInboundItem) => {
|
||||||
if (!inbound || !Array.isArray(inbound.clients)) {
|
const dbInbound = new DBInbound(dbInboundItem);
|
||||||
return;
|
if (dbInbound) {
|
||||||
|
const inbound = dbInbound.toInbound();
|
||||||
|
if (inbound) {
|
||||||
|
const clients = inbound.clients;
|
||||||
|
if (clients.length > 0) {
|
||||||
|
clients.forEach((client) => {
|
||||||
|
if (client['subId'] === currentClient['subId']) {
|
||||||
|
client['inboundId'] = dbInboundItem.id
|
||||||
|
client['clientId'] = this.getClientId(dbInbound.protocol, client)
|
||||||
|
response.inbounds.push(dbInboundItem.id)
|
||||||
|
response.clients.push(client)
|
||||||
|
response.editIds.push(client['clientId'])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
return response;
|
||||||
inbound.clients.forEach((client) => {
|
},
|
||||||
if (client.subId === currentClient.subId) {
|
|
||||||
client.inboundId = dbInboundItem.id;
|
|
||||||
client.clientId = this.getClientId(dbInbound.protocol, client);
|
|
||||||
|
|
||||||
response.inbounds.push(dbInboundItem.id);
|
|
||||||
response.clients.push(client);
|
|
||||||
response.editIds.push(client.clientId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error processing dbInboundItem:", dbInboundItem, error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return response;
|
|
||||||
},
|
|
||||||
getClientId(protocol, client) {
|
getClientId(protocol, client) {
|
||||||
switch (protocol) {
|
switch (protocol) {
|
||||||
case Protocols.TROJAN: return client.password;
|
case Protocols.TROJAN: return client.password;
|
||||||
@ -1264,10 +1165,10 @@
|
|||||||
}
|
}
|
||||||
return newDbInbound;
|
return newDbInbound;
|
||||||
},
|
},
|
||||||
showQrcode(dbInboundId, client, isJustSub = false) {
|
showQrcode(dbInboundId, client) {
|
||||||
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||||
newDbInbound = this.checkFallback(dbInbound);
|
newDbInbound = this.checkFallback(dbInbound);
|
||||||
qrModal.show('{{ i18n "qrCode"}}', newDbInbound, client, isJustSub);
|
qrModal.show('{{ i18n "qrCode"}}', newDbInbound, client);
|
||||||
},
|
},
|
||||||
showInfo(dbInboundId, client) {
|
showInfo(dbInboundId, client) {
|
||||||
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||||
@ -1287,61 +1188,36 @@
|
|||||||
},
|
},
|
||||||
async switchEnableClient(dbInboundId, client) {
|
async switchEnableClient(dbInboundId, client) {
|
||||||
this.loading()
|
this.loading()
|
||||||
const subGroup = this.subSettings.enable ? this.getSubGroupClients(this.dbInbounds, client) : [];
|
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||||
if (subGroup && subGroup.clients && subGroup.clients.length > 0){
|
inbound = dbInbound.toInbound();
|
||||||
await this.updateClient(subGroup.clients.map(item => {
|
clients = inbound.clients;
|
||||||
item.enable = !item.enable
|
index = this.findIndexOfClient(dbInbound.protocol, clients, client);
|
||||||
return item
|
clients[index].enable = !clients[index].enable;
|
||||||
}), subGroup.inbounds, subGroup.editIds);
|
clientId = this.getClientId(dbInbound.protocol, clients[index]);
|
||||||
}else{
|
await this.updateClient(clients[index], dbInboundId, clientId);
|
||||||
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
|
||||||
inbound = dbInbound.toInbound();
|
|
||||||
clients = inbound.clients;
|
|
||||||
index = this.findIndexOfClient(dbInbound.protocol, clients, client);
|
|
||||||
clients[index].enable = !clients[index].enable;
|
|
||||||
clientId = this.getClientId(dbInbound.protocol, clients[index]);
|
|
||||||
await this.updateClient(clients[index], dbInboundId, clientId);
|
|
||||||
}
|
|
||||||
this.loading(false);
|
this.loading(false);
|
||||||
},
|
},
|
||||||
async submit(url, data, model, isJson = false) {
|
async submit(url, data, modal) {
|
||||||
const msg = isJson ? await HttpUtil.postWithModalJson(url, data, model) : await HttpUtil.postWithModal(url, data, model);
|
const msg = await HttpUtil.postWithModal(url, data, modal);
|
||||||
if (msg.success) {
|
if (msg.success) {
|
||||||
await this.getDBInbounds();
|
await this.getDBInbounds();
|
||||||
}
|
}
|
||||||
return msg
|
|
||||||
},
|
},
|
||||||
getInboundClients(dbInbound) {
|
getInboundClients(dbInbound) {
|
||||||
return dbInbound.toInbound().clients;
|
return dbInbound.toInbound().clients;
|
||||||
},
|
},
|
||||||
resetClientTrafficHandler(client, dbInboundId, clients = []) {
|
|
||||||
if (clients.length > 0){
|
|
||||||
const resetRequests = clients
|
|
||||||
.filter(client => {
|
|
||||||
const inbound = this.dbInbounds.find(inbound => inbound.id === client.inboundId);
|
|
||||||
return inbound && this.hasClientStats(inbound, client.email);
|
|
||||||
}).map(client => ({ inboundId: client.inboundId, email: client.email}));
|
|
||||||
|
|
||||||
this.submit('/panel/inbound/resetGroupClientTraffic', resetRequests, null, true)
|
|
||||||
}else {
|
|
||||||
this.submit('/panel/inbound/' + dbInboundId + '/resetClientTraffic/' + client.email);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
resetClientTraffic(client, dbInboundId, confirmation = true) {
|
resetClientTraffic(client, dbInboundId, confirmation = true) {
|
||||||
const subGroup = this.subSettings.enable ? this.getSubGroupClients(this.dbInbounds, client) : [];
|
|
||||||
const clients = subGroup && subGroup.clients && subGroup.clients.length > 1 ? subGroup.clients : [];
|
|
||||||
if (confirmation){
|
if (confirmation){
|
||||||
const clientEmails = clients.length > 0 ? clients.map(item => item.email) : client.email
|
|
||||||
this.$confirm({
|
this.$confirm({
|
||||||
title: '{{ i18n "pages.inbounds.resetTraffic"}}' + ' ' + clientEmails,
|
title: '{{ i18n "pages.inbounds.resetTraffic"}}' + ' ' + client.email,
|
||||||
content: '{{ i18n "pages.inbounds.resetTrafficContent"}}',
|
content: '{{ i18n "pages.inbounds.resetTrafficContent"}}',
|
||||||
class: themeSwitcher.currentTheme,
|
class: themeSwitcher.currentTheme,
|
||||||
okText: '{{ i18n "reset"}}',
|
okText: '{{ i18n "reset"}}',
|
||||||
cancelText: '{{ i18n "cancel"}}',
|
cancelText: '{{ i18n "cancel"}}',
|
||||||
onOk: () => this.resetClientTrafficHandler(client, dbInboundId, clients),
|
onOk: () => this.submit('/panel/inbound/' + dbInboundId + '/resetClientTraffic/' + client.email),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.resetClientTrafficHandler(client, dbInboundId, clients);
|
this.submit('/panel/inbound/' + dbInboundId + '/resetClientTraffic/' + client.email);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
resetAllTraffic() {
|
resetAllTraffic() {
|
||||||
@ -1377,10 +1253,6 @@
|
|||||||
isExpiry(dbInbound, index) {
|
isExpiry(dbInbound, index) {
|
||||||
return dbInbound.toInbound().isExpiry(index);
|
return dbInbound.toInbound().isExpiry(index);
|
||||||
},
|
},
|
||||||
hasClientStats(dbInbound, email) {
|
|
||||||
if (email.length == 0) return 0;
|
|
||||||
return !!dbInbound.clientStats.find(stats => stats.email === email);
|
|
||||||
},
|
|
||||||
getUpStats(dbInbound, email) {
|
getUpStats(dbInbound, email) {
|
||||||
if (email.length == 0) return 0;
|
if (email.length == 0) return 0;
|
||||||
clientStats = dbInbound.clientStats.find(stats => stats.email === email);
|
clientStats = dbInbound.clientStats.find(stats => stats.email === email);
|
||||||
|
@ -268,7 +268,6 @@
|
|||||||
<a-tab-pane key="4" tab='{{ i18n "pages.settings.subSettings" }}'>
|
<a-tab-pane key="4" tab='{{ i18n "pages.settings.subSettings" }}'>
|
||||||
<a-list item-layout="horizontal">
|
<a-list item-layout="horizontal">
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.settings.subEnable"}}' desc='{{ i18n "pages.settings.subEnableDesc"}}' v-model="allSetting.subEnable"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.settings.subEnable"}}' desc='{{ i18n "pages.settings.subEnableDesc"}}' v-model="allSetting.subEnable"></setting-list-item>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.settings.subSyncEnable"}}' desc='{{ i18n "pages.settings.subSyncEnableDesc"}}' v-model="allSetting.subSyncEnable"></setting-list-item>
|
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.settings.subEncrypt"}}' desc='{{ i18n "pages.settings.subEncryptDesc"}}' v-model="allSetting.subEncrypt"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.settings.subEncrypt"}}' desc='{{ i18n "pages.settings.subEncryptDesc"}}' v-model="allSetting.subEncrypt"></setting-list-item>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.settings.subShowInfo"}}' desc='{{ i18n "pages.settings.subShowInfoDesc"}}' v-model="allSetting.subShowInfo"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.settings.subShowInfo"}}' desc='{{ i18n "pages.settings.subShowInfoDesc"}}' v-model="allSetting.subShowInfo"></setting-list-item>
|
||||||
<setting-list-item type="text" title='{{ i18n "pages.settings.subListen"}}' desc='{{ i18n "pages.settings.subListenDesc"}}' v-model="allSetting.subListen"></setting-list-item>
|
<setting-list-item type="text" title='{{ i18n "pages.settings.subListen"}}' desc='{{ i18n "pages.settings.subListenDesc"}}' v-model="allSetting.subListen"></setting-list-item>
|
||||||
|
@ -1,178 +0,0 @@
|
|||||||
package job
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"x-ui/database"
|
|
||||||
"x-ui/database/model"
|
|
||||||
"x-ui/logger"
|
|
||||||
"x-ui/xray"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SyncClientTrafficJob struct {
|
|
||||||
subClientsCollection map[string][]string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewClientTrafficSyncJob() *SyncClientTrafficJob {
|
|
||||||
return new(SyncClientTrafficJob)
|
|
||||||
}
|
|
||||||
func (j *SyncClientTrafficJob) Run() {
|
|
||||||
// Step 1: Group clients by SubID
|
|
||||||
subClientsCollection := j.collectClientsGroupedBySubId()
|
|
||||||
|
|
||||||
// Step 2: Sync client traffics for each SubID group
|
|
||||||
for subId, emails := range subClientsCollection {
|
|
||||||
err := j.syncClientTraffics(map[string][]string{subId: emails})
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Failed to sync traffics for SubID ", subId, ": ", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// collectClientsGroupedBySubId groups clients by their SubIDs
|
|
||||||
func (j *SyncClientTrafficJob) collectClientsGroupedBySubId() map[string][]string {
|
|
||||||
db := database.GetDB()
|
|
||||||
result := make(map[string][]string)
|
|
||||||
|
|
||||||
// Fetch all inbounds
|
|
||||||
var inbounds []*model.Inbound
|
|
||||||
if err := db.Model(&model.Inbound{}).Find(&inbounds).Error; err != nil {
|
|
||||||
logger.Error("Error fetching inbounds: ", err)
|
|
||||||
return result // Return empty map on error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process each inbound
|
|
||||||
for _, inbound := range inbounds {
|
|
||||||
if inbound.Settings == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
settingsMap, err := parseSettings(inbound.Settings, uint(inbound.Id))
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
clients, ok := settingsMap["clients"].([]interface{})
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
processClients(clients, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove SubIDs with one or fewer emails
|
|
||||||
filterSingleEmailSubIDs(result)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseSettings unmarshals the JSON settings and returns it as a map
|
|
||||||
func parseSettings(settings string, inboundID uint) (map[string]interface{}, error) {
|
|
||||||
if !json.Valid([]byte(settings)) {
|
|
||||||
return nil, fmt.Errorf("Invalid JSON format in Settings for inbound ID %d", inboundID)
|
|
||||||
}
|
|
||||||
|
|
||||||
var tempData map[string]interface{}
|
|
||||||
if err := json.Unmarshal([]byte(settings), &tempData); err != nil {
|
|
||||||
return nil, fmt.Errorf("Error unmarshalling settings for inbound ID %d: %v", inboundID, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return tempData, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// processClients extracts SubID and email from the clients and populates the result map
|
|
||||||
func processClients(clients []interface{}, result map[string][]string) {
|
|
||||||
for _, client := range clients {
|
|
||||||
clientMap, ok := client.(map[string]interface{})
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
subId, ok := clientMap["subId"].(string)
|
|
||||||
if !ok || subId == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
email, ok := clientMap["email"].(string)
|
|
||||||
if !ok || email == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
result[subId] = append(result[subId], email)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// filterSingleEmailSubIDs removes SubIDs with one or fewer emails from the result map
|
|
||||||
func filterSingleEmailSubIDs(result map[string][]string) {
|
|
||||||
for subId, emails := range result {
|
|
||||||
if len(emails) <= 1 {
|
|
||||||
delete(result, subId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// syncClientTraffics synchronizes traffic data for each SubID group
|
|
||||||
func (j *SyncClientTrafficJob) syncClientTraffics(result map[string][]string) error {
|
|
||||||
for subId, emails := range result {
|
|
||||||
db := database.GetDB()
|
|
||||||
|
|
||||||
// Step 1: Calculate maxUp and maxDown (outside transaction)
|
|
||||||
var maxUp, maxDown int64
|
|
||||||
err := calculateMaxTraffic(db, emails, &maxUp, &maxDown)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Failed to calculate max traffic for SubID ", subId, ": ", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step 2: Update traffic data with retry mechanism
|
|
||||||
err = retryOperation(func() error {
|
|
||||||
return updateTraffic(db, emails, maxUp, maxDown)
|
|
||||||
}, 5, 100*time.Millisecond)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("Failed to update client traffics for SubID ", subId, ": ", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculateMaxTraffic calculates max up and down traffic for a group of emails
|
|
||||||
func calculateMaxTraffic(db *gorm.DB, emails []string, maxUp, maxDown *int64) error {
|
|
||||||
return db.Model(&xray.ClientTraffic{}).
|
|
||||||
Where("email IN ?", emails).
|
|
||||||
Select("MAX(up) AS max_up, MAX(down) AS max_down").
|
|
||||||
Row().
|
|
||||||
Scan(maxUp, maxDown)
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateTraffic updates the traffic data in the database within a transaction
|
|
||||||
func updateTraffic(db *gorm.DB, emails []string, maxUp, maxDown int64) error {
|
|
||||||
return db.Transaction(func(tx *gorm.DB) error {
|
|
||||||
return tx.Model(&xray.ClientTraffic{}).
|
|
||||||
Where("email IN ?", emails).
|
|
||||||
Updates(map[string]interface{}{
|
|
||||||
"up": maxUp,
|
|
||||||
"down": maxDown,
|
|
||||||
}).Error
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// retryOperation retries an operation multiple times with a delay
|
|
||||||
func retryOperation(operation func() error, maxRetries int, delay time.Duration) error {
|
|
||||||
var err error
|
|
||||||
for i := 0; i < maxRetries; i++ {
|
|
||||||
err = operation()
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
logger.Info(fmt.Sprintf("Retry %d/%d failed: %v", i+1, maxRetries, err))
|
|
||||||
time.Sleep(delay)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
@ -50,7 +50,6 @@ var defaultValueMap = map[string]string{
|
|||||||
"tgLang": "en-US",
|
"tgLang": "en-US",
|
||||||
"secretEnable": "false",
|
"secretEnable": "false",
|
||||||
"subEnable": "false",
|
"subEnable": "false",
|
||||||
"subSyncEnable": "true",
|
|
||||||
"subListen": "",
|
"subListen": "",
|
||||||
"subPort": "2096",
|
"subPort": "2096",
|
||||||
"subPath": "/sub/",
|
"subPath": "/sub/",
|
||||||
@ -417,14 +416,6 @@ func (s *SettingService) GetSubEnable() (bool, error) {
|
|||||||
return s.getBool("subEnable")
|
return s.getBool("subEnable")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SettingService) GetSubSyncEnable() (bool, error) {
|
|
||||||
return s.getBool("subSyncEnable")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SettingService) SetSubSyncEnable(value bool) error {
|
|
||||||
return s.setBool("subSyncEnable", value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SettingService) GetSubListen() (string, error) {
|
func (s *SettingService) GetSubListen() (string, error) {
|
||||||
return s.getString("subListen")
|
return s.getString("subListen")
|
||||||
}
|
}
|
||||||
@ -553,7 +544,6 @@ func (s *SettingService) GetDefaultSettings(host string) (interface{}, error) {
|
|||||||
"defaultKey": func() (interface{}, error) { return s.GetKeyFile() },
|
"defaultKey": func() (interface{}, error) { return s.GetKeyFile() },
|
||||||
"tgBotEnable": func() (interface{}, error) { return s.GetTgbotEnabled() },
|
"tgBotEnable": func() (interface{}, error) { return s.GetTgbotEnabled() },
|
||||||
"subEnable": func() (interface{}, error) { return s.GetSubEnable() },
|
"subEnable": func() (interface{}, error) { return s.GetSubEnable() },
|
||||||
"subSyncEnable": func() (interface{}, error) { return s.GetSubSyncEnable() },
|
|
||||||
"subURI": func() (interface{}, error) { return s.GetSubURI() },
|
"subURI": func() (interface{}, error) { return s.GetSubURI() },
|
||||||
"subJsonURI": func() (interface{}, error) { return s.GetSubJsonURI() },
|
"subJsonURI": func() (interface{}, error) { return s.GetSubJsonURI() },
|
||||||
"remarkModel": func() (interface{}, error) { return s.GetRemarkModel() },
|
"remarkModel": func() (interface{}, error) { return s.GetRemarkModel() },
|
||||||
|
@ -190,9 +190,6 @@
|
|||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "Add Client"
|
"add" = "Add Client"
|
||||||
"groupAdd" = "Add subscription user"
|
|
||||||
"isGroupEdit" = "Group editing"
|
|
||||||
"isGroupEditDesc" = "All clients with the same subscription are edited"
|
|
||||||
"edit" = "Edit Client"
|
"edit" = "Edit Client"
|
||||||
"submitAdd" = "Add Client"
|
"submitAdd" = "Add Client"
|
||||||
"submitEdit" = "Save Changes"
|
"submitEdit" = "Save Changes"
|
||||||
@ -290,8 +287,6 @@
|
|||||||
"subSettings" = "Subscription"
|
"subSettings" = "Subscription"
|
||||||
"subEnable" = "Enable Subscription Service"
|
"subEnable" = "Enable Subscription Service"
|
||||||
"subEnableDesc" = "Enables the subscription service."
|
"subEnableDesc" = "Enables the subscription service."
|
||||||
"subSyncEnable" = "Enable Subscription Sync"
|
|
||||||
"subSyncEnableDesc" = "Traffic from clients with the same subscription will be synchronized every 10 seconds."
|
|
||||||
"subListen" = "Listen IP"
|
"subListen" = "Listen IP"
|
||||||
"subListenDesc" = "The IP address for the subscription service. (leave blank to listen on all IPs)"
|
"subListenDesc" = "The IP address for the subscription service. (leave blank to listen on all IPs)"
|
||||||
"subPort" = "Listen Port"
|
"subPort" = "Listen Port"
|
||||||
|
@ -190,7 +190,6 @@
|
|||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "Agregar Cliente"
|
"add" = "Agregar Cliente"
|
||||||
"groupAdd" = "Agregar usuario de suscripción"
|
|
||||||
"edit" = "Editar Cliente"
|
"edit" = "Editar Cliente"
|
||||||
"submitAdd" = "Agregar Cliente"
|
"submitAdd" = "Agregar Cliente"
|
||||||
"submitEdit" = "Guardar Cambios"
|
"submitEdit" = "Guardar Cambios"
|
||||||
@ -288,8 +287,6 @@
|
|||||||
"subSettings" = "Suscripción"
|
"subSettings" = "Suscripción"
|
||||||
"subEnable" = "Habilitar Servicio"
|
"subEnable" = "Habilitar Servicio"
|
||||||
"subEnableDesc" = "Función de suscripción con configuración separada."
|
"subEnableDesc" = "Función de suscripción con configuración separada."
|
||||||
"subSyncEnable" = "Habilitar sincronización de suscripciones"
|
|
||||||
"subSyncEnableDesc" = "El tráfico de los clientes con la misma suscripción se sincronizará cada 10 segundos."
|
|
||||||
"subListen" = "Listening IP"
|
"subListen" = "Listening IP"
|
||||||
"subListenDesc" = "Dejar en blanco por defecto para monitorear todas las IPs."
|
"subListenDesc" = "Dejar en blanco por defecto para monitorear todas las IPs."
|
||||||
"subPort" = "Puerto de Suscripción"
|
"subPort" = "Puerto de Suscripción"
|
||||||
|
@ -190,9 +190,6 @@
|
|||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "کاربر جدید"
|
"add" = "کاربر جدید"
|
||||||
"groupAdd" = "افزودن کاربر سابسکریپشن"
|
|
||||||
"isGroupEdit" = "ویرایش گروهی"
|
|
||||||
"isGroupEditDesc" = "همه کاربران با سابسکریپشن یکسان ویرایش می شوند"
|
|
||||||
"edit" = "ویرایش کاربر"
|
"edit" = "ویرایش کاربر"
|
||||||
"submitAdd" = "اضافه کردن"
|
"submitAdd" = "اضافه کردن"
|
||||||
"submitEdit" = "ذخیره تغییرات"
|
"submitEdit" = "ذخیره تغییرات"
|
||||||
@ -290,8 +287,6 @@
|
|||||||
"subSettings" = "سابسکریپشن"
|
"subSettings" = "سابسکریپشن"
|
||||||
"subEnable" = "فعالسازی سرویس سابسکریپشن"
|
"subEnable" = "فعالسازی سرویس سابسکریپشن"
|
||||||
"subEnableDesc" = "سرویس سابسکریپشن را فعالمیکند"
|
"subEnableDesc" = "سرویس سابسکریپشن را فعالمیکند"
|
||||||
"subSyncEnable" = "فعالسازی همگام سازی سابسکریپشن"
|
|
||||||
"subSyncEnableDesc" = "ترافیک کلاینت هایی که سابسکریپشن یکسان دارند هر ۱۰ ثانیه همگام میشوند."
|
|
||||||
"subListen" = "آدرس آیپی"
|
"subListen" = "آدرس آیپی"
|
||||||
"subListenDesc" = "آدرس آیپی برای سرویس سابسکریپشن. برای گوش دادن بهتمام آیپیها خالیبگذارید"
|
"subListenDesc" = "آدرس آیپی برای سرویس سابسکریپشن. برای گوش دادن بهتمام آیپیها خالیبگذارید"
|
||||||
"subPort" = "پورت"
|
"subPort" = "پورت"
|
||||||
|
@ -190,9 +190,6 @@
|
|||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "Tambah Klien"
|
"add" = "Tambah Klien"
|
||||||
"groupAdd" = "Tambahkan pengguna langganan"
|
|
||||||
"isGroupEdit" = "Pengeditan grup"
|
|
||||||
"isGroupEditDesc" = "Semua klien dengan langganan yang sama akan diedit"
|
|
||||||
"edit" = "Edit Klien"
|
"edit" = "Edit Klien"
|
||||||
"submitAdd" = "Tambah Klien"
|
"submitAdd" = "Tambah Klien"
|
||||||
"submitEdit" = "Simpan Perubahan"
|
"submitEdit" = "Simpan Perubahan"
|
||||||
@ -290,8 +287,6 @@
|
|||||||
"subSettings" = "Langganan"
|
"subSettings" = "Langganan"
|
||||||
"subEnable" = "Aktifkan Layanan Langganan"
|
"subEnable" = "Aktifkan Layanan Langganan"
|
||||||
"subEnableDesc" = "Mengaktifkan layanan langganan."
|
"subEnableDesc" = "Mengaktifkan layanan langganan."
|
||||||
"subSyncEnable" = "Aktifkan Sinkronisasi Langganan"
|
|
||||||
"subSyncEnableDesc" = "Lalu lintas dari klien dengan langganan yang sama akan disinkronkan setiap 10 detik."
|
|
||||||
"subListen" = "IP Pendengar"
|
"subListen" = "IP Pendengar"
|
||||||
"subListenDesc" = "Alamat IP untuk layanan langganan. (biarkan kosong untuk mendengarkan semua IP)"
|
"subListenDesc" = "Alamat IP untuk layanan langganan. (biarkan kosong untuk mendengarkan semua IP)"
|
||||||
"subPort" = "Port Pendengar"
|
"subPort" = "Port Pendengar"
|
||||||
|
@ -190,9 +190,6 @@
|
|||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "クライアント追加"
|
"add" = "クライアント追加"
|
||||||
"groupAdd" = "サブスクリプション ユーザーの追加"
|
|
||||||
"isGroupEdit" = "グループの編集"
|
|
||||||
"isGroupEditDesc" = "同じサブスクリプションを持つすべてのクライアントが編集されます"
|
|
||||||
"edit" = "クライアント編集"
|
"edit" = "クライアント編集"
|
||||||
"submitAdd" = "クライアント追加"
|
"submitAdd" = "クライアント追加"
|
||||||
"submitEdit" = "変更を保存"
|
"submitEdit" = "変更を保存"
|
||||||
@ -290,8 +287,6 @@
|
|||||||
"subSettings" = "サブスクリプション設定"
|
"subSettings" = "サブスクリプション設定"
|
||||||
"subEnable" = "サブスクリプションサービスを有効にする"
|
"subEnable" = "サブスクリプションサービスを有効にする"
|
||||||
"subEnableDesc" = "サブスクリプションサービス機能を有効にする"
|
"subEnableDesc" = "サブスクリプションサービス機能を有効にする"
|
||||||
"subSyncEnable" = "サブスクリプション同期を有効にする"
|
|
||||||
"subSyncEnableDesc" = "同じサブスクリプションを持つクライアントからのトラフィックは 10 秒ごとに同期されます。"
|
|
||||||
"subListen" = "監視IP"
|
"subListen" = "監視IP"
|
||||||
"subListenDesc" = "サブスクリプションサービスが監視するIPアドレス(空白にするとすべてのIPを監視)"
|
"subListenDesc" = "サブスクリプションサービスが監視するIPアドレス(空白にするとすべてのIPを監視)"
|
||||||
"subPort" = "監視ポート"
|
"subPort" = "監視ポート"
|
||||||
|
@ -190,9 +190,6 @@
|
|||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "Adicionar Cliente"
|
"add" = "Adicionar Cliente"
|
||||||
"groupAdd" = "Adicionar usuário de assinatura"
|
|
||||||
"isGroupEdit" = "Edição de grupo"
|
|
||||||
"isGroupEditDesc" = "Todos os clientes com a mesma assinatura são editados"
|
|
||||||
"edit" = "Editar Cliente"
|
"edit" = "Editar Cliente"
|
||||||
"submitAdd" = "Adicionar Cliente"
|
"submitAdd" = "Adicionar Cliente"
|
||||||
"submitEdit" = "Salvar Alterações"
|
"submitEdit" = "Salvar Alterações"
|
||||||
@ -290,8 +287,6 @@
|
|||||||
"subSettings" = "Assinatura"
|
"subSettings" = "Assinatura"
|
||||||
"subEnable" = "Ativar Serviço de Assinatura"
|
"subEnable" = "Ativar Serviço de Assinatura"
|
||||||
"subEnableDesc" = "Ativa o serviço de assinatura."
|
"subEnableDesc" = "Ativa o serviço de assinatura."
|
||||||
"subSyncEnable" = "Habilitar sincronização de assinatura"
|
|
||||||
"subSyncEnableDesc" = "O tráfego de clientes com a mesma assinatura será sincronizado a cada 10 segundos."
|
|
||||||
"subListen" = "IP de Escuta"
|
"subListen" = "IP de Escuta"
|
||||||
"subListenDesc" = "O endereço IP para o serviço de assinatura. (deixe em branco para escutar em todos os IPs)"
|
"subListenDesc" = "O endereço IP para o serviço de assinatura. (deixe em branco para escutar em todos os IPs)"
|
||||||
"subPort" = "Porta de Escuta"
|
"subPort" = "Porta de Escuta"
|
||||||
|
@ -190,9 +190,6 @@
|
|||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "Добавить пользователя"
|
"add" = "Добавить пользователя"
|
||||||
"groupAdd" = "Добавить пользователя подписки"
|
|
||||||
"isGroupEdit" = "Групповое редактирование"
|
|
||||||
"isGroupEditDesc" = "Все клиенты с одинаковой подпиской редактируются"
|
|
||||||
"edit" = "Редактировать пользователя"
|
"edit" = "Редактировать пользователя"
|
||||||
"submitAdd" = "Добавить пользователя"
|
"submitAdd" = "Добавить пользователя"
|
||||||
"submitEdit" = "Сохранить изменения"
|
"submitEdit" = "Сохранить изменения"
|
||||||
@ -290,8 +287,6 @@
|
|||||||
"subSettings" = "Подписка"
|
"subSettings" = "Подписка"
|
||||||
"subEnable" = "Включить службу"
|
"subEnable" = "Включить службу"
|
||||||
"subEnableDesc" = "Функция подписки с отдельной конфигурацией"
|
"subEnableDesc" = "Функция подписки с отдельной конфигурацией"
|
||||||
"subSyncEnable" = "Включить синхронизацию подписки"
|
|
||||||
"subSyncEnableDesc" = "Трафик от клиентов с одинаковой подпиской будет синхронизироваться каждые 10 секунд."
|
|
||||||
"subListen" = "Прослушивание IP"
|
"subListen" = "Прослушивание IP"
|
||||||
"subListenDesc" = "Оставьте пустым по умолчанию, чтобы отслеживать все IP-адреса"
|
"subListenDesc" = "Оставьте пустым по умолчанию, чтобы отслеживать все IP-адреса"
|
||||||
"subPort" = "Порт подписки"
|
"subPort" = "Порт подписки"
|
||||||
|
@ -190,9 +190,6 @@
|
|||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "Müşteri Ekle"
|
"add" = "Müşteri Ekle"
|
||||||
"groupAdd" = "Abonelik kullanıcısı ekle"
|
|
||||||
"isGroupEdit" = "Grup düzenleme"
|
|
||||||
"isGroupEditDesc" = "Aynı aboneliğe sahip tüm istemciler düzenlendi"
|
|
||||||
"edit" = "Müşteriyi Düzenle"
|
"edit" = "Müşteriyi Düzenle"
|
||||||
"submitAdd" = "Müşteri Ekle"
|
"submitAdd" = "Müşteri Ekle"
|
||||||
"submitEdit" = "Değişiklikleri Kaydet"
|
"submitEdit" = "Değişiklikleri Kaydet"
|
||||||
@ -290,8 +287,6 @@
|
|||||||
"subSettings" = "Abonelik"
|
"subSettings" = "Abonelik"
|
||||||
"subEnable" = "Abonelik Hizmetini Etkinleştir"
|
"subEnable" = "Abonelik Hizmetini Etkinleştir"
|
||||||
"subEnableDesc" = "Abonelik hizmetini etkinleştirir."
|
"subEnableDesc" = "Abonelik hizmetini etkinleştirir."
|
||||||
"subSyncEnable" = "Abonelik Senkronizasyonunu Etkinleştir"
|
|
||||||
"subSyncEnableDesc" = "Aynı aboneliğe sahip istemcilerden gelen trafik her 10 saniyede bir senkronize edilecektir."
|
|
||||||
"subListen" = "Dinleme IP"
|
"subListen" = "Dinleme IP"
|
||||||
"subListenDesc" = "Abonelik hizmeti için IP adresi. (tüm IP'leri dinlemek için boş bırakın)"
|
"subListenDesc" = "Abonelik hizmeti için IP adresi. (tüm IP'leri dinlemek için boş bırakın)"
|
||||||
"subPort" = "Dinleme Portu"
|
"subPort" = "Dinleme Portu"
|
||||||
|
@ -190,9 +190,6 @@
|
|||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "Додати клієнта"
|
"add" = "Додати клієнта"
|
||||||
"groupAdd" = "Додати підписаного користувача"
|
|
||||||
"isGroupEdit" = "Редагування групи"
|
|
||||||
"isGroupEditDesc" = "Всі клієнти з однаковою підпискою редагуються"
|
|
||||||
"edit" = "Редагувати клієнта"
|
"edit" = "Редагувати клієнта"
|
||||||
"submitAdd" = "Додати клієнта"
|
"submitAdd" = "Додати клієнта"
|
||||||
"submitEdit" = "Зберегти зміни"
|
"submitEdit" = "Зберегти зміни"
|
||||||
@ -290,8 +287,6 @@
|
|||||||
"subSettings" = "Підписка"
|
"subSettings" = "Підписка"
|
||||||
"subEnable" = "Увімкнути службу підписки"
|
"subEnable" = "Увімкнути службу підписки"
|
||||||
"subEnableDesc" = "Вмикає службу підписки."
|
"subEnableDesc" = "Вмикає службу підписки."
|
||||||
"subSyncEnable" = "Увімкнути синхронізацію підписки"
|
|
||||||
"subSyncEnableDesc" = "Трафік від клієнтів з однаковою підпискою буде синхронізовано кожні 10 секунд."
|
|
||||||
"subListen" = "Слухати IP"
|
"subListen" = "Слухати IP"
|
||||||
"subListenDesc" = "IP-адреса для служби підписки. (залиште порожнім, щоб слухати всі IP-адреси)"
|
"subListenDesc" = "IP-адреса для служби підписки. (залиште порожнім, щоб слухати всі IP-адреси)"
|
||||||
"subPort" = "Слухати порт"
|
"subPort" = "Слухати порт"
|
||||||
|
@ -190,9 +190,6 @@
|
|||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "Thêm người dùng"
|
"add" = "Thêm người dùng"
|
||||||
"groupAdd" = "Thêm người dùng đăng ký"
|
|
||||||
"isGroupEdit" = "Chỉnh sửa nhóm"
|
|
||||||
"isGroupEditDesc" = "Tất cả người dùng có cùng đăng ký đều có thể được chỉnh sửa"
|
|
||||||
"edit" = "Chỉnh sửa người dùng"
|
"edit" = "Chỉnh sửa người dùng"
|
||||||
"submitAdd" = "Thêm"
|
"submitAdd" = "Thêm"
|
||||||
"submitEdit" = "Lưu thay đổi"
|
"submitEdit" = "Lưu thay đổi"
|
||||||
@ -290,8 +287,6 @@
|
|||||||
"subSettings" = "Gói đăng ký"
|
"subSettings" = "Gói đăng ký"
|
||||||
"subEnable" = "Bật dịch vụ"
|
"subEnable" = "Bật dịch vụ"
|
||||||
"subEnableDesc" = "Tính năng gói đăng ký với cấu hình riêng"
|
"subEnableDesc" = "Tính năng gói đăng ký với cấu hình riêng"
|
||||||
"subSyncEnable" = "Bật đồng bộ đăng ký"
|
|
||||||
"subSyncEnableDesc" = "Lưu lượng truy cập từ các máy khách có cùng đăng ký sẽ được đồng bộ sau mỗi 10 giây."
|
|
||||||
"subListen" = "Listening IP"
|
"subListen" = "Listening IP"
|
||||||
"subListenDesc" = "Mặc định để trống để nghe tất cả các IP"
|
"subListenDesc" = "Mặc định để trống để nghe tất cả các IP"
|
||||||
"subPort" = "Cổng gói đăng ký"
|
"subPort" = "Cổng gói đăng ký"
|
||||||
|
@ -190,9 +190,6 @@
|
|||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "添加客户端"
|
"add" = "添加客户端"
|
||||||
"groupAdd" = "添加订阅用户"
|
|
||||||
"isGroupEdit" = "群组编辑"
|
|
||||||
"isGroupEditDesc" = "所有具有相同订阅的客户端均被编辑"
|
|
||||||
"edit" = "编辑客户端"
|
"edit" = "编辑客户端"
|
||||||
"submitAdd" = "添加客户端"
|
"submitAdd" = "添加客户端"
|
||||||
"submitEdit" = "保存修改"
|
"submitEdit" = "保存修改"
|
||||||
@ -290,8 +287,6 @@
|
|||||||
"subSettings" = "订阅设置"
|
"subSettings" = "订阅设置"
|
||||||
"subEnable" = "启用订阅服务"
|
"subEnable" = "启用订阅服务"
|
||||||
"subEnableDesc" = "启用订阅服务功能"
|
"subEnableDesc" = "启用订阅服务功能"
|
||||||
"subSyncEnable" = "启用订阅同步"
|
|
||||||
"subSyncEnableDesc" = "具有相同订阅的客户端的流量将每 10 秒同步一次。"
|
|
||||||
"subListen" = "监听 IP"
|
"subListen" = "监听 IP"
|
||||||
"subListenDesc" = "订阅服务监听的 IP 地址(留空表示监听所有 IP)"
|
"subListenDesc" = "订阅服务监听的 IP 地址(留空表示监听所有 IP)"
|
||||||
"subPort" = "监听端口"
|
"subPort" = "监听端口"
|
||||||
|
@ -190,9 +190,6 @@
|
|||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "新增客戶端"
|
"add" = "新增客戶端"
|
||||||
"groupAdd" = "新增訂閱使用者"
|
|
||||||
"isGroupEdit" = "群組編輯"
|
|
||||||
"isGroupEditDesc" = "所有具有相同訂閱的用戶端都被編輯"
|
|
||||||
"edit" = "編輯客戶端"
|
"edit" = "編輯客戶端"
|
||||||
"submitAdd" = "新增客戶端"
|
"submitAdd" = "新增客戶端"
|
||||||
"submitEdit" = "儲存修改"
|
"submitEdit" = "儲存修改"
|
||||||
@ -290,8 +287,6 @@
|
|||||||
"subSettings" = "訂閱設定"
|
"subSettings" = "訂閱設定"
|
||||||
"subEnable" = "啟用訂閱服務"
|
"subEnable" = "啟用訂閱服務"
|
||||||
"subEnableDesc" = "啟用訂閱服務功能"
|
"subEnableDesc" = "啟用訂閱服務功能"
|
||||||
"subSyncEnable" = "啟用訂閱同步"
|
|
||||||
"subSyncEnableDesc" = "來自具有相同訂閱的客戶端的流量將每 10 秒同步一次。"
|
|
||||||
"subListen" = "監聽 IP"
|
"subListen" = "監聽 IP"
|
||||||
"subListenDesc" = "訂閱服務監聽的 IP 地址(留空表示監聽所有 IP)"
|
"subListenDesc" = "訂閱服務監聽的 IP 地址(留空表示監聽所有 IP)"
|
||||||
"subPort" = "監聽埠"
|
"subPort" = "監聽埠"
|
||||||
|
@ -260,13 +260,6 @@ func (s *Server) startTask() {
|
|||||||
s.cron.AddJob("@every 10s", job.NewXrayTrafficJob())
|
s.cron.AddJob("@every 10s", job.NewXrayTrafficJob())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
isSubEnable, err1 := s.settingService.GetSubEnable()
|
|
||||||
isSubSyncEnable, err2 := s.settingService.GetSubSyncEnable()
|
|
||||||
if err1 == nil && err2 == nil && isSubEnable && isSubSyncEnable {
|
|
||||||
// Sync the client traffic with the same SubId every 10 seconds
|
|
||||||
s.cron.AddJob("@every 10s", job.NewClientTrafficSyncJob())
|
|
||||||
}
|
|
||||||
|
|
||||||
// check client ips from log file every 10 sec
|
// check client ips from log file every 10 sec
|
||||||
s.cron.AddJob("@every 10s", job.NewCheckClientIpJob())
|
s.cron.AddJob("@every 10s", job.NewCheckClientIpJob())
|
||||||
|
|
||||||
|
@ -2,9 +2,9 @@ package xray
|
|||||||
|
|
||||||
type ClientTraffic struct {
|
type ClientTraffic struct {
|
||||||
Id int `json:"id" form:"id" gorm:"primaryKey;autoIncrement"`
|
Id int `json:"id" form:"id" gorm:"primaryKey;autoIncrement"`
|
||||||
InboundId int `json:"inboundId" form:"inboundId" gorm:"index;not null"`
|
InboundId int `json:"inboundId" form:"inboundId"`
|
||||||
Enable bool `json:"enable" form:"enable"`
|
Enable bool `json:"enable" form:"enable"`
|
||||||
Email string `json:"email" form:"email" gorm:"uniqueIndex"`
|
Email string `json:"email" form:"email" gorm:"unique"`
|
||||||
Up int64 `json:"up" form:"up"`
|
Up int64 `json:"up" form:"up"`
|
||||||
Down int64 `json:"down" form:"down"`
|
Down int64 `json:"down" form:"down"`
|
||||||
ExpiryTime int64 `json:"expiryTime" form:"expiryTime"`
|
ExpiryTime int64 `json:"expiryTime" form:"expiryTime"`
|
||||||
|
Loading…
Reference in New Issue
Block a user