mirror of
https://github.com/alireza0/x-ui.git
synced 2026-03-22 00:35:48 +00:00
[feature] import-export inbound #699
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"x-ui/database/model"
|
"x-ui/database/model"
|
||||||
@@ -35,6 +36,7 @@ func (a *InboundController) initRouter(g *gin.RouterGroup) {
|
|||||||
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)
|
||||||
|
g.POST("/import", a.importInbound)
|
||||||
g.POST("/onlines", a.onlines)
|
g.POST("/onlines", a.onlines)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,6 +256,31 @@ func (a *InboundController) delDepletedClients(c *gin.Context) {
|
|||||||
jsonMsg(c, "All delpeted clients are deleted", nil)
|
jsonMsg(c, "All delpeted clients are deleted", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *InboundController) importInbound(c *gin.Context) {
|
||||||
|
inbound := &model.Inbound{}
|
||||||
|
err := json.Unmarshal([]byte(c.PostForm("data")), inbound)
|
||||||
|
if err != nil {
|
||||||
|
jsonMsg(c, "Something went wrong!", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
user := session.GetLoginUser(c)
|
||||||
|
inbound.Id = 0
|
||||||
|
inbound.UserId = user.Id
|
||||||
|
inbound.Tag = fmt.Sprintf("inbound-%v", inbound.Port)
|
||||||
|
|
||||||
|
for index := range inbound.ClientStats {
|
||||||
|
inbound.ClientStats[index].Id = 0
|
||||||
|
inbound.ClientStats[index].Enable = true
|
||||||
|
}
|
||||||
|
|
||||||
|
needRestart := false
|
||||||
|
inbound, needRestart, err = a.inboundService.AddInbound(inbound)
|
||||||
|
jsonMsgObj(c, I18nWeb(c, "pages.inbounds.create"), inbound, err)
|
||||||
|
if err == nil && needRestart {
|
||||||
|
a.xrayService.SetToNeedRestart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a *InboundController) onlines(c *gin.Context) {
|
func (a *InboundController) onlines(c *gin.Context) {
|
||||||
jsonObj(c, a.inboundService.GetOnlineClinets(), nil)
|
jsonObj(c, a.inboundService.GetOnlineClinets(), nil)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,10 @@
|
|||||||
this.clipboard = new ClipboardJS('#txt-modal-ok-btn', {
|
this.clipboard = new ClipboardJS('#txt-modal-ok-btn', {
|
||||||
text: () => this.content,
|
text: () => this.content,
|
||||||
});
|
});
|
||||||
this.clipboard.on('success', () => app.$message.success('{{ i18n "copied" }}'));
|
this.clipboard.on('success', () => {
|
||||||
|
app.$message.success('{{ i18n "copied" }}')
|
||||||
|
this.close();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -125,6 +125,10 @@
|
|||||||
<template v-if="!isMobile">{{ i18n "pages.inbounds.generalActions" }}</template>
|
<template v-if="!isMobile">{{ i18n "pages.inbounds.generalActions" }}</template>
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-menu slot="overlay" @click="a => generalActions(a)" :theme="themeSwitcher.currentTheme">
|
<a-menu slot="overlay" @click="a => generalActions(a)" :theme="themeSwitcher.currentTheme">
|
||||||
|
<a-menu-item key="import">
|
||||||
|
<a-icon type="import"></a-icon>
|
||||||
|
{{ i18n "pages.inbounds.importInbound" }}
|
||||||
|
</a-menu-item>
|
||||||
<a-menu-item key="export">
|
<a-menu-item key="export">
|
||||||
<a-icon type="export"></a-icon>
|
<a-icon type="export"></a-icon>
|
||||||
{{ i18n "pages.inbounds.export" }}
|
{{ i18n "pages.inbounds.export" }}
|
||||||
@@ -226,6 +230,10 @@
|
|||||||
<a-menu-item key="resetTraffic">
|
<a-menu-item key="resetTraffic">
|
||||||
<a-icon type="retweet"></a-icon> {{ i18n "pages.inbounds.resetTraffic" }}
|
<a-icon type="retweet"></a-icon> {{ i18n "pages.inbounds.resetTraffic" }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
|
<a-menu-item key="clipboard">
|
||||||
|
<a-icon type="copy"></a-icon>
|
||||||
|
{{ i18n "pages.inbounds.copyToClipboard" }}
|
||||||
|
</a-menu-item>
|
||||||
<a-menu-item key="clone">
|
<a-menu-item key="clone">
|
||||||
<a-icon type="block"></a-icon> {{ i18n "pages.inbounds.clone"}}
|
<a-icon type="block"></a-icon> {{ i18n "pages.inbounds.clone"}}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
@@ -707,6 +715,9 @@
|
|||||||
},
|
},
|
||||||
generalActions(action) {
|
generalActions(action) {
|
||||||
switch (action.key) {
|
switch (action.key) {
|
||||||
|
case "import":
|
||||||
|
this.importInbound();
|
||||||
|
break;
|
||||||
case "export":
|
case "export":
|
||||||
this.exportAllLinks();
|
this.exportAllLinks();
|
||||||
break;
|
break;
|
||||||
@@ -741,6 +752,9 @@
|
|||||||
case "export":
|
case "export":
|
||||||
this.inboundLinks(dbInbound.id);
|
this.inboundLinks(dbInbound.id);
|
||||||
break;
|
break;
|
||||||
|
case "clipboard":
|
||||||
|
this.copyToClipboard(dbInbound.id);
|
||||||
|
break;
|
||||||
case "resetTraffic":
|
case "resetTraffic":
|
||||||
this.resetTraffic(dbInbound.id);
|
this.resetTraffic(dbInbound.id);
|
||||||
break;
|
break;
|
||||||
@@ -792,7 +806,7 @@
|
|||||||
this.$confirm({
|
this.$confirm({
|
||||||
title: '{{ i18n "pages.inbounds.cloneInbound"}} \"' + dbInbound.remark + '\"',
|
title: '{{ i18n "pages.inbounds.cloneInbound"}} \"' + dbInbound.remark + '\"',
|
||||||
content: '{{ i18n "pages.inbounds.cloneInboundContent"}}',
|
content: '{{ i18n "pages.inbounds.cloneInboundContent"}}',
|
||||||
okText: '{{ i18n "pages.inbounds.update"}}',
|
okText: '{{ i18n "pages.inbounds.clone"}}',
|
||||||
class: themeSwitcher.currentTheme,
|
class: themeSwitcher.currentTheme,
|
||||||
cancelText: '{{ i18n "cancel" }}',
|
cancelText: '{{ i18n "cancel" }}',
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
@@ -1160,6 +1174,18 @@
|
|||||||
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||||
newDbInbound = this.checkFallback(dbInbound);
|
newDbInbound = this.checkFallback(dbInbound);
|
||||||
txtModal.show('{{ i18n "pages.inbounds.export"}}', newDbInbound.genInboundLinks, newDbInbound.remark);
|
txtModal.show('{{ i18n "pages.inbounds.export"}}', newDbInbound.genInboundLinks, newDbInbound.remark);
|
||||||
|
},
|
||||||
|
importInbound() {
|
||||||
|
promptModal.open({
|
||||||
|
title: '{{ i18n "pages.inbounds.importInbound" }}',
|
||||||
|
type: 'textarea',
|
||||||
|
value: '',
|
||||||
|
okText: '{{ i18n "pages.inbounds.import" }}',
|
||||||
|
confirm: async (dbInboundText) => {
|
||||||
|
await this.submit('/xui/inbound/import', {data: dbInboundText}, promptModal);
|
||||||
|
promptModal.close();
|
||||||
|
},
|
||||||
|
});
|
||||||
},
|
},
|
||||||
exportAllLinks() {
|
exportAllLinks() {
|
||||||
let copyText = [];
|
let copyText = [];
|
||||||
@@ -1168,6 +1194,10 @@
|
|||||||
}
|
}
|
||||||
txtModal.show('{{ i18n "pages.inbounds.export"}}', copyText.join('\r\n'), 'All-Inbounds');
|
txtModal.show('{{ i18n "pages.inbounds.export"}}', copyText.join('\r\n'), 'All-Inbounds');
|
||||||
},
|
},
|
||||||
|
copyToClipboard(dbInboundId) {
|
||||||
|
dbInbound = this.dbInbounds.find(row => row.id === dbInboundId);
|
||||||
|
txtModal.show('{{ i18n "pages.inbounds.inboundData" }}', JSON.stringify(dbInbound, null, 2));
|
||||||
|
},
|
||||||
async startDataRefreshLoop() {
|
async startDataRefreshLoop() {
|
||||||
while (this.isRefreshEnabled) {
|
while (this.isRefreshEnabled) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -168,9 +168,13 @@ func (s *InboundService) AddInbound(inbound *model.Inbound) (*model.Inbound, boo
|
|||||||
|
|
||||||
err = tx.Save(inbound).Error
|
err = tx.Save(inbound).Error
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for _, client := range clients {
|
if len(inbound.ClientStats) == 0 {
|
||||||
s.AddClientStat(tx, inbound.Id, &client)
|
for _, client := range clients {
|
||||||
|
s.AddClientStat(tx, inbound.Id, &client)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return inbound, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
needRestart := false
|
needRestart := false
|
||||||
|
|||||||
@@ -170,6 +170,10 @@
|
|||||||
"subscriptionDesc" = "You can find your sub link on Details, also you can use the same name for several configurations"
|
"subscriptionDesc" = "You can find your sub link on Details, also you can use the same name for several configurations"
|
||||||
"info" = "Info"
|
"info" = "Info"
|
||||||
"same" = "Same"
|
"same" = "Same"
|
||||||
|
"inboundData" = "Inbound's data"
|
||||||
|
"copyToClipboard" = "Copy to clipboard"
|
||||||
|
"import" = "Import"
|
||||||
|
"importInbound" = "Import an inbound"
|
||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "Add Client"
|
"add" = "Add Client"
|
||||||
|
|||||||
@@ -148,7 +148,7 @@
|
|||||||
"client" = "کاربر"
|
"client" = "کاربر"
|
||||||
"export" = "استخراج لینکها"
|
"export" = "استخراج لینکها"
|
||||||
"clone" = "شبیه سازی"
|
"clone" = "شبیه سازی"
|
||||||
"cloneInbound" = "ایجاد"
|
"cloneInbound" = "شبیهسازی سرویس"
|
||||||
"cloneInboundContent" = "همه موارد این ورودی بجز پورت ، ای پی و کلاینت ها شبیه سازی خواهند شد"
|
"cloneInboundContent" = "همه موارد این ورودی بجز پورت ، ای پی و کلاینت ها شبیه سازی خواهند شد"
|
||||||
"resetAllTraffic" = "ریست ترافیک کل سرویس ها"
|
"resetAllTraffic" = "ریست ترافیک کل سرویس ها"
|
||||||
"resetAllTrafficTitle" = "ریست ترافیک کل سرویس ها"
|
"resetAllTrafficTitle" = "ریست ترافیک کل سرویس ها"
|
||||||
@@ -169,6 +169,10 @@
|
|||||||
"subscriptionDesc" = "می توانید ساب لینک خود را در جزئیات پیدا کنید، همچنین می توانید از همین نام برای چندین کانفیگ استفاده کنید"
|
"subscriptionDesc" = "می توانید ساب لینک خود را در جزئیات پیدا کنید، همچنین می توانید از همین نام برای چندین کانفیگ استفاده کنید"
|
||||||
"info" = "اطلاعات"
|
"info" = "اطلاعات"
|
||||||
"same" = "همسان"
|
"same" = "همسان"
|
||||||
|
"inboundData" = "دادههای سرویس"
|
||||||
|
"copyToClipboard" = "کپی در حافظه"
|
||||||
|
"import" = "وارد کردن"
|
||||||
|
"importInbound" = "وارد کردن یک سرویس"
|
||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "کاربر جدید"
|
"add" = "کاربر جدید"
|
||||||
|
|||||||
@@ -170,6 +170,10 @@
|
|||||||
"subscriptionDesc" = "вы можете найти свою ссылку подписки в разделе «Подробнее», также вы можете использовать одно и то же имя для нескольких конфигов"
|
"subscriptionDesc" = "вы можете найти свою ссылку подписки в разделе «Подробнее», также вы можете использовать одно и то же имя для нескольких конфигов"
|
||||||
"info" = "Информация"
|
"info" = "Информация"
|
||||||
"same" = "Тот же"
|
"same" = "Тот же"
|
||||||
|
"inboundData" = "Входящие данные"
|
||||||
|
"copyToClipboard" = "Копировать в буфер обмена"
|
||||||
|
"import" = "Импортировать"
|
||||||
|
"importInbound" = "Импортировать входящее сообщение"
|
||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "Добавить клиента"
|
"add" = "Добавить клиента"
|
||||||
|
|||||||
@@ -170,6 +170,10 @@
|
|||||||
"subscriptionDesc" = "Bạn có thể tìm thấy liên kết phụ của mình trên Chi tiết, bạn cũng có thể sử dụng cùng tên cho một số cấu hình"
|
"subscriptionDesc" = "Bạn có thể tìm thấy liên kết phụ của mình trên Chi tiết, bạn cũng có thể sử dụng cùng tên cho một số cấu hình"
|
||||||
"info" = "Thông tin"
|
"info" = "Thông tin"
|
||||||
"same" = "Như nhau"
|
"same" = "Như nhau"
|
||||||
|
"inboundData" = "Dữ liệu gửi đến"
|
||||||
|
"copyToClipboard" = "Sao chép vào bảng nhớ tạm"
|
||||||
|
"import" = "Nhập"
|
||||||
|
"importInbound" = "Nhập hàng gửi về"
|
||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "Thêm máy khách"
|
"add" = "Thêm máy khách"
|
||||||
|
|||||||
@@ -170,6 +170,10 @@
|
|||||||
"subscriptionDesc" = "您可以在详细信息上找到您的子链接,也可以对多个配置使用相同的名称"
|
"subscriptionDesc" = "您可以在详细信息上找到您的子链接,也可以对多个配置使用相同的名称"
|
||||||
"info" = "信息"
|
"info" = "信息"
|
||||||
"same" = "相同"
|
"same" = "相同"
|
||||||
|
"inboundData" = "入站数据"
|
||||||
|
"copyToClipboard" = "复制到剪贴板"
|
||||||
|
"import"="导入"
|
||||||
|
"importInbound" = "导入入站"
|
||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "添加客户端"
|
"add" = "添加客户端"
|
||||||
|
|||||||
Reference in New Issue
Block a user