mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-09-12 13:10:05 +00:00
Merge branch 'MHSanaei:main' into main
This commit is contained in:
commit
2187f84b8b
23 changed files with 85 additions and 67 deletions
|
@ -32,6 +32,7 @@ type Inbound struct {
|
||||||
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"`
|
||||||
|
AllTime int64 `json:"allTime" form:"allTime" gorm:"default:0"`
|
||||||
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"`
|
||||||
|
@ -45,7 +46,6 @@ type Inbound struct {
|
||||||
StreamSettings string `json:"streamSettings" form:"streamSettings"`
|
StreamSettings string `json:"streamSettings" form:"streamSettings"`
|
||||||
Tag string `json:"tag" form:"tag" gorm:"unique"`
|
Tag string `json:"tag" form:"tag" gorm:"unique"`
|
||||||
Sniffing string `json:"sniffing" form:"sniffing"`
|
Sniffing string `json:"sniffing" form:"sniffing"`
|
||||||
Allocate string `json:"allocate" form:"allocate"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type OutboundTraffics struct {
|
type OutboundTraffics struct {
|
||||||
|
@ -80,7 +80,6 @@ func (i *Inbound) GenXrayInboundConfig() *xray.InboundConfig {
|
||||||
StreamSettings: json_util.RawMessage(i.StreamSettings),
|
StreamSettings: json_util.RawMessage(i.StreamSettings),
|
||||||
Tag: i.Tag,
|
Tag: i.Tag,
|
||||||
Sniffing: json_util.RawMessage(i.Sniffing),
|
Sniffing: json_util.RawMessage(i.Sniffing),
|
||||||
Allocate: json_util.RawMessage(i.Allocate),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ class DBInbound {
|
||||||
this.up = 0;
|
this.up = 0;
|
||||||
this.down = 0;
|
this.down = 0;
|
||||||
this.total = 0;
|
this.total = 0;
|
||||||
|
this.allTime = 0;
|
||||||
this.remark = "";
|
this.remark = "";
|
||||||
this.enable = true;
|
this.enable = true;
|
||||||
this.expiryTime = 0;
|
this.expiryTime = 0;
|
||||||
|
|
|
@ -1042,27 +1042,6 @@ class Sniffing extends XrayCommonClass {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Allocate extends XrayCommonClass {
|
|
||||||
constructor(
|
|
||||||
strategy = "always",
|
|
||||||
refresh = 5,
|
|
||||||
concurrency = 3,
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
this.strategy = strategy;
|
|
||||||
this.refresh = refresh;
|
|
||||||
this.concurrency = concurrency;
|
|
||||||
}
|
|
||||||
|
|
||||||
static fromJson(json = {}) {
|
|
||||||
return new Allocate(
|
|
||||||
json.strategy,
|
|
||||||
json.refresh,
|
|
||||||
json.concurrency,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Inbound extends XrayCommonClass {
|
class Inbound extends XrayCommonClass {
|
||||||
constructor(
|
constructor(
|
||||||
port = RandomUtil.randomInteger(10000, 60000),
|
port = RandomUtil.randomInteger(10000, 60000),
|
||||||
|
@ -1072,7 +1051,6 @@ class Inbound extends XrayCommonClass {
|
||||||
streamSettings = new StreamSettings(),
|
streamSettings = new StreamSettings(),
|
||||||
tag = '',
|
tag = '',
|
||||||
sniffing = new Sniffing(),
|
sniffing = new Sniffing(),
|
||||||
allocate = new Allocate(),
|
|
||||||
clientStats = '',
|
clientStats = '',
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
@ -1083,7 +1061,6 @@ class Inbound extends XrayCommonClass {
|
||||||
this.stream = streamSettings;
|
this.stream = streamSettings;
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
this.sniffing = sniffing;
|
this.sniffing = sniffing;
|
||||||
this.allocate = allocate;
|
|
||||||
this.clientStats = clientStats;
|
this.clientStats = clientStats;
|
||||||
}
|
}
|
||||||
getClientStats() {
|
getClientStats() {
|
||||||
|
@ -1248,7 +1225,6 @@ class Inbound extends XrayCommonClass {
|
||||||
this.stream = new StreamSettings();
|
this.stream = new StreamSettings();
|
||||||
this.tag = '';
|
this.tag = '';
|
||||||
this.sniffing = new Sniffing();
|
this.sniffing = new Sniffing();
|
||||||
this.allocate = new Allocate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
genVmessLink(address = '', port = this.port, forceTls, remark = '', clientId, security) {
|
genVmessLink(address = '', port = this.port, forceTls, remark = '', clientId, security) {
|
||||||
|
@ -1703,7 +1679,6 @@ class Inbound extends XrayCommonClass {
|
||||||
StreamSettings.fromJson(json.streamSettings),
|
StreamSettings.fromJson(json.streamSettings),
|
||||||
json.tag,
|
json.tag,
|
||||||
Sniffing.fromJson(json.sniffing),
|
Sniffing.fromJson(json.sniffing),
|
||||||
Allocate.fromJson(json.allocate),
|
|
||||||
json.clientStats
|
json.clientStats
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1721,7 +1696,6 @@ class Inbound extends XrayCommonClass {
|
||||||
streamSettings: streamSettings,
|
streamSettings: streamSettings,
|
||||||
tag: this.tag,
|
tag: this.tag,
|
||||||
sniffing: this.sniffing.toJson(),
|
sniffing: this.sniffing.toJson(),
|
||||||
allocate: this.allocate.toJson(),
|
|
||||||
clientStats: this.clientStats
|
clientStats: this.clientStats
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,10 @@
|
||||||
</table>
|
</table>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template slot="allTime" slot-scope="text, client">
|
||||||
|
<a-tag>[[ SizeFormatter.sizeFormat(getAllTimeClient(record, client.email)) ]]</a-tag>
|
||||||
|
</template>
|
||||||
<template slot="expiryTime" slot-scope="text, client, index">
|
<template slot="expiryTime" slot-scope="text, client, index">
|
||||||
<template v-if="client.expiryTime !=0 && client.reset >0">
|
<template v-if="client.expiryTime !=0 && client.reset >0">
|
||||||
<a-popover :overlay-class-name="themeSwitcher.currentTheme">
|
<a-popover :overlay-class-name="themeSwitcher.currentTheme">
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
{{define "form/allocate"}}
|
|
||||||
<a-form :colon="false" :label-col="{ md: {span:8} }" :wrapper-col="{ md: {span:14} }">
|
|
||||||
<a-form-item label='Strategy'>
|
|
||||||
<a-select v-model="inbound.allocate.strategy" :dropdown-class-name="themeSwitcher.currentTheme">
|
|
||||||
<a-select-option v-for="s in ['always','random']" :value="s">[[ s ]]</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label='Refresh'>
|
|
||||||
<a-input-number v-model.number="inbound.allocate.refresh" min="0"></a-input-number>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label='Concurrency'>
|
|
||||||
<a-input-number v-model.number="inbound.allocate.concurrency" min="0"></a-input-number>
|
|
||||||
</a-form-item>
|
|
||||||
</a-form>
|
|
||||||
{{end}}
|
|
|
@ -121,13 +121,4 @@
|
||||||
</a-collapse-panel>
|
</a-collapse-panel>
|
||||||
</a-collapse>
|
</a-collapse>
|
||||||
|
|
||||||
<!-- allocate -->
|
|
||||||
<!-- Temporarily disabled until we accepts range for port allocation
|
|
||||||
<a-collapse>
|
|
||||||
<a-collapse-panel header='Allocate'>
|
|
||||||
{{template "form/allocate"}}
|
|
||||||
</a-collapse-panel>
|
|
||||||
</a-collapse>
|
|
||||||
-->
|
|
||||||
|
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -167,28 +167,35 @@
|
||||||
<a-col>
|
<a-col>
|
||||||
<a-card size="small" :style="{ padding: '16px' }" hoverable>
|
<a-card size="small" :style="{ padding: '16px' }" hoverable>
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :sm="12" :md="6">
|
<a-col :sm="12" :md="5">
|
||||||
<a-custom-statistic title='{{ i18n "pages.inbounds.totalDownUp" }}' :value="`${SizeFormatter.sizeFormat(total.up)} / ${SizeFormatter.sizeFormat(total.down)}`">
|
<a-custom-statistic title='{{ i18n "pages.inbounds.totalDownUp" }}' :value="`${SizeFormatter.sizeFormat(total.up)} / ${SizeFormatter.sizeFormat(total.down)}`">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<a-icon type="swap"></a-icon>
|
<a-icon type="swap"></a-icon>
|
||||||
</template>
|
</template>
|
||||||
</a-custom-statistic>
|
</a-custom-statistic>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="12" :md="6">
|
<a-col :sm="12" :md="5">
|
||||||
<a-custom-statistic title='{{ i18n "pages.inbounds.totalUsage" }}' :value="SizeFormatter.sizeFormat(total.up + total.down)" :style="{ marginTop: isMobile ? '10px' : 0 }">
|
<a-custom-statistic title='{{ i18n "pages.inbounds.totalUsage" }}' :value="SizeFormatter.sizeFormat(total.up + total.down)" :style="{ marginTop: isMobile ? '10px' : 0 }">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<a-icon type="pie-chart"></a-icon>
|
<a-icon type="pie-chart"></a-icon>
|
||||||
</template>
|
</template>
|
||||||
</a-custom-statistic>
|
</a-custom-statistic>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="12" :md="6">
|
<a-col :sm="12" :md="5">
|
||||||
|
<a-custom-statistic title='{{ i18n "pages.inbounds.allTimeTrafficUsage" }}' :value="SizeFormatter.sizeFormat(total.allTime)" :style="{ marginTop: isMobile ? '10px' : 0 }">
|
||||||
|
<template #prefix>
|
||||||
|
<a-icon type="history"></a-icon>
|
||||||
|
</template>
|
||||||
|
</a-custom-statistic>
|
||||||
|
</a-col>
|
||||||
|
<a-col :sm="12" :md="5">
|
||||||
<a-custom-statistic title='{{ i18n "pages.inbounds.inboundCount" }}' :value="dbInbounds.length" :style="{ marginTop: isMobile ? '10px' : 0 }">
|
<a-custom-statistic title='{{ i18n "pages.inbounds.inboundCount" }}' :value="dbInbounds.length" :style="{ marginTop: isMobile ? '10px' : 0 }">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<a-icon type="bars"></a-icon>
|
<a-icon type="bars"></a-icon>
|
||||||
</template>
|
</template>
|
||||||
</a-custom-statistic>
|
</a-custom-statistic>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="12" :md="6">
|
<a-col :sm="12" :md="4">
|
||||||
<a-custom-statistic title='{{ i18n "clients" }}' value=" " :style="{ marginTop: isMobile ? '10px' : 0 }">
|
<a-custom-statistic title='{{ i18n "clients" }}' value=" " :style="{ marginTop: isMobile ? '10px' : 0 }">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<a-space direction="horizontal">
|
<a-space direction="horizontal">
|
||||||
|
@ -484,6 +491,9 @@
|
||||||
</a-tag>
|
</a-tag>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
</template>
|
</template>
|
||||||
|
<template slot="allTimeInbound" slot-scope="text, dbInbound">
|
||||||
|
<a-tag>[[ SizeFormatter.sizeFormat(dbInbound.allTime || 0) ]]</a-tag>
|
||||||
|
</template>
|
||||||
<template slot="enable" slot-scope="text, dbInbound">
|
<template slot="enable" slot-scope="text, dbInbound">
|
||||||
<a-switch v-model="dbInbound.enable" @change="switchEnable(dbInbound.id,dbInbound.enable)"></a-switch>
|
<a-switch v-model="dbInbound.enable" @change="switchEnable(dbInbound.id,dbInbound.enable)"></a-switch>
|
||||||
</template>
|
</template>
|
||||||
|
@ -723,6 +733,11 @@
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 60,
|
width: 60,
|
||||||
scopedSlots: { customRender: 'traffic' },
|
scopedSlots: { customRender: 'traffic' },
|
||||||
|
}, {
|
||||||
|
title: '{{ i18n "pages.inbounds.allTimeTraffic" }}',
|
||||||
|
align: 'center',
|
||||||
|
width: 60,
|
||||||
|
scopedSlots: { customRender: 'allTimeInbound' },
|
||||||
}, {
|
}, {
|
||||||
title: '{{ i18n "pages.inbounds.expireDate" }}',
|
title: '{{ i18n "pages.inbounds.expireDate" }}',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
@ -759,6 +774,7 @@
|
||||||
{ title: '{{ i18n "online" }}', width: 30, scopedSlots: { customRender: 'online' } },
|
{ title: '{{ i18n "online" }}', width: 30, scopedSlots: { customRender: 'online' } },
|
||||||
{ title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } },
|
{ title: '{{ i18n "pages.inbounds.client" }}', width: 80, scopedSlots: { customRender: 'client' } },
|
||||||
{ title: '{{ i18n "pages.inbounds.traffic" }}', width: 80, align: 'center', scopedSlots: { customRender: 'traffic' } },
|
{ title: '{{ i18n "pages.inbounds.traffic" }}', width: 80, align: 'center', scopedSlots: { customRender: 'traffic' } },
|
||||||
|
{ title: '{{ i18n "pages.inbounds.allTimeTraffic" }}', width: 80, align: 'center', scopedSlots: { customRender: 'allTime' } },
|
||||||
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 80, align: 'center', scopedSlots: { customRender: 'expiryTime' } },
|
{ title: '{{ i18n "pages.inbounds.expireDate" }}', width: 80, align: 'center', scopedSlots: { customRender: 'expiryTime' } },
|
||||||
{ title: '{{ i18n "pages.inbounds.createdAt" }}', width: 90, align: 'center', scopedSlots: { customRender: 'createdAt' } },
|
{ title: '{{ i18n "pages.inbounds.createdAt" }}', width: 90, align: 'center', scopedSlots: { customRender: 'createdAt' } },
|
||||||
{ title: '{{ i18n "pages.inbounds.updatedAt" }}', width: 90, align: 'center', scopedSlots: { customRender: 'updatedAt' } },
|
{ title: '{{ i18n "pages.inbounds.updatedAt" }}', width: 90, align: 'center', scopedSlots: { customRender: 'updatedAt' } },
|
||||||
|
@ -1077,7 +1093,6 @@
|
||||||
settings: Inbound.Settings.getSettings(baseInbound.protocol).toString(),
|
settings: Inbound.Settings.getSettings(baseInbound.protocol).toString(),
|
||||||
streamSettings: baseInbound.stream.toString(),
|
streamSettings: baseInbound.stream.toString(),
|
||||||
sniffing: baseInbound.sniffing.toString(),
|
sniffing: baseInbound.sniffing.toString(),
|
||||||
allocate: baseInbound.allocate.toString(),
|
|
||||||
};
|
};
|
||||||
await this.submit('/panel/inbound/add', data, inModal);
|
await this.submit('/panel/inbound/add', data, inModal);
|
||||||
},
|
},
|
||||||
|
@ -1127,7 +1142,6 @@
|
||||||
data.streamSettings = JSON.stringify({ sockopt: inbound.stream.sockopt.toJson() }, null, 2);
|
data.streamSettings = JSON.stringify({ sockopt: inbound.stream.sockopt.toJson() }, null, 2);
|
||||||
}
|
}
|
||||||
data.sniffing = inbound.sniffing.toString();
|
data.sniffing = inbound.sniffing.toString();
|
||||||
data.allocate = inbound.allocate.toString();
|
|
||||||
|
|
||||||
await this.submit('/panel/inbound/add', data, inModal);
|
await this.submit('/panel/inbound/add', data, inModal);
|
||||||
},
|
},
|
||||||
|
@ -1151,7 +1165,6 @@
|
||||||
data.streamSettings = JSON.stringify({ sockopt: inbound.stream.sockopt.toJson() }, null, 2);
|
data.streamSettings = JSON.stringify({ sockopt: inbound.stream.sockopt.toJson() }, null, 2);
|
||||||
}
|
}
|
||||||
data.sniffing = inbound.sniffing.toString();
|
data.sniffing = inbound.sniffing.toString();
|
||||||
data.allocate = inbound.allocate.toString();
|
|
||||||
|
|
||||||
await this.submit(`/panel/inbound/update/${dbInbound.id}`, data, inModal);
|
await this.submit(`/panel/inbound/update/${dbInbound.id}`, data, inModal);
|
||||||
},
|
},
|
||||||
|
@ -1419,6 +1432,12 @@
|
||||||
clientStats = dbInbound.clientStats.find(stats => stats.email === email);
|
clientStats = dbInbound.clientStats.find(stats => stats.email === email);
|
||||||
return clientStats ? clientStats.up + clientStats.down : 0;
|
return clientStats ? clientStats.up + clientStats.down : 0;
|
||||||
},
|
},
|
||||||
|
getAllTimeClient(dbInbound, email) {
|
||||||
|
if (email.length == 0) return 0;
|
||||||
|
clientStats = dbInbound.clientStats.find(stats => stats.email === email);
|
||||||
|
if (!clientStats) return 0;
|
||||||
|
return clientStats.allTime || (clientStats.up + clientStats.down);
|
||||||
|
},
|
||||||
getRemStats(dbInbound, email) {
|
getRemStats(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);
|
||||||
|
@ -1608,11 +1627,12 @@
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
total() {
|
total() {
|
||||||
let down = 0, up = 0;
|
let down = 0, up = 0, allTime = 0;
|
||||||
let clients = 0, deactive = [], depleted = [], expiring = [];
|
let clients = 0, deactive = [], depleted = [], expiring = [];
|
||||||
this.dbInbounds.forEach(dbInbound => {
|
this.dbInbounds.forEach(dbInbound => {
|
||||||
down += dbInbound.down;
|
down += dbInbound.down;
|
||||||
up += dbInbound.up;
|
up += dbInbound.up;
|
||||||
|
allTime += (dbInbound.allTime || (dbInbound.up + dbInbound.down));
|
||||||
if (this.clientCount[dbInbound.id]) {
|
if (this.clientCount[dbInbound.id]) {
|
||||||
clients += this.clientCount[dbInbound.id].clients;
|
clients += this.clientCount[dbInbound.id].clients;
|
||||||
deactive = deactive.concat(this.clientCount[dbInbound.id].deactive);
|
deactive = deactive.concat(this.clientCount[dbInbound.id].deactive);
|
||||||
|
@ -1623,6 +1643,7 @@
|
||||||
return {
|
return {
|
||||||
down: down,
|
down: down,
|
||||||
up: up,
|
up: up,
|
||||||
|
allTime: allTime,
|
||||||
clients: clients,
|
clients: clients,
|
||||||
deactive: deactive,
|
deactive: deactive,
|
||||||
depleted: depleted,
|
depleted: depleted,
|
||||||
|
|
|
@ -403,7 +403,6 @@ func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound,
|
||||||
oldInbound.Settings = inbound.Settings
|
oldInbound.Settings = inbound.Settings
|
||||||
oldInbound.StreamSettings = inbound.StreamSettings
|
oldInbound.StreamSettings = inbound.StreamSettings
|
||||||
oldInbound.Sniffing = inbound.Sniffing
|
oldInbound.Sniffing = inbound.Sniffing
|
||||||
oldInbound.Allocate = inbound.Allocate
|
|
||||||
if inbound.Listen == "" || inbound.Listen == "0.0.0.0" || inbound.Listen == "::" || inbound.Listen == "::0" {
|
if inbound.Listen == "" || inbound.Listen == "0.0.0.0" || inbound.Listen == "::" || inbound.Listen == "::0" {
|
||||||
oldInbound.Tag = fmt.Sprintf("inbound-%v", inbound.Port)
|
oldInbound.Tag = fmt.Sprintf("inbound-%v", inbound.Port)
|
||||||
} else {
|
} else {
|
||||||
|
@ -915,8 +914,9 @@ func (s *InboundService) addInboundTraffic(tx *gorm.DB, traffics []*xray.Traffic
|
||||||
if traffic.IsInbound {
|
if traffic.IsInbound {
|
||||||
err = tx.Model(&model.Inbound{}).Where("tag = ?", traffic.Tag).
|
err = tx.Model(&model.Inbound{}).Where("tag = ?", traffic.Tag).
|
||||||
Updates(map[string]any{
|
Updates(map[string]any{
|
||||||
"up": gorm.Expr("up + ?", traffic.Up),
|
"up": gorm.Expr("up + ?", traffic.Up),
|
||||||
"down": gorm.Expr("down + ?", traffic.Down),
|
"down": gorm.Expr("down + ?", traffic.Down),
|
||||||
|
"all_time": gorm.Expr("COALESCE(all_time, 0) + ?", traffic.Up+traffic.Down),
|
||||||
}).Error
|
}).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -962,6 +962,7 @@ func (s *InboundService) addClientTraffic(tx *gorm.DB, traffics []*xray.ClientTr
|
||||||
if dbClientTraffics[dbTraffic_index].Email == traffics[traffic_index].Email {
|
if dbClientTraffics[dbTraffic_index].Email == traffics[traffic_index].Email {
|
||||||
dbClientTraffics[dbTraffic_index].Up += traffics[traffic_index].Up
|
dbClientTraffics[dbTraffic_index].Up += traffics[traffic_index].Up
|
||||||
dbClientTraffics[dbTraffic_index].Down += traffics[traffic_index].Down
|
dbClientTraffics[dbTraffic_index].Down += traffics[traffic_index].Down
|
||||||
|
dbClientTraffics[dbTraffic_index].AllTime += (traffics[traffic_index].Up + traffics[traffic_index].Down)
|
||||||
|
|
||||||
// Add user in onlineUsers array on traffic
|
// Add user in onlineUsers array on traffic
|
||||||
if traffics[traffic_index].Up+traffics[traffic_index].Down > 0 {
|
if traffics[traffic_index].Up+traffics[traffic_index].Down > 0 {
|
||||||
|
@ -2036,6 +2037,25 @@ func (s *InboundService) MigrationRequirements() {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Calculate and backfill all_time from up+down for inbounds and clients
|
||||||
|
err = tx.Exec(`
|
||||||
|
UPDATE inbounds
|
||||||
|
SET all_time = IFNULL(up, 0) + IFNULL(down, 0)
|
||||||
|
WHERE IFNULL(all_time, 0) = 0 AND (IFNULL(up, 0) + IFNULL(down, 0)) > 0
|
||||||
|
`).Error
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = tx.Exec(`
|
||||||
|
UPDATE client_traffics
|
||||||
|
SET all_time = IFNULL(up, 0) + IFNULL(down, 0)
|
||||||
|
WHERE IFNULL(all_time, 0) = 0 AND (IFNULL(up, 0) + IFNULL(down, 0)) > 0
|
||||||
|
`).Error
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Fix inbounds based problems
|
// Fix inbounds based problems
|
||||||
var inbounds []*model.Inbound
|
var inbounds []*model.Inbound
|
||||||
err = tx.Model(model.Inbound{}).Where("protocol IN (?)", []string{"vmess", "vless", "trojan"}).Find(&inbounds).Error
|
err = tx.Model(model.Inbound{}).Where("protocol IN (?)", []string{"vmess", "vless", "trojan"}).Find(&inbounds).Error
|
||||||
|
|
|
@ -151,6 +151,8 @@
|
||||||
"getConfigError" = "حدث خطأ أثناء استرجاع ملف الإعدادات"
|
"getConfigError" = "حدث خطأ أثناء استرجاع ملف الإعدادات"
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
|
"allTimeTraffic" = "إجمالي حركة المرور"
|
||||||
|
"allTimeTrafficUsage" = "إجمالي الاستخدام طوال الوقت"
|
||||||
"title" = "الإدخالات"
|
"title" = "الإدخالات"
|
||||||
"totalDownUp" = "إجمالي المرسل/المستقبل"
|
"totalDownUp" = "إجمالي المرسل/المستقبل"
|
||||||
"totalUsage" = "إجمالي الاستخدام"
|
"totalUsage" = "إجمالي الاستخدام"
|
||||||
|
|
|
@ -151,6 +151,8 @@
|
||||||
"getConfigError" = "An error occurred while retrieving the config file."
|
"getConfigError" = "An error occurred while retrieving the config file."
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
|
"allTimeTraffic" = "All-time Traffic"
|
||||||
|
"allTimeTrafficUsage" = "All Time Total Usage"
|
||||||
"title" = "Inbounds"
|
"title" = "Inbounds"
|
||||||
"totalDownUp" = "Total Sent/Received"
|
"totalDownUp" = "Total Sent/Received"
|
||||||
"totalUsage" = "Total Usage"
|
"totalUsage" = "Total Usage"
|
||||||
|
|
|
@ -151,6 +151,8 @@
|
||||||
"getConfigError" = "Ocurrió un error al obtener el archivo de configuración"
|
"getConfigError" = "Ocurrió un error al obtener el archivo de configuración"
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
|
"allTimeTraffic" = "Tráfico Total"
|
||||||
|
"allTimeTrafficUsage" = "Uso total de todos los tiempos"
|
||||||
"title" = "Entradas"
|
"title" = "Entradas"
|
||||||
"totalDownUp" = "Subidas/Descargas Totales"
|
"totalDownUp" = "Subidas/Descargas Totales"
|
||||||
"totalUsage" = "Uso Total"
|
"totalUsage" = "Uso Total"
|
||||||
|
|
|
@ -151,6 +151,8 @@
|
||||||
"getConfigError" = "خطا در دریافت فایل پیکربندی"
|
"getConfigError" = "خطا در دریافت فایل پیکربندی"
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
|
"allTimeTraffic" = "کل ترافیک"
|
||||||
|
"allTimeTrafficUsage" = "کل استفاده در تمام مدت"
|
||||||
"title" = "کاربران"
|
"title" = "کاربران"
|
||||||
"totalDownUp" = "دریافت/ارسال کل"
|
"totalDownUp" = "دریافت/ارسال کل"
|
||||||
"totalUsage" = "مصرف کل"
|
"totalUsage" = "مصرف کل"
|
||||||
|
|
|
@ -151,6 +151,8 @@
|
||||||
"getConfigError" = "Terjadi kesalahan saat mengambil file konfigurasi"
|
"getConfigError" = "Terjadi kesalahan saat mengambil file konfigurasi"
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
|
"allTimeTraffic" = "Total Lalu Lintas"
|
||||||
|
"allTimeTrafficUsage" = "Total Penggunaan Sepanjang Waktu"
|
||||||
"title" = "Masuk"
|
"title" = "Masuk"
|
||||||
"totalDownUp" = "Total Terkirim/Diterima"
|
"totalDownUp" = "Total Terkirim/Diterima"
|
||||||
"totalUsage" = "Penggunaan Total"
|
"totalUsage" = "Penggunaan Total"
|
||||||
|
|
|
@ -151,6 +151,8 @@
|
||||||
"getConfigError" = "設定ファイルの取得中にエラーが発生しました"
|
"getConfigError" = "設定ファイルの取得中にエラーが発生しました"
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
|
"allTimeTraffic" = "総トラフィック"
|
||||||
|
"allTimeTrafficUsage" = "これまでの総使用量"
|
||||||
"title" = "インバウンド一覧"
|
"title" = "インバウンド一覧"
|
||||||
"totalDownUp" = "総アップロード / ダウンロード"
|
"totalDownUp" = "総アップロード / ダウンロード"
|
||||||
"totalUsage" = "総使用量"
|
"totalUsage" = "総使用量"
|
||||||
|
|
|
@ -151,6 +151,8 @@
|
||||||
"getConfigError" = "Ocorreu um erro ao recuperar o arquivo de configuração"
|
"getConfigError" = "Ocorreu um erro ao recuperar o arquivo de configuração"
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
|
"allTimeTraffic" = "Tráfego Total"
|
||||||
|
"allTimeTrafficUsage" = "Uso total de todos os tempos"
|
||||||
"title" = "Inbounds"
|
"title" = "Inbounds"
|
||||||
"totalDownUp" = "Total Enviado/Recebido"
|
"totalDownUp" = "Total Enviado/Recebido"
|
||||||
"totalUsage" = "Uso Total"
|
"totalUsage" = "Uso Total"
|
||||||
|
|
|
@ -151,6 +151,8 @@
|
||||||
"getConfigError" = "Произошла ошибка при получении конфигурационного файла"
|
"getConfigError" = "Произошла ошибка при получении конфигурационного файла"
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
|
"allTimeTraffic" = "Общий трафик"
|
||||||
|
"allTimeTrafficUsage" = "Общее использование за все время"
|
||||||
"title" = "Инбаунды"
|
"title" = "Инбаунды"
|
||||||
"totalDownUp" = "Объем отправленного/полученного трафика"
|
"totalDownUp" = "Объем отправленного/полученного трафика"
|
||||||
"totalUsage" = "Всего трафика"
|
"totalUsage" = "Всего трафика"
|
||||||
|
|
|
@ -151,6 +151,8 @@
|
||||||
"getConfigError" = "Yapılandırma dosyası alınırken bir hata oluştu"
|
"getConfigError" = "Yapılandırma dosyası alınırken bir hata oluştu"
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
|
"allTimeTraffic" = "Toplam Trafik"
|
||||||
|
"allTimeTrafficUsage" = "Tüm Zamanların Toplam Kullanımı"
|
||||||
"title" = "Gelenler"
|
"title" = "Gelenler"
|
||||||
"totalDownUp" = "Toplam Gönderilen/Alınan"
|
"totalDownUp" = "Toplam Gönderilen/Alınan"
|
||||||
"totalUsage" = "Toplam Kullanım"
|
"totalUsage" = "Toplam Kullanım"
|
||||||
|
|
|
@ -151,6 +151,8 @@
|
||||||
"getConfigError" = "Виникла помилка під час отримання файлу конфігурації"
|
"getConfigError" = "Виникла помилка під час отримання файлу конфігурації"
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
|
"allTimeTraffic" = "Загальний трафік"
|
||||||
|
"allTimeTrafficUsage" = "Загальне використання за весь час"
|
||||||
"title" = "Вхідні"
|
"title" = "Вхідні"
|
||||||
"totalDownUp" = "Всього надісланих/отриманих"
|
"totalDownUp" = "Всього надісланих/отриманих"
|
||||||
"totalUsage" = "Всього використанно"
|
"totalUsage" = "Всього використанно"
|
||||||
|
|
|
@ -151,6 +151,8 @@
|
||||||
"getConfigError" = "Lỗi xảy ra khi truy xuất tệp cấu hình"
|
"getConfigError" = "Lỗi xảy ra khi truy xuất tệp cấu hình"
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
|
"allTimeTraffic" = "Tổng Lưu Lượng"
|
||||||
|
"allTimeTrafficUsage" = "Tổng mức sử dụng mọi lúc"
|
||||||
"title" = "Điểm vào (Inbounds)"
|
"title" = "Điểm vào (Inbounds)"
|
||||||
"totalDownUp" = "Tổng tải lên/tải xuống"
|
"totalDownUp" = "Tổng tải lên/tải xuống"
|
||||||
"totalUsage" = "Tổng sử dụng"
|
"totalUsage" = "Tổng sử dụng"
|
||||||
|
|
|
@ -151,6 +151,8 @@
|
||||||
"getConfigError" = "检索配置文件时出错"
|
"getConfigError" = "检索配置文件时出错"
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
|
"allTimeTraffic" = "累计总流量"
|
||||||
|
"allTimeTrafficUsage" = "所有时间总使用量"
|
||||||
"title" = "入站列表"
|
"title" = "入站列表"
|
||||||
"totalDownUp" = "总上传 / 下载"
|
"totalDownUp" = "总上传 / 下载"
|
||||||
"totalUsage" = "总用量"
|
"totalUsage" = "总用量"
|
||||||
|
|
|
@ -151,6 +151,8 @@
|
||||||
"getConfigError" = "檢索設定檔時發生錯誤"
|
"getConfigError" = "檢索設定檔時發生錯誤"
|
||||||
|
|
||||||
[pages.inbounds]
|
[pages.inbounds]
|
||||||
|
"allTimeTraffic" = "累計總流量"
|
||||||
|
"allTimeTrafficUsage" = "所有时间总使用量"
|
||||||
"title" = "入站列表"
|
"title" = "入站列表"
|
||||||
"totalDownUp" = "總上傳 / 下載"
|
"totalDownUp" = "總上傳 / 下載"
|
||||||
"totalUsage" = "總用量"
|
"totalUsage" = "總用量"
|
||||||
|
|
|
@ -7,6 +7,7 @@ type ClientTraffic struct {
|
||||||
Email string `json:"email" form:"email" gorm:"unique"`
|
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"`
|
||||||
|
AllTime int64 `json:"allTime" form:"allTime"`
|
||||||
ExpiryTime int64 `json:"expiryTime" form:"expiryTime"`
|
ExpiryTime int64 `json:"expiryTime" form:"expiryTime"`
|
||||||
Total int64 `json:"total" form:"total"`
|
Total int64 `json:"total" form:"total"`
|
||||||
Reset int `json:"reset" form:"reset" gorm:"default:0"`
|
Reset int `json:"reset" form:"reset" gorm:"default:0"`
|
||||||
|
|
|
@ -14,7 +14,6 @@ type InboundConfig struct {
|
||||||
StreamSettings json_util.RawMessage `json:"streamSettings"`
|
StreamSettings json_util.RawMessage `json:"streamSettings"`
|
||||||
Tag string `json:"tag"`
|
Tag string `json:"tag"`
|
||||||
Sniffing json_util.RawMessage `json:"sniffing"`
|
Sniffing json_util.RawMessage `json:"sniffing"`
|
||||||
Allocate json_util.RawMessage `json:"allocate"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *InboundConfig) Equals(other *InboundConfig) bool {
|
func (c *InboundConfig) Equals(other *InboundConfig) bool {
|
||||||
|
@ -39,8 +38,5 @@ func (c *InboundConfig) Equals(other *InboundConfig) bool {
|
||||||
if !bytes.Equal(c.Sniffing, other.Sniffing) {
|
if !bytes.Equal(c.Sniffing, other.Sniffing) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !bytes.Equal(c.Allocate, other.Allocate) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue