流量统计,修复问题

This commit is contained in:
sprov
2021-05-30 22:41:02 +08:00
parent 4bae13dcc6
commit 810dad53d5
18 changed files with 690 additions and 149 deletions

112
web/controller/inbound.go Normal file
View File

@@ -0,0 +1,112 @@
package controller
import (
"fmt"
"github.com/gin-gonic/gin"
"go.uber.org/atomic"
"strconv"
"x-ui/database/model"
"x-ui/logger"
"x-ui/web/global"
"x-ui/web/service"
"x-ui/web/session"
)
type InboundController struct {
inboundService service.InboundService
xrayService service.XrayService
isNeedXrayRestart atomic.Bool
}
func NewInboundController(g *gin.RouterGroup) *InboundController {
a := &InboundController{}
a.initRouter(g)
a.startTask()
return a
}
func (a *InboundController) initRouter(g *gin.RouterGroup) {
g = g.Group("/inbound")
g.POST("/list", a.getInbounds)
g.POST("/add", a.addInbound)
g.POST("/del/:id", a.delInbound)
g.POST("/update/:id", a.updateInbound)
}
func (a *InboundController) startTask() {
webServer := global.GetWebServer()
c := webServer.GetCron()
c.AddFunc("@every 10s", func() {
if a.isNeedXrayRestart.Load() {
err := a.xrayService.RestartXray()
if err != nil {
logger.Error("restart xray failed:", err)
}
a.isNeedXrayRestart.Store(false)
}
})
}
func (a *InboundController) getInbounds(c *gin.Context) {
user := session.GetLoginUser(c)
inbounds, err := a.inboundService.GetInbounds(user.Id)
if err != nil {
jsonMsg(c, "获取", err)
return
}
jsonObj(c, inbounds, nil)
}
func (a *InboundController) addInbound(c *gin.Context) {
inbound := &model.Inbound{}
err := c.ShouldBind(inbound)
if err != nil {
jsonMsg(c, "添加", err)
return
}
user := session.GetLoginUser(c)
inbound.UserId = user.Id
inbound.Enable = true
inbound.Tag = fmt.Sprintf("inbound-%v", inbound.Port)
err = a.inboundService.AddInbound(inbound)
jsonMsg(c, "添加", err)
if err == nil {
a.isNeedXrayRestart.Store(true)
}
}
func (a *InboundController) delInbound(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
jsonMsg(c, "删除", err)
return
}
err = a.inboundService.DelInbound(id)
jsonMsg(c, "删除", err)
if err == nil {
a.isNeedXrayRestart.Store(true)
}
}
func (a *InboundController) updateInbound(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
jsonMsg(c, "修改", err)
return
}
inbound := &model.Inbound{
Id: id,
}
err = c.ShouldBind(inbound)
if err != nil {
jsonMsg(c, "修改", err)
return
}
err = a.inboundService.UpdateInbound(inbound)
jsonMsg(c, "修改", err)
if err == nil {
a.isNeedXrayRestart.Store(true)
}
}

44
web/controller/setting.go Normal file
View File

@@ -0,0 +1,44 @@
package controller
import (
"github.com/gin-gonic/gin"
"x-ui/web/entity"
"x-ui/web/service"
)
type SettingController struct {
settingService service.SettingService
}
func NewSettingController(g *gin.RouterGroup) *SettingController {
a := &SettingController{}
a.initRouter(g)
return a
}
func (a *SettingController) initRouter(g *gin.RouterGroup) {
g = g.Group("/setting")
g.POST("/all", a.getAllSetting)
g.POST("/update", a.updateSetting)
}
func (a *SettingController) getAllSetting(c *gin.Context) {
allSetting, err := a.settingService.GetAllSetting()
if err != nil {
jsonMsg(c, "获取设置", err)
return
}
jsonObj(c, allSetting, nil)
}
func (a *SettingController) updateSetting(c *gin.Context) {
allSetting := &entity.AllSetting{}
err := c.ShouldBind(allSetting)
if err != nil {
jsonMsg(c, "修改设置", err)
return
}
err = a.settingService.UpdateAllSetting(allSetting)
jsonMsg(c, "修改设置", err)
}

View File

@@ -2,31 +2,18 @@ package controller
import (
"github.com/gin-gonic/gin"
"go.uber.org/atomic"
"log"
"strconv"
"x-ui/database/model"
"x-ui/logger"
"x-ui/web/entity"
"x-ui/web/global"
"x-ui/web/service"
"x-ui/web/session"
)
type XUIController struct {
BaseController
inboundService service.InboundService
xrayService service.XrayService
settingService service.SettingService
isNeedXrayRestart atomic.Bool
inboundController *InboundController
settingController *SettingController
}
func NewXUIController(g *gin.RouterGroup) *XUIController {
a := &XUIController{}
a.initRouter(g)
a.startTask()
return a
}
@@ -36,27 +23,10 @@ func (a *XUIController) initRouter(g *gin.RouterGroup) {
g.GET("/", a.index)
g.GET("/inbounds", a.inbounds)
g.POST("/inbounds", a.getInbounds)
g.POST("/inbound/add", a.addInbound)
g.POST("/inbound/del/:id", a.delInbound)
g.POST("/inbound/update/:id", a.updateInbound)
g.GET("/setting", a.setting)
g.POST("/setting/all", a.getAllSetting)
g.POST("/setting/update", a.updateSetting)
}
func (a *XUIController) startTask() {
webServer := global.GetWebServer()
c := webServer.GetCron()
c.AddFunc("@every 10s", func() {
if a.isNeedXrayRestart.Load() {
err := a.xrayService.RestartXray()
if err != nil {
logger.Error("restart xray failed:", err)
}
a.isNeedXrayRestart.Store(false)
}
})
a.inboundController = NewInboundController(g)
a.settingController = NewSettingController(g)
}
func (a *XUIController) index(c *gin.Context) {
@@ -70,85 +40,3 @@ func (a *XUIController) inbounds(c *gin.Context) {
func (a *XUIController) setting(c *gin.Context) {
html(c, "setting.html", "设置", nil)
}
func (a *XUIController) getInbounds(c *gin.Context) {
user := session.GetLoginUser(c)
inbounds, err := a.inboundService.GetInbounds(user.Id)
if err != nil {
jsonMsg(c, "获取", err)
return
}
jsonObj(c, inbounds, nil)
}
func (a *XUIController) addInbound(c *gin.Context) {
inbound := &model.Inbound{}
err := c.ShouldBind(inbound)
if err != nil {
jsonMsg(c, "添加", err)
return
}
user := session.GetLoginUser(c)
inbound.UserId = user.Id
inbound.Enable = true
log.Println(inbound)
err = a.inboundService.AddInbound(inbound)
jsonMsg(c, "添加", err)
if err == nil {
a.isNeedXrayRestart.Store(true)
}
}
func (a *XUIController) delInbound(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
jsonMsg(c, "删除", err)
return
}
err = a.inboundService.DelInbound(id)
jsonMsg(c, "删除", err)
if err == nil {
a.isNeedXrayRestart.Store(true)
}
}
func (a *XUIController) updateInbound(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
jsonMsg(c, "修改", err)
return
}
inbound := &model.Inbound{
Id: id,
}
err = c.ShouldBind(inbound)
if err != nil {
jsonMsg(c, "修改", err)
return
}
err = a.inboundService.UpdateInbound(inbound)
jsonMsg(c, "修改", err)
if err == nil {
a.isNeedXrayRestart.Store(true)
}
}
func (a *XUIController) getAllSetting(c *gin.Context) {
allSetting, err := a.settingService.GetAllSetting()
if err != nil {
jsonMsg(c, "获取设置", err)
return
}
jsonObj(c, allSetting, nil)
}
func (a *XUIController) updateSetting(c *gin.Context) {
allSetting := &entity.AllSetting{}
err := c.ShouldBind(allSetting)
if err != nil {
jsonMsg(c, "修改设置", err)
return
}
err = a.settingService.UpdateAllSetting(allSetting)
jsonMsg(c, "修改设置", err)
}

View File

@@ -60,6 +60,10 @@
<template slot="protocol" slot-scope="text, dbInbound">
<a-tag color="blue">[[ dbInbound.protocol ]]</a-tag>
</template>
<template slot="traffic" slot-scope="text, dbInbound">
<a-tag color="blue">[[ sizeFormat(dbInbound.up) ]]</a-tag>
<a-tag color="green">[[ sizeFormat(dbInbound.down) ]]</a-tag>
</template>
<template slot="settings" slot-scope="text, dbInbound">
<a-button type="link">查看</a-button>
</template>
@@ -67,8 +71,7 @@
<a-button type="link">查看</a-button>
</template>
<template slot="enable" slot-scope="text, dbInbound">
<a-tag v-if="dbInbound.enable" color="green">启用</a-tag>
<a-tag v-else color="red">禁用</a-tag>
<a-switch v-model="dbInbound.enable" @change="switchEnable(dbInbound)"></a-switch>
</template>
<template slot="expiryTime" slot-scope="text, dbInbound">
<span v-if="dbInbound.expiryTime > 0" color="red">[[ DateUtil.formatMillis(dbInbound.expiryTime) ]]</span>
@@ -104,6 +107,11 @@
align: 'center',
dataIndex: "port",
width: 60,
}, {
title: "traffic",
align: 'center',
width: 60,
scopedSlots: { customRender: 'traffic' },
}, {
title: "settings",
align: 'center',
@@ -146,7 +154,7 @@
},
async getDBInbounds() {
this.loading();
const msg = await HttpUtil.post('/xui/inbounds');
const msg = await HttpUtil.post('/xui/inbound/list');
this.loading(false);
if (!msg.success) {
return;
@@ -247,9 +255,19 @@
resetAllTraffic() {
this.submit('/xui/reset_all_traffic');
},
setEnable(inbound, enable) {
let data = {enable: enable};
this.submit(`/xui/inbound/update/${inbound.id}`, data);
switchEnable(dbInbound) {
const data = {
remark: dbInbound.remark,
enable: dbInbound.enable,
listen: dbInbound.listen,
port: dbInbound.port,
protocol: dbInbound.protocol,
settings: dbInbound.settings,
stream_settings: dbInbound.stream,
sniffing: dbInbound.sniffing,
};
this.submit(`/xui/inbound/update/${dbInbound.id}`, data);
},
async submit(url, data, modal) {
const msg = await HttpUtil.postWithModal(url, data, modal);

View File

@@ -1,9 +1,11 @@
package service
import (
"fmt"
"gorm.io/gorm"
"x-ui/database"
"x-ui/database/model"
"x-ui/xray"
)
type InboundService struct {
@@ -63,7 +65,36 @@ func (s *InboundService) UpdateInbound(inbound *model.Inbound) error {
oldInbound.Settings = inbound.Settings
oldInbound.StreamSettings = inbound.StreamSettings
oldInbound.Sniffing = inbound.Sniffing
oldInbound.Tag = fmt.Sprintf("inbound-%v", inbound.Port)
db := database.GetDB()
return db.Save(oldInbound).Error
}
func (s *InboundService) AddTraffic(traffics []*xray.Traffic) (err error) {
if len(traffics) == 0 {
return nil
}
db := database.GetDB()
db = db.Model(model.Inbound{})
tx := db.Begin()
defer func() {
if err != nil {
tx.Rollback()
} else {
tx.Commit()
}
}()
for _, traffic := range traffics {
if traffic.IsInbound {
err = tx.Where("tag = ?", traffic.Tag).
UpdateColumn("up", gorm.Expr("up + ?", traffic.Up)).
UpdateColumn("down", gorm.Expr("down + ?", traffic.Down)).
Error
if err != nil {
return
}
}
}
return
}

View File

@@ -265,7 +265,7 @@ func (s *ServerService) UpdateXray(version string) error {
s.xrayService.StopXray()
defer func() {
err := s.xrayService.StartXray()
err := s.xrayService.RestartXray()
if err != nil {
logger.Error("start xray failed:", err)
}

View File

@@ -3,11 +3,12 @@ package service
import (
"encoding/json"
"errors"
"x-ui/util/common"
"sync"
"x-ui/xray"
)
var p *xray.Process
var lock sync.Mutex
var result string
type XrayService struct {
@@ -64,15 +65,27 @@ func (s *XrayService) GetXrayConfig() (*xray.Config, error) {
return nil, err
}
for _, inbound := range inbounds {
if !inbound.Enable {
continue
}
inboundConfig := inbound.GenXrayInboundConfig()
xrayConfig.InboundConfigs = append(xrayConfig.InboundConfigs, *inboundConfig)
}
return xrayConfig, nil
}
func (s *XrayService) StartXray() error {
if s.IsXrayRunning() {
return nil
func (s *XrayService) GetXrayTraffic() ([]*xray.Traffic, error) {
if !s.IsXrayRunning() {
return nil, errors.New("xray is not running")
}
return p.GetTraffic(true)
}
func (s *XrayService) RestartXray() error {
lock.Lock()
defer lock.Unlock()
if p != nil {
p.Stop()
}
xrayConfig, err := s.GetXrayConfig()
@@ -81,20 +94,15 @@ func (s *XrayService) StartXray() error {
}
p = xray.NewProcess(xrayConfig)
err = p.Start()
result = ""
return err
return p.Start()
}
func (s *XrayService) StopXray() error {
lock.Lock()
defer lock.Unlock()
if s.IsXrayRunning() {
return p.Stop()
}
return errors.New("xray is not running")
}
func (s *XrayService) RestartXray() error {
err1 := s.StopXray()
err2 := s.StartXray()
return common.Combine(err1, err2)
}

View File

@@ -18,8 +18,10 @@ import (
"net/http"
"os"
"strconv"
"time"
"x-ui/config"
"x-ui/logger"
"x-ui/util"
"x-ui/util/common"
"x-ui/web/controller"
"x-ui/web/service"
@@ -51,6 +53,7 @@ type Server struct {
xrayService service.XrayService
settingService service.SettingService
inboundService service.InboundService
cron *cron.Cron
@@ -236,19 +239,43 @@ func (s *Server) initI18n(engine *gin.Engine) error {
}
func (s *Server) startTask() {
err := s.xrayService.StartXray()
err := s.xrayService.RestartXray()
if err != nil {
logger.Warning("start xray failed:", err)
}
var checkTime = 0
s.cron.AddFunc("@every 30s", func() {
if s.xrayService.IsXrayRunning() {
checkTime = 0
return
}
err := s.xrayService.StartXray()
checkTime++
if checkTime < 2 {
return
}
err := s.xrayService.RestartXray()
if err != nil {
logger.Warning("start xray failed:", err)
}
})
go func() {
time.Sleep(time.Second * 5)
// 与重启 xray 的时间错开
s.cron.AddFunc("@every 10s", func() {
if !s.xrayService.IsXrayRunning() {
return
}
traffics, err := s.xrayService.GetXrayTraffic()
if err != nil {
logger.Warning("get xray traffic failed:", err)
return
}
err = s.inboundService.AddTraffic(traffics)
if err != nil {
logger.Warning("add traffic failed:", err)
}
})
}()
}
func (s *Server) Start() (err error) {
@@ -318,6 +345,10 @@ func (s *Server) Start() (err error) {
}
func (s *Server) Stop() error {
if util.IsDone(s.ctx) {
// 防止 gc 后调用第二次 Stop
s.xrayService.StopXray()
}
s.cancel()
if s.cron != nil {
s.cron.Stop()