Skip to content

Commit

Permalink
Show outbound traffic in outbounds table (MHSanaei#1711)
Browse files Browse the repository at this point in the history
* store outbound traffic in database

* show outbound traffic in outbounds table

* add refresh button
  • Loading branch information
surbiks authored Jan 29, 2024
1 parent 9fbaede commit 6c0775b
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 15 deletions.
5 changes: 5 additions & 0 deletions database/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var db *gorm.DB
var initializers = []func() error{
initUser,
initInbound,
initOutbound,
initSetting,
initInboundClientIps,
initClientTraffic,
Expand Down Expand Up @@ -51,6 +52,10 @@ func initInbound() error {
return db.AutoMigrate(&model.Inbound{})
}

func initOutbound() error {
return db.AutoMigrate(&model.OutboundTraffics{})
}

func initSetting() error {
return db.AutoMigrate(&model.Setting{})
}
Expand Down
9 changes: 9 additions & 0 deletions database/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ type Inbound struct {
Tag string `json:"tag" form:"tag" gorm:"unique"`
Sniffing string `json:"sniffing" form:"sniffing"`
}

type OutboundTraffics struct {
Id int `json:"id" form:"id" gorm:"primaryKey;autoIncrement"`
Tag string `json:"tag" form:"tag" gorm:"unique"`
Up int64 `json:"up" form:"up" gorm:"default:0"`
Down int64 `json:"down" form:"down" gorm:"default:0"`
Total int64 `json:"total" form:"total" gorm:"default:0"`
}

type InboundClientIps struct {
Id int `json:"id" gorm:"primaryKey;autoIncrement"`
ClientEmail string `json:"clientEmail" form:"clientEmail" gorm:"unique"`
Expand Down
11 changes: 11 additions & 0 deletions web/controller/xray_setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type XraySettingController struct {
XraySettingService service.XraySettingService
SettingService service.SettingService
InboundService service.InboundService
OutboundService service.OutboundService
XrayService service.XrayService
}

Expand All @@ -27,6 +28,7 @@ func (a *XraySettingController) initRouter(g *gin.RouterGroup) {
g.GET("/getXrayResult", a.getXrayResult)
g.GET("/getDefaultJsonConfig", a.getDefaultXrayConfig)
g.POST("/warp/:action", a.warp)
g.GET("/getOutboundsTraffic", a.getOutboundsTraffic)
}

func (a *XraySettingController) getXraySetting(c *gin.Context) {
Expand Down Expand Up @@ -84,3 +86,12 @@ func (a *XraySettingController) warp(c *gin.Context) {

jsonObj(c, resp, err)
}

func (a *XraySettingController) getOutboundsTraffic(c *gin.Context) {
outboundsTraffic, err := a.OutboundService.GetOutboundsTraffic()
if err != nil {
jsonMsg(c, "Error getting traffics", err)
return
}
jsonObj(c, outboundsTraffic, nil)
}
48 changes: 46 additions & 2 deletions web/html/xui/xray.html
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,15 @@
</a-table>
</a-tab-pane>
<a-tab-pane key="tpl-3" tab='{{ i18n "pages.xray.Outbounds"}}' style="padding-top: 20px;" force-render="true">
<a-button type="primary" icon="plus" @click="addOutbound()" style="margin-bottom: 10px;">{{ i18n "pages.xray.outbound.addOutbound" }}</a-button>
<a-button type="primary" @click="showWarp()" style="margin-bottom: 10px;">WARP</a-button>
<a-row>
<a-col :xs="12" :sm="12" :lg="12">
<a-button type="primary" icon="plus" @click="addOutbound()" style="margin-bottom: 10px;">{{ i18n "pages.xray.outbound.addOutbound" }}</a-button>
<a-button type="primary" @click="showWarp()" style="margin-bottom: 10px;">WARP</a-button>
</a-col>
<a-col :xs="12" :sm="12" :lg="12" style="text-align: right;">
<a-icon type="sync" :spin="refreshing" @click="refreshOutboundTraffic()" style="margin: 0 5px;"/>
</a-col>
</a-row>
<a-table :columns="outboundColumns" bordered
:row-key="r => r.key"
:data-source="outboundData"
Expand Down Expand Up @@ -378,6 +385,9 @@
<a-tag style="margin:0;" v-if="outbound.streamSettings.security=='reality'" color="green">reality</a-tag>
</template>
</template>
<template slot="traffic" slot-scope="text, outbound, index">
<a-tag color="green">[[ findOutboundTraffic(outbound) ]]</a-tag>
</template>
</a-table>
</a-tab-pane>
<a-tab-pane key="tpl-4" tab='{{ i18n "pages.xray.outbound.reverse"}}' style="padding-top: 20px;" force-render="true">
Expand Down Expand Up @@ -463,6 +473,7 @@
{ title: '{{ i18n "pages.xray.outbound.tag"}}', dataIndex: 'tag', align: 'center', width: 50 },
{ title: '{{ i18n "protocol"}}', align: 'center', width: 50, scopedSlots: { customRender: 'protocol' } },
{ title: '{{ i18n "pages.xray.outbound.address"}}', align: 'center', width: 50, scopedSlots: { customRender: 'address' } },
{ title: '{{ i18n "pages.inbounds.traffic" }}', align: 'center', width: 50, scopedSlots: { customRender: 'traffic' } },
];

const reverseColumns = [
Expand All @@ -483,7 +494,9 @@
oldXraySetting: '',
xraySetting: '',
inboundTags: [],
outboundsTraffic: [],
saveBtnDisable: true,
refreshing: false,
restartResult: '',
isMobile: window.innerWidth <= 768,
advSettings: 'xraySetting',
Expand Down Expand Up @@ -581,6 +594,12 @@
loading(spinning = true) {
this.spinning = spinning;
},
async getOutboundsTraffic() {
const msg = await HttpUtil.get("/panel/xray/getOutboundsTraffic");
if (msg.success) {
this.outboundsTraffic = msg.obj;
}
},
async getXraySetting() {
this.loading(true);
const msg = await HttpUtil.post("/panel/xray/");
Expand Down Expand Up @@ -759,6 +778,14 @@
}
return true;
},
findOutboundTraffic(o) {
for (const otraffic of this.outboundsTraffic) {
if (otraffic.tag == o.tag) {
return sizeFormat(otraffic.up) + ' / ' + sizeFormat(otraffic.down);
}
}
return sizeFormat(0) + ' / ' + sizeFormat(0);
},
findOutboundAddress(o) {
serverObj = null;
switch(o.protocol){
Expand Down Expand Up @@ -816,6 +843,22 @@
outbounds.splice(index,1);
this.outboundSettings = JSON.stringify(outbounds);
},
async refreshOutboundTraffic() {
if (!this.refreshing) {
this.refreshing = true;
await this.getOutboundsTraffic();

data = []
if (this.templateSettings != null) {
this.templateSettings.outbounds.forEach((o, index) => {
data.push({'key': index, ...o});
});
}

this.outboundData = data;
this.refreshing = false;
}
},
addReverse(){
reverseModal.show({
title: '{{ i18n "pages.xray.outbound.addReverse"}}',
Expand Down Expand Up @@ -949,6 +992,7 @@
async mounted() {
await this.getXraySetting();
await this.getXrayResult();
await this.getOutboundsTraffic();
while (true) {
await PromiseUtil.sleep(800);
this.saveBtnDisable = this.oldXraySetting === this.xraySetting;
Expand Down
15 changes: 10 additions & 5 deletions web/job/xray_traffic_job.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import (
)

type XrayTrafficJob struct {
xrayService service.XrayService
inboundService service.InboundService
xrayService service.XrayService
inboundService service.InboundService
outboundService service.OutboundService
}

func NewXrayTrafficJob() *XrayTrafficJob {
Expand All @@ -24,11 +25,15 @@ func (j *XrayTrafficJob) Run() {
logger.Warning("get xray traffic failed:", err)
return
}
err, needRestart := j.inboundService.AddTraffic(traffics, clientTraffics)
err, needRestart0 := j.inboundService.AddTraffic(traffics, clientTraffics)
if err != nil {
logger.Warning("add traffic failed:", err)
logger.Warning("add inbound traffic failed:", err)
}
if needRestart {
err, needRestart1 := j.outboundService.AddTraffic(traffics, clientTraffics)
if err != nil {
logger.Warning("add outbound traffic failed:", err)
}
if needRestart0 || needRestart1 {
j.xrayService.SetToNeedRestart()
}

Expand Down
4 changes: 2 additions & 2 deletions web/service/inbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
return needRestart, tx.Save(oldInbound).Error
}

func (s *InboundService) AddTraffic(inboundTraffics []*xray.Traffic, clientTraffics []*xray.ClientTraffic) (error, bool) {
func (s *InboundService) AddTraffic(traffics []*xray.Traffic, clientTraffics []*xray.ClientTraffic) (error, bool) {
var err error
db := database.GetDB()
tx := db.Begin()
Expand All @@ -694,7 +694,7 @@ func (s *InboundService) AddTraffic(inboundTraffics []*xray.Traffic, clientTraff
tx.Commit()
}
}()
err = s.addInboundTraffic(tx, inboundTraffics)
err = s.addInboundTraffic(tx, traffics)
if err != nil {
return err, false
}
Expand Down
80 changes: 80 additions & 0 deletions web/service/outbound.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package service

import (
"x-ui/database"
"x-ui/database/model"
"x-ui/logger"
"x-ui/xray"

"gorm.io/gorm"
)

type OutboundService struct {
xrayApi xray.XrayAPI
}

func (s *OutboundService) AddTraffic(traffics []*xray.Traffic, clientTraffics []*xray.ClientTraffic) (error, bool) {
var err error
db := database.GetDB()
tx := db.Begin()

defer func() {
if err != nil {
tx.Rollback()
} else {
tx.Commit()
}
}()

err = s.addOutboundTraffic(tx, traffics)
if err != nil {
return err, false
}

return nil, false
}

func (s *OutboundService) addOutboundTraffic(tx *gorm.DB, traffics []*xray.Traffic) error {
if len(traffics) == 0 {
return nil
}

var err error

for _, traffic := range traffics {
if traffic.IsOutbound {

var outbound model.OutboundTraffics

err = tx.Model(&model.OutboundTraffics{}).Where("tag = ?", traffic.Tag).
FirstOrCreate(&outbound).Error
if err != nil {
return err
}

outbound.Tag = traffic.Tag
outbound.Up = outbound.Up + traffic.Up
outbound.Down = outbound.Down + traffic.Down
outbound.Total = outbound.Up + outbound.Down

err = tx.Save(&outbound).Error
if err != nil {
return err
}
}
}
return nil
}

func (s *OutboundService) GetOutboundsTraffic() ([]*model.OutboundTraffics, error) {
db := database.GetDB()
var traffics []*model.OutboundTraffics

err := db.Model(model.OutboundTraffics{}).Find(&traffics).Error
if err != nil {
logger.Warning(err)
return nil, err
}

return traffics, nil
}
6 changes: 4 additions & 2 deletions xray/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ func (x *XrayAPI) GetTraffic(reset bool) ([]*Traffic, []*ClientTraffic, error) {
continue
}
isInbound := matchs[1] == "inbound"
isOutbound := matchs[1] == "outbound"
tag := matchs[2]
isDown := matchs[3] == "downlink"
if tag == "api" {
Expand All @@ -221,8 +222,9 @@ func (x *XrayAPI) GetTraffic(reset bool) ([]*Traffic, []*ClientTraffic, error) {
traffic, ok := tagTrafficMap[tag]
if !ok {
traffic = &Traffic{
IsInbound: isInbound,
Tag: tag,
IsInbound: isInbound,
IsOutbound: isOutbound,
Tag: tag,
}
tagTrafficMap[tag] = traffic
traffics = append(traffics, traffic)
Expand Down
9 changes: 5 additions & 4 deletions xray/traffic.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package xray

type Traffic struct {
IsInbound bool
Tag string
Up int64
Down int64
IsInbound bool
IsOutbound bool
Tag string
Up int64
Down int64
}

0 comments on commit 6c0775b

Please sign in to comment.