update pack 2

This commit is contained in:
MHSanaei
2023-02-18 16:07:32 +03:30
parent fe9844b51b
commit b412df70f1
23 changed files with 212 additions and 220 deletions

View File

@@ -1359,7 +1359,7 @@ Inbound.VmessSettings = class extends Inbound.Settings {
}
};
Inbound.VmessSettings.Vmess = class extends XrayCommonClass {
constructor(id=RandomUtil.randomUUID(), alterId=0, email='', totalGB=0, expiryTime='') {
constructor(id=RandomUtil.randomUUID(), alterId=0, email=RandomUtil.randomText(), totalGB=0, expiryTime='') {
super();
this.id = id;
this.alterId = alterId;
@@ -1441,7 +1441,7 @@ Inbound.VLESSSettings = class extends Inbound.Settings {
};
Inbound.VLESSSettings.VLESS = class extends XrayCommonClass {
constructor(id=RandomUtil.randomUUID(), flow='', email='', totalGB=0, fingerprint = UTLS_FINGERPRINT.UTLS_CHROME, expiryTime='') {
constructor(id=RandomUtil.randomUUID(), flow='', email=RandomUtil.randomText(), totalGB=0, fingerprint = UTLS_FINGERPRINT.UTLS_CHROME, expiryTime='') {
super();
this.id = id;
this.flow = flow;
@@ -1557,7 +1557,7 @@ Inbound.TrojanSettings = class extends Inbound.Settings {
}
};
Inbound.TrojanSettings.Trojan = class extends XrayCommonClass {
constructor(password=RandomUtil.randomSeq(10), flow ='', email='', totalGB=0, expiryTime='') {
constructor(password=RandomUtil.randomSeq(10), flow ='', email=RandomUtil.randomText(), totalGB=0, expiryTime='') {
super();
this.password = password;
this.flow = flow;

View File

@@ -136,6 +136,16 @@ class RandomUtil {
return (c === 'x' ? r : (r & 0x7 | 0x8)).toString(16);
});
}
static randomText() {
var chars = 'abcdefghijklmnopqrstuvwxyz1234567890';
var string = '';
var len = 6 + Math.floor(Math.random() * 5)
for(var ii=0; ii<len; ii++){
string += chars[Math.floor(Math.random() * chars.length)];
}
return string;
}
}
class ObjectUtil {

View File

@@ -12,7 +12,7 @@ type BaseController struct {
func (a *BaseController) checkLogin(c *gin.Context) {
if !session.IsLogin(c) {
if isAjax(c) {
pureJsonMsg(c, false, I18n(c , "pages.login.loginAgain"))
pureJsonMsg(c, false, I18n(c, "pages.login.loginAgain"))
} else {
c.Redirect(http.StatusTemporaryRedirect, c.GetString("base_path"))
}
@@ -22,12 +22,11 @@ func (a *BaseController) checkLogin(c *gin.Context) {
}
}
func I18n(c *gin.Context, name string) string {
anyfunc, _ := c.Get("I18n")
i18n, _ := anyfunc.(func(key string, params ...string) (string, error))
func I18n(c *gin.Context , name string) string{
anyfunc, _ := c.Get("I18n")
i18n, _ := anyfunc.(func(key string, params ...string) (string, error))
message, _ := i18n(name)
message, _ := i18n(name)
return message;
return message
}

View File

@@ -2,13 +2,14 @@ package controller
import (
"fmt"
"github.com/gin-gonic/gin"
"strconv"
"x-ui/database/model"
"x-ui/logger"
"x-ui/web/global"
"x-ui/web/service"
"x-ui/web/session"
"github.com/gin-gonic/gin"
)
type InboundController struct {
@@ -30,9 +31,7 @@ func (a *InboundController) initRouter(g *gin.RouterGroup) {
g.POST("/add", a.addInbound)
g.POST("/del/:id", a.delInbound)
g.POST("/update/:id", a.updateInbound)
g.POST("/resetClientTraffic/:email", a.resetClientTraffic)
}
@@ -53,7 +52,7 @@ func (a *InboundController) getInbounds(c *gin.Context) {
user := session.GetLoginUser(c)
inbounds, err := a.inboundService.GetInbounds(user.Id)
if err != nil {
jsonMsg(c, I18n(c , "pages.inbounds.toasts.obtain"), err)
jsonMsg(c, I18n(c, "pages.inbounds.toasts.obtain"), err)
return
}
jsonObj(c, inbounds, nil)
@@ -61,12 +60,12 @@ func (a *InboundController) getInbounds(c *gin.Context) {
func (a *InboundController) getInbound(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
jsonMsg(c, I18n(c , "get"), err)
jsonMsg(c, I18n(c, "get"), err)
return
}
inbound, err := a.inboundService.GetInbound(id)
if err != nil {
jsonMsg(c, I18n(c , "pages.inbounds.toasts.obtain"), err)
jsonMsg(c, I18n(c, "pages.inbounds.toasts.obtain"), err)
return
}
jsonObj(c, inbound, nil)
@@ -76,7 +75,7 @@ func (a *InboundController) addInbound(c *gin.Context) {
inbound := &model.Inbound{}
err := c.ShouldBind(inbound)
if err != nil {
jsonMsg(c, I18n(c , "pages.inbounds.addTo"), err)
jsonMsg(c, I18n(c, "pages.inbounds.addTo"), err)
return
}
user := session.GetLoginUser(c)
@@ -84,7 +83,7 @@ func (a *InboundController) addInbound(c *gin.Context) {
inbound.Enable = true
inbound.Tag = fmt.Sprintf("inbound-%v", inbound.Port)
inbound, err = a.inboundService.AddInbound(inbound)
jsonMsgObj(c, I18n(c , "pages.inbounds.addTo"), inbound, err)
jsonMsgObj(c, I18n(c, "pages.inbounds.addTo"), inbound, err)
if err == nil {
a.xrayService.SetToNeedRestart()
}
@@ -93,11 +92,11 @@ func (a *InboundController) addInbound(c *gin.Context) {
func (a *InboundController) delInbound(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
jsonMsg(c, I18n(c , "delete"), err)
jsonMsg(c, I18n(c, "delete"), err)
return
}
err = a.inboundService.DelInbound(id)
jsonMsgObj(c, I18n(c , "delete"), id, err)
jsonMsgObj(c, I18n(c, "delete"), id, err)
if err == nil {
a.xrayService.SetToNeedRestart()
}
@@ -106,7 +105,7 @@ func (a *InboundController) delInbound(c *gin.Context) {
func (a *InboundController) updateInbound(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
jsonMsg(c, I18n(c , "pages.inbounds.revise"), err)
jsonMsg(c, I18n(c, "pages.inbounds.revise"), err)
return
}
inbound := &model.Inbound{
@@ -114,11 +113,11 @@ func (a *InboundController) updateInbound(c *gin.Context) {
}
err = c.ShouldBind(inbound)
if err != nil {
jsonMsg(c, I18n(c , "pages.inbounds.revise"), err)
jsonMsg(c, I18n(c, "pages.inbounds.revise"), err)
return
}
inbound, err = a.inboundService.UpdateInbound(inbound)
jsonMsgObj(c, I18n(c , "pages.inbounds.revise"), inbound, err)
jsonMsgObj(c, I18n(c, "pages.inbounds.revise"), inbound, err)
if err == nil {
a.xrayService.SetToNeedRestart()
}

View File

@@ -46,7 +46,7 @@ func (a *IndexController) login(c *gin.Context) {
var form LoginForm
err := c.ShouldBind(&form)
if err != nil {
pureJsonMsg(c, false, I18n(c , "pages.login.toasts.invalidFormData"))
pureJsonMsg(c, false, I18n(c, "pages.login.toasts.invalidFormData"))
return
}
if form.Username == "" {
@@ -54,7 +54,7 @@ func (a *IndexController) login(c *gin.Context) {
return
}
if form.Password == "" {
pureJsonMsg(c, false, I18n(c , "pages.login.toasts.emptyPassword"))
pureJsonMsg(c, false, I18n(c, "pages.login.toasts.emptyPassword"))
return
}
user := a.userService.CheckUser(form.Username, form.Password)
@@ -62,7 +62,7 @@ func (a *IndexController) login(c *gin.Context) {
if user == nil {
job.NewStatsNotifyJob().UserLoginNotify(form.Username, getRemoteIp(c), timeStr, 0)
logger.Infof("wrong username or password: \"%s\" \"%s\"", form.Username, form.Password)
pureJsonMsg(c, false, I18n(c , "pages.login.toasts.wrongUsernameOrPassword"))
pureJsonMsg(c, false, I18n(c, "pages.login.toasts.wrongUsernameOrPassword"))
return
} else {
logger.Infof("%s login success,Ip Address:%s\n", form.Username, getRemoteIp(c))
@@ -71,7 +71,7 @@ func (a *IndexController) login(c *gin.Context) {
err = session.SetLoginUser(c, user)
logger.Info("user", user.Id, "login success")
jsonMsg(c, I18n(c , "pages.login.toasts.successLogin"), err)
jsonMsg(c, I18n(c, "pages.login.toasts.successLogin"), err)
}
func (a *IndexController) logout(c *gin.Context) {

View File

@@ -68,7 +68,7 @@ func (a *ServerController) getXrayVersion(c *gin.Context) {
versions, err := a.serverService.GetXrayVersions()
if err != nil {
jsonMsg(c, I18n(c , "getVersion"), err)
jsonMsg(c, I18n(c, "getVersion"), err)
return
}
@@ -81,5 +81,5 @@ func (a *ServerController) getXrayVersion(c *gin.Context) {
func (a *ServerController) installXray(c *gin.Context) {
version := c.Param("version")
err := a.serverService.UpdateXray(version)
jsonMsg(c, I18n(c , "install") + " xray", err)
jsonMsg(c, I18n(c, "install")+" xray", err)
}

View File

@@ -40,7 +40,7 @@ func (a *SettingController) initRouter(g *gin.RouterGroup) {
func (a *SettingController) getAllSetting(c *gin.Context) {
allSetting, err := a.settingService.GetAllSetting()
if err != nil {
jsonMsg(c, I18n(c , "pages.setting.toasts.getSetting"), err)
jsonMsg(c, I18n(c, "pages.setting.toasts.getSetting"), err)
return
}
jsonObj(c, allSetting, nil)
@@ -50,27 +50,27 @@ func (a *SettingController) updateSetting(c *gin.Context) {
allSetting := &entity.AllSetting{}
err := c.ShouldBind(allSetting)
if err != nil {
jsonMsg(c, I18n(c , "pages.setting.toasts.modifySetting"), err)
jsonMsg(c, I18n(c, "pages.setting.toasts.modifySetting"), err)
return
}
err = a.settingService.UpdateAllSetting(allSetting)
jsonMsg(c, I18n(c , "pages.setting.toasts.modifySetting"), err)
jsonMsg(c, I18n(c, "pages.setting.toasts.modifySetting"), err)
}
func (a *SettingController) updateUser(c *gin.Context) {
form := &updateUserForm{}
err := c.ShouldBind(form)
if err != nil {
jsonMsg(c, I18n(c , "pages.setting.toasts.modifySetting"), err)
jsonMsg(c, I18n(c, "pages.setting.toasts.modifySetting"), err)
return
}
user := session.GetLoginUser(c)
if user.Username != form.OldUsername || user.Password != form.OldPassword {
jsonMsg(c, I18n(c , "pages.setting.toasts.modifyUser"), errors.New(I18n(c , "pages.setting.toasts.originalUserPassIncorrect")))
jsonMsg(c, I18n(c, "pages.setting.toasts.modifyUser"), errors.New(I18n(c, "pages.setting.toasts.originalUserPassIncorrect")))
return
}
if form.NewUsername == "" || form.NewPassword == "" {
jsonMsg(c,I18n(c , "pages.setting.toasts.modifyUser"), errors.New(I18n(c , "pages.setting.toasts.userPassMustBeNotEmpty")))
jsonMsg(c, I18n(c, "pages.setting.toasts.modifyUser"), errors.New(I18n(c, "pages.setting.toasts.userPassMustBeNotEmpty")))
return
}
err = a.userService.UpdateUser(user.Id, form.NewUsername, form.NewPassword)
@@ -79,10 +79,10 @@ func (a *SettingController) updateUser(c *gin.Context) {
user.Password = form.NewPassword
session.SetLoginUser(c, user)
}
jsonMsg(c, I18n(c , "pages.setting.toasts.modifyUser"), err)
jsonMsg(c, I18n(c, "pages.setting.toasts.modifyUser"), err)
}
func (a *SettingController) restartPanel(c *gin.Context) {
err := a.panelService.RestartPanel(time.Second * 3)
jsonMsg(c, I18n(c , "pages.setting.restartPanel"), err)
jsonMsg(c, I18n(c, "pages.setting.restartPanel"), err)
}

View File

@@ -46,12 +46,12 @@ func jsonMsgObj(c *gin.Context, msg string, obj interface{}, err error) {
if err == nil {
m.Success = true
if msg != "" {
m.Msg = msg + I18n(c , "success")
m.Msg = msg + I18n(c, "success")
}
} else {
m.Success = false
m.Msg = msg + I18n(c , "fail") + ": " + err.Error()
logger.Warning(msg + I18n(c , "fail") + ": ", err)
m.Msg = msg + I18n(c, "fail") + ": " + err.Error()
logger.Warning(msg+I18n(c, "fail")+": ", err)
}
c.JSON(http.StatusOK, m)
}

View File

@@ -9,10 +9,10 @@
<a-form layout="inline">
<a-form-item>
<span slot="label">
Username
Email
<a-tooltip>
<template slot="title">
The Username Must Be Completely Unique
The Email Must Be Completely Unique
</template>
<!--Renew Svg Icon-->
<svg

View File

@@ -9,10 +9,10 @@
<a-form layout="inline">
<a-form-item>
<span slot="label">
Username
Email
<a-tooltip>
<template slot="title">
The Username Must Be Completely Unique
The Email Must Be Completely Unique
</template>
<!--Renew Svg Icon-->
<svg

View File

@@ -8,10 +8,10 @@
<a-form layout="inline">
<a-form-item>
<span slot="label">
Username
Email
<a-tooltip>
<template slot="title">
The Username Must Be Completely Unique
The Email Must Be Completely Unique
</template>
<!--Renew Svg Icon-->
<svg

View File

@@ -152,13 +152,18 @@
const columns = [{
title: '{{ i18n "pages.inbounds.operate" }}',
align: 'center',
width: 40,
width: 50,
scopedSlots: { customRender: 'action' },
}, {
title: '{{ i18n "pages.inbounds.enable" }}',
align: 'center',
width: 40,
scopedSlots: { customRender: 'enable' },
}, {
title: "Id",
align: 'center',
dataIndex: "id",
width: 20,
}, {
title: '{{ i18n "pages.inbounds.remark" }}',
align: 'center',
@@ -192,8 +197,8 @@
}];
const innerColumns = [
{ title: '', width: 20, scopedSlots: { customRender: 'actions' } },
{ title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } },
{ title: '', width: 70, scopedSlots: { customRender: 'actions' } },
{ title: '{{ i18n "pages.inbounds.client" }}', width: 60, scopedSlots: { customRender: 'client' } },
{ title: '{{ i18n "pages.inbounds.traffic" }}↑|↓', width: 80, scopedSlots: { customRender: 'traffic' } },
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 70, scopedSlots: { customRender: 'expiryTime' } },
{ title: 'UID', width: 150, dataIndex: "id" },
@@ -201,15 +206,15 @@
];
const innerTrojanColumns = [
{ title: '', width: 20, scopedSlots: { customRender: 'actions' } },
{ title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } },
{ title: '', width: 70, scopedSlots: { customRender: 'actions' } },
{ title: '{{ i18n "pages.inbounds.client" }}', width: 60, scopedSlots: { customRender: 'client' } },
{ title: '{{ i18n "pages.inbounds.traffic" }}↑|↓', width: 80, scopedSlots: { customRender: 'traffic' } },
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 70, scopedSlots: { customRender: 'expiryTime' } },
{ title: 'Password', width: 150, dataIndex: "password" },
];
const innerOneColumns = [
{ title: '', width: 50, scopedSlots: { customRender: 'actions' } },
{ title: '', width: 70, scopedSlots: { customRender: 'actions' } },
];
const app = new Vue({
@@ -276,7 +281,7 @@
this.showQrcode(dbInbound);
break;
case "edit":
this.openEditInbound(dbInbound);
this.openEditInbound(dbInbound.id);
break;
case "resetTraffic":
this.resetTraffic(dbInbound);
@@ -299,7 +304,8 @@
isEdit: false
});
},
openEditInbound(dbInbound) {
openEditInbound(dbInbound_id) {
dbInbound = this.dbInbounds.find(row => row.id === dbInbound_id);
const inbound = dbInbound.toInbound();
inModal.show({
title: '{{ i18n "pages.inbounds.modifyInbound"}}',

View File

@@ -1,15 +1,8 @@
{{define "client_row"}}
<template slot="actions" slot-scope="text, client, index">
<a-dropdown>
<a-icon @click="e => e.preventDefault()" type="menu"></a-icon>
<template #overlay>
<a-menu>
<a-menu-item v-if="record.hasLink()" @click="showQrcode(record,index);"><a-icon type="qrcode"></a-icon>{{ i18n "qrCode" }}</a-menu-item>
<a-menu-item @click="showInfo(record,index);"><a-icon type="info-circle"></a-icon>{{ i18n "info" }}</a-menu-item>
<a-menu-item @click="resetClientTraffic(client,record,$event)" v-if="client.email != ''"><a-icon type="retweet"></a-icon>{{ i18n "pages.inbounds.resetTraffic" }}</a-menu-item>
</a-menu>
</template>
</a-dropdown>
<a-icon v-if="record.hasLink()" style="font-size: 26px" type="qrcode" @click="showQrcode(record,index);"></a-icon>&nbsp;&nbsp;
<a-icon v-if="client.email != ''" style="font-size: 26px" type="retweet" @click="resetClientTraffic(client,record,$event)"></a-icon>&nbsp;&nbsp;
<a-icon type="info-circle" style="font-size: 26px" @click="showInfo(record,index);"></a-icon>
</template>
<template slot="client" slot-scope="text, client">
[[ client.email ]]

View File

@@ -8,6 +8,7 @@ import (
"x-ui/logger"
"x-ui/util/common"
"x-ui/web/service"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
)
@@ -54,7 +55,7 @@ func (j *StatsNotifyJob) SendMsgToTgbot(msg string) {
bot.Send(info)
}
//Here run is a interface method of Job interface
// Here run is a interface method of Job interface
func (j *StatsNotifyJob) Run() {
if !j.xrayService.IsXrayRunning() {
return
@@ -94,14 +95,14 @@ func (j *StatsNotifyJob) Run() {
}
info += fmt.Sprintf("IP:%s\r\n \r\n", ip)
//get traffic
// get traffic
inbouds, err := j.inboundService.GetAllInbounds()
if err != nil {
logger.Warning("StatsNotifyJob run failed:", err)
return
}
//NOTE:If there no any sessions here,need to notify here
//TODO:分节点推送,自动转化格式
// NOTE:If there no any sessions here,need to notify here
// TODO:Sub-node push, automatic conversion format
for _, inbound := range inbouds {
info += fmt.Sprintf("Node name:%s\r\nPort:%d\r\nUpload↑:%s\r\nDownload↓:%s\r\nTotal:%s\r\n", inbound.Remark, inbound.Port, common.FormatTraffic(inbound.Up), common.FormatTraffic(inbound.Down), common.FormatTraffic((inbound.Up + inbound.Down)))
if inbound.ExpiryTime == 0 {
@@ -119,7 +120,7 @@ func (j *StatsNotifyJob) UserLoginNotify(username string, ip string, time string
return
}
var msg string
//get hostname
// Get hostname
name, err := os.Hostname()
if err != nil {
fmt.Println("get hostname error:", err)
@@ -136,11 +137,10 @@ func (j *StatsNotifyJob) UserLoginNotify(username string, ip string, time string
j.SendMsgToTgbot(msg)
}
var numericKeyboard = tgbotapi.NewInlineKeyboardMarkup(
tgbotapi.NewInlineKeyboardRow(
tgbotapi.NewInlineKeyboardButtonData("Get Usage", "get_usage"),
),
tgbotapi.NewInlineKeyboardRow(
tgbotapi.NewInlineKeyboardButtonData("Get Usage", "get_usage"),
),
)
func (j *StatsNotifyJob) OnReceive() *StatsNotifyJob {
@@ -156,13 +156,13 @@ func (j *StatsNotifyJob) OnReceive() *StatsNotifyJob {
}
bot.Debug = false
u := tgbotapi.NewUpdate(0)
u.Timeout = 10
u.Timeout = 10
updates := bot.GetUpdatesChan(u)
updates := bot.GetUpdatesChan(u)
for update := range updates {
if update.Message == nil {
for update := range updates {
if update.Message == nil {
if update.CallbackQuery != nil {
// Respond to the callback query, telling Telegram to show the user
// a message with the data received.
@@ -170,60 +170,60 @@ func (j *StatsNotifyJob) OnReceive() *StatsNotifyJob {
if _, err := bot.Request(callback); err != nil {
logger.Warning(err)
}
// And finally, send a message containing the data received.
msg := tgbotapi.NewMessage(update.CallbackQuery.Message.Chat.ID, "")
switch update.CallbackQuery.Data {
case "get_usage":
msg.Text = "for get your usage send command like this : \n <code>/usage uuid | id</code> \n example : <code>/usage fc3239ed-8f3b-4151-ff51-b183d5182142</code>"
msg.ParseMode = "HTML"
}
case "get_usage":
msg.Text = "for get your usage send command like this : \n <code>/usage uuid | id</code> \n example : <code>/usage fc3239ed-8f3b-4151-ff51-b183d5182142</code>"
msg.ParseMode = "HTML"
}
if _, err := bot.Send(msg); err != nil {
logger.Warning(err)
}
}
continue
}
if !update.Message.IsCommand() { // ignore any non-command Messages
continue
}
continue
}
// Create a new MessageConfig. We don't have text yet,
// so we leave it empty.
msg := tgbotapi.NewMessage(update.Message.Chat.ID, "")
if !update.Message.IsCommand() { // ignore any non-command Messages
continue
}
// Extract the command from the Message.
switch update.Message.Command() {
case "help":
msg.Text = "What you need?"
// Create a new MessageConfig. We don't have text yet,
// so we leave it empty.
msg := tgbotapi.NewMessage(update.Message.Chat.ID, "")
// Extract the command from the Message.
switch update.Message.Command() {
case "help":
msg.Text = "What you need?"
msg.ReplyMarkup = numericKeyboard
case "start":
msg.Text = "Hi :) \n What you need?"
case "start":
msg.Text = "Hi :) \n What you need?"
msg.ReplyMarkup = numericKeyboard
case "status":
msg.Text = "bot is ok."
case "status":
msg.Text = "bot is ok."
case "usage":
msg.Text = j.getClientUsage(update.Message.CommandArguments())
default:
msg.Text = "I don't know that command, /help"
case "usage":
msg.Text = j.getClientUsage(update.Message.CommandArguments())
default:
msg.Text = "I don't know that command, /help"
msg.ReplyMarkup = numericKeyboard
}
}
if _, err := bot.Send(msg); err != nil {
logger.Warning(err)
}
}
if _, err := bot.Send(msg); err != nil {
logger.Warning(err)
}
}
return j
}
func (j *StatsNotifyJob) getClientUsage(id string) string {
traffic , err := j.inboundService.GetClientTrafficById(id)
traffic, err := j.inboundService.GetClientTrafficById(id)
if err != nil {
logger.Warning(err)
return "something wrong!"
@@ -241,8 +241,8 @@ func (j *StatsNotifyJob) getClientUsage(id string) string {
total = fmt.Sprintf("%s", common.FormatTraffic((traffic.Total)))
}
output := fmt.Sprintf("💡 Active: %t\r\n📧 Email: %s\r\n🔼 Upload↑: %s\r\n🔽 Download↓: %s\r\n🔄 Total: %s / %s\r\n📅 Expire in: %s\r\n",
traffic.Enable, traffic.Email, common.FormatTraffic(traffic.Up), common.FormatTraffic(traffic.Down), common.FormatTraffic((traffic.Up + traffic.Down)),
total, expiryTime)
traffic.Enable, traffic.Email, common.FormatTraffic(traffic.Up), common.FormatTraffic(traffic.Down), common.FormatTraffic((traffic.Up + traffic.Down)),
total, expiryTime)
return output
}

View File

@@ -1,14 +1,14 @@
package service
import (
"encoding/json"
"fmt"
"time"
"x-ui/database"
"encoding/json"
"x-ui/database/model"
"x-ui/logger"
"x-ui/util/common"
"x-ui/xray"
"x-ui/logger"
"gorm.io/gorm"
)
@@ -64,11 +64,11 @@ func (s *InboundService) getClients(inbound *model.Inbound) ([]model.Client, err
return clients, nil
}
func (s *InboundService) checkEmailsExist(emails map[string] bool, ignoreId int) (string, error) {
func (s *InboundService) checkEmailsExist(emails map[string]bool, ignoreId int) (string, error) {
db := database.GetDB()
var inbounds []*model.Inbound
db = db.Model(model.Inbound{}).Where("Protocol in ?", []model.Protocol{model.VMess, model.VLESS})
if (ignoreId > 0) {
var inbounds []*model.Inbound
db = db.Model(model.Inbound{}).Where("Protocol in ?", []model.Protocol{model.VMess, model.VLESS, model.Trojan})
if ignoreId > 0 {
db = db.Where("id != ?", ignoreId)
}
db = db.Find(&inbounds)
@@ -96,25 +96,25 @@ func (s *InboundService) checkEmailExistForInbound(inbound *model.Inbound) (stri
if err != nil {
return "", err
}
emails := make(map[string] bool)
emails := make(map[string]bool)
for _, client := range clients {
if (client.Email != "") {
if client.Email != "" {
if emails[client.Email] {
return client.Email, nil
}
emails[client.Email] = true;
emails[client.Email] = true
}
}
return s.checkEmailsExist(emails, inbound.Id)
}
func (s *InboundService) AddInbound(inbound *model.Inbound) (*model.Inbound,error) {
func (s *InboundService) AddInbound(inbound *model.Inbound) (*model.Inbound, error) {
exist, err := s.checkPortExist(inbound.Port, 0)
if err != nil {
return inbound, err
}
if exist {
return inbound, common.NewError("端口已存在:", inbound.Port)
return inbound, common.NewError("Port already exists:", inbound.Port)
}
existEmail, err := s.checkEmailExistForInbound(inbound)
@@ -129,7 +129,7 @@ func (s *InboundService) AddInbound(inbound *model.Inbound) (*model.Inbound,erro
err = db.Save(inbound).Error
if err == nil {
s.UpdateClientStat(inbound.Id,inbound.Settings)
s.UpdateClientStat(inbound.Id, inbound.Settings)
}
return inbound, err
}
@@ -141,7 +141,7 @@ func (s *InboundService) AddInbounds(inbounds []*model.Inbound) error {
return err
}
if exist {
return common.NewError("端口已存在:", inbound.Port)
return common.NewError("Port already exists:", inbound.Port)
}
}
@@ -187,9 +187,9 @@ func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound,
return inbound, err
}
if exist {
return inbound, common.NewError("端口已存在:", inbound.Port)
return inbound, common.NewError("Port already exists:", inbound.Port)
}
existEmail, err := s.checkEmailExistForInbound(inbound)
if err != nil {
return inbound, err
@@ -216,7 +216,7 @@ func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound,
oldInbound.Sniffing = inbound.Sniffing
oldInbound.Tag = fmt.Sprintf("inbound-%v", inbound.Port)
s.UpdateClientStat(inbound.Id,inbound.Settings)
s.UpdateClientStat(inbound.Id, inbound.Settings)
db := database.GetDB()
return inbound, db.Save(oldInbound).Error
}
@@ -276,13 +276,13 @@ func (s *InboundService) AddClientTraffic(traffics []*xray.ClientTraffic) (err e
for _, traffic := range traffics {
inbound := &model.Inbound{}
err := txInbound.Where("settings like ?", "%" + traffic.Email + "%").First(inbound).Error
err := txInbound.Where("settings like ?", "%"+traffic.Email+"%").First(inbound).Error
traffic.InboundId = inbound.Id
if err != nil {
if err == gorm.ErrRecordNotFound {
// delete removed client record
clientErr := s.DelClientStat(tx, traffic.Email)
logger.Warning(err, traffic.Email,clientErr)
logger.Warning(err, traffic.Email, clientErr)
}
continue
@@ -298,19 +298,19 @@ func (s *InboundService) AddClientTraffic(traffics []*xray.ClientTraffic) (err e
}
}
if tx.Where("inbound_id = ?", inbound.Id).Where("email = ?", traffic.Email).
UpdateColumn("enable", true).
UpdateColumn("expiry_time", traffic.ExpiryTime).
UpdateColumn("total",traffic.Total).
UpdateColumn("up", gorm.Expr("up + ?", traffic.Up)).
UpdateColumn("down", gorm.Expr("down + ?", traffic.Down)).RowsAffected == 0 {
UpdateColumn("enable", true).
UpdateColumn("expiry_time", traffic.ExpiryTime).
UpdateColumn("total", traffic.Total).
UpdateColumn("up", gorm.Expr("up + ?", traffic.Up)).
UpdateColumn("down", gorm.Expr("down + ?", traffic.Down)).RowsAffected == 0 {
err = tx.Create(traffic).Error
}
if err != nil {
logger.Warning("AddClientTraffic update data ", err)
continue
}
}
return
}
@@ -335,7 +335,7 @@ func (s *InboundService) DisableInvalidClients() (int64, error) {
count := result.RowsAffected
return count, err
}
func (s *InboundService) UpdateClientStat(inboundId int, inboundSettings string) (error) {
func (s *InboundService) UpdateClientStat(inboundId int, inboundSettings string) error {
db := database.GetDB()
// get settings clients
@@ -344,8 +344,8 @@ func (s *InboundService) UpdateClientStat(inboundId int, inboundSettings string)
clients := settings["clients"]
for _, client := range clients {
result := db.Model(xray.ClientTraffic{}).
Where("inbound_id = ? and email = ?", inboundId, client.Email).
Updates(map[string]interface{}{"enable": true, "total": client.TotalGB, "expiry_time": client.ExpiryTime})
Where("inbound_id = ? and email = ?", inboundId, client.Email).
Updates(map[string]interface{}{"enable": true, "total": client.TotalGB, "expiry_time": client.ExpiryTime})
if result.RowsAffected == 0 {
clientTraffic := xray.ClientTraffic{}
clientTraffic.InboundId = inboundId
@@ -361,7 +361,7 @@ func (s *InboundService) UpdateClientStat(inboundId int, inboundSettings string)
if err != nil {
return err
}
}
return nil
}
@@ -369,7 +369,7 @@ func (s *InboundService) DelClientStat(tx *gorm.DB, email string) error {
return tx.Where("email = ?", email).Delete(xray.ClientTraffic{}).Error
}
func (s *InboundService) ResetClientTraffic(clientEmail string) (error) {
func (s *InboundService) ResetClientTraffic(clientEmail string) error {
db := database.GetDB()
result := db.Model(xray.ClientTraffic{}).
@@ -379,7 +379,6 @@ func (s *InboundService) ResetClientTraffic(clientEmail string) (error) {
err := result.Error
if err != nil {
return err
}
@@ -390,7 +389,7 @@ func (s *InboundService) GetClientTrafficById(uuid string) (traffic *xray.Client
inbound := &model.Inbound{}
traffic = &xray.ClientTraffic{}
err = db.Model(model.Inbound{}).Where("settings like ?", "%" + uuid + "%").First(inbound).Error
err = db.Model(model.Inbound{}).Where("settings like ?", "%"+uuid+"%").First(inbound).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
logger.Warning(err)

View File

@@ -69,7 +69,7 @@ func (s *SettingService) GetAllSetting() (*entity.AllSetting, error) {
}
if !found {
// 有些设置自动生成,不需要返回到前端给用户修改
// Some settings are automatically generated, no need to return to the front end to modify the user
return nil
}

View File

@@ -6,6 +6,7 @@ import (
"sync"
"x-ui/logger"
"x-ui/xray"
"go.uber.org/atomic"
)
@@ -50,6 +51,7 @@ func (s *XrayService) GetXrayVersion() string {
}
return p.GetVersion()
}
func RemoveIndex(s []interface{}, index int) []interface{} {
return append(s[:index], s[index+1:]...)
}
@@ -79,25 +81,24 @@ func (s *XrayService) GetXrayConfig() (*xray.Config, error) {
// get settings clients
settings := map[string]interface{}{}
json.Unmarshal([]byte(inbound.Settings), &settings)
clients, ok := settings["clients"].([]interface{})
clients, ok := settings["clients"].([]interface{})
if ok {
// check users active or not
clientStats := inbound.ClientStats
for _, clientTraffic := range clientStats {
for index, client := range clients {
c := client.(map[string]interface{})
if c["email"] == clientTraffic.Email {
if ! clientTraffic.Enable {
clients = RemoveIndex(clients,index)
logger.Info("Remove Inbound User",c["email"] ,"due the expire or traffic limit")
if !clientTraffic.Enable {
clients = RemoveIndex(clients, index)
logger.Info("Remove Inbound User", c["email"], "due the expire or traffic limit")
}
}
}
}
settings["clients"] = clients
@@ -105,7 +106,7 @@ func (s *XrayService) GetXrayConfig() (*xray.Config, error) {
if err != nil {
return nil, err
}
inbound.Settings = string(modifiedSettings)
}
inboundConfig := inbound.GenXrayInboundConfig()

View File

@@ -21,7 +21,7 @@ import (
"x-ui/web/network"
"x-ui/web/service"
"github.com/BurntSushi/toml"
"github.com/pelletier/go-toml/v2"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
@@ -271,7 +271,7 @@ func (s *Server) initI18n(engine *gin.Engine) error {
})
}
engine.FuncMap["i18n"] = I18n;
engine.FuncMap["i18n"] = I18n
engine.Use(func(c *gin.Context) {
//accept := c.GetHeader("Accept-Language")
@@ -286,7 +286,7 @@ func (s *Server) initI18n(engine *gin.Engine) error {
localizer = i18n.NewLocalizer(bundle, lang)
c.Set("localizer", localizer)
c.Set("I18n" , I18n)
c.Set("I18n", I18n)
c.Next()
})
@@ -298,19 +298,19 @@ func (s *Server) startTask() {
if err != nil {
logger.Warning("start xray failed:", err)
}
// 每 30 秒检查一次 xray 是否在运行
// Check whether xray is running every 30 seconds
s.cron.AddJob("@every 30s", job.NewCheckXrayRunningJob())
go func() {
time.Sleep(time.Second * 5)
// 每 10 秒统计一次流量,首次启动延迟 5 秒,与重启 xray 的时间错开
// Statistics every 10 seconds, start the delay for 5 seconds for the first time, and staggered with the time to restart xray
s.cron.AddJob("@every 10s", job.NewXrayTrafficJob())
}()
// 每 30 秒检查一次 inbound 流量超出和到期的情况
// Check the inbound traffic every 30 seconds that the traffic exceeds and expires
s.cron.AddJob("@every 30s", job.NewCheckInboundJob())
// 每一天提示一次流量情况,上海时间8点30
// Make a traffic condition every day, 8:30
var entry cron.EntryID
isTgbotenabled, err := s.settingService.GetTgbotenabled()
if (err == nil) && (isTgbotenabled) {
@@ -320,7 +320,7 @@ func (s *Server) startTask() {
runtime = "@daily"
}
logger.Infof("Tg notify enabled,run at %s", runtime)
entry, err = s.cron.AddJob(runtime, job.NewStatsNotifyJob())
_, err = s.cron.AddJob(runtime, job.NewStatsNotifyJob())
if err != nil {
logger.Warning("Add NewStatsNotifyJob error", err)
return
@@ -333,7 +333,7 @@ func (s *Server) startTask() {
}
func (s *Server) Start() (err error) {
//这是一个匿名函数,没没有函数名
//This is an anonymous function, no function name
defer func() {
if err != nil {
s.Stop()