Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
Diffstat (limited to 'web')
-rw-r--r--web/controller/server.go7
-rw-r--r--web/html/index.html114
-rw-r--r--web/service/server.go32
3 files changed, 151 insertions, 2 deletions
diff --git a/web/controller/server.go b/web/controller/server.go
index 8a7a2198..dd001f5e 100644
--- a/web/controller/server.go
+++ b/web/controller/server.go
@@ -46,6 +46,7 @@ func (a *ServerController) initRouter(g *gin.RouterGroup) {
g.POST("/installXray/:version", a.installXray)
g.POST("/updateGeofile/:fileName", a.updateGeofile)
g.POST("/logs/:count", a.getLogs)
+ g.POST("/xraylogs/:count", a.getXrayLogs)
g.POST("/getConfigJson", a.getConfigJson)
g.GET("/getDb", a.getDb)
g.POST("/importDB", a.importDB)
@@ -134,6 +135,12 @@ func (a *ServerController) getLogs(c *gin.Context) {
jsonObj(c, logs, nil)
}
+func (a *ServerController) getXrayLogs(c *gin.Context) {
+ count := c.Param("count")
+ logs := a.serverService.GetXrayLogs(count)
+ jsonObj(c, logs, nil)
+}
+
func (a *ServerController) getConfigJson(c *gin.Context) {
configJson, err := a.serverService.GetConfigJson()
if err != nil {
diff --git a/web/html/index.html b/web/html/index.html
index db678cd6..4089e6a6 100644
--- a/web/html/index.html
+++ b/web/html/index.html
@@ -167,7 +167,10 @@
<span>{{ i18n "pages.index.xrayErrorPopoverTitle" }}</span>
</a-col>
<a-col>
- <a-icon type="bars" :style="{ cursor: 'pointer', float: 'right' }" @click="openLogs()"></a-tag>
+ <a-icon type="bars" :style="{ cursor: 'pointer', float: 'right' }" @click="openLogs()"></a-icon>
+ </a-col>
+ <a-col>
+ <a-icon type="bars" :style="{ cursor: 'pointer', float: 'right' }" @click="openXrayLogs()"></a-icon>
</a-col>
</a-row>
</span>
@@ -179,6 +182,10 @@
</template>
</template>
<template #actions>
+ <a-space v-if="app.ipLimitEnable" direction="horizontal" @click="openXrayLogs()" :style="{ justifyContent: 'center' }">
+ <a-icon type="bars"></a-icon>
+ <span v-if="!isMobile">{{ i18n "pages.index.logs" }}</span>
+ </a-space>
<a-space direction="horizontal" @click="stopXrayService" :style="{ justifyContent: 'center' }">
<a-icon type="poweroff"></a-icon>
<span v-if="!isMobile">{{ i18n "pages.index.stopXray" }}</span>
@@ -422,6 +429,40 @@
</a-form>
<div class="ant-input" :style="{ height: 'auto', maxHeight: '500px', overflow: 'auto', marginTop: '0.5rem' }" v-html="logModal.formattedLogs"></div>
</a-modal>
+ <a-modal id="xraylog-modal"
+ v-model="xraylogModal.visible"
+ :closable="true" @cancel="() => xraylogModal.visible = false"
+ :class="themeSwitcher.currentTheme"
+ width="80vw"
+ footer="">
+ <template slot="title">
+ {{ i18n "pages.index.logs" }}
+ <a-icon :spin="xraylogModal.loading"
+ type="sync"
+ :style="{ verticalAlign: 'middle', marginLeft: '10px' }"
+ :disabled="xraylogModal.loading"
+ @click="openXrayLogs()">
+ </a-icon>
+ </template>
+ <a-form layout="inline">
+ <a-form-item :style="{ marginRight: '0.5rem' }">
+ <a-input-group compact>
+ <a-select size="small" v-model="xraylogModal.rows" :style="{ width: '70px' }"
+ @change="openXrayLogs()" :dropdown-class-name="themeSwitcher.currentTheme">
+ <a-select-option value="10">10</a-select-option>
+ <a-select-option value="20">20</a-select-option>
+ <a-select-option value="50">50</a-select-option>
+ <a-select-option value="100">100</a-select-option>
+ <a-select-option value="500">500</a-select-option>
+ </a-select>
+ </a-input-group>
+ </a-form-item>
+ <a-form-item :style="{ float: 'right' }">
+ <a-button type="primary" icon="download" @click="FileManager.downloadTextFile(xraylogModal.logs?.join('\n'), 'x-ui.log')"></a-button>
+ </a-form-item>
+ </a-form>
+ <div class="ant-input" :style="{ height: 'auto', maxHeight: '500px', overflow: 'auto', marginTop: '0.5rem' }" v-html="xraylogModal.formattedLogs"></div>
+ </a-modal>
<a-modal id="backup-modal"
v-model="backupModal.visible"
title='{{ i18n "pages.index.backupTitle" }}'
@@ -606,6 +647,57 @@
},
};
+ const xraylogModal = {
+ visible: false,
+ logs: [],
+ rows: 20,
+ loading: false,
+ show(logs) {
+ this.visible = true;
+ this.logs = logs;
+ this.formattedLogs = this.logs?.length > 0 ? this.formatLogs(this.logs) : "No Record...";
+ },
+ formatLogs(logs) {
+ let formattedLogs = '';
+
+ logs.forEach((log, index) => {
+ if(index > 0) formattedLogs += '<br>';
+
+ const parts = log.split(' ');
+
+ if(parts.length === 9) {
+ const dateTime = `<b>${parts[0]} ${parts[1]}</b>`;
+ const from = `<b>${parts[3]}</b>`;
+ const to = `<b>${parts[5].replace(/^\/+/, "")}</b>`;
+
+ let outboundColor = '';
+ if (parts[8].startsWith('blocked')) {
+ outboundColor = ' style="color: #e04141;"';
+ }
+ else if (!parts[8].startsWith('direct')) {
+ outboundColor = ' style="color: #3c89e8;"';
+ }
+
+ formattedLogs += `<span${outboundColor}>
+${dateTime}
+ ${parts[2]}
+ ${from}
+ ${parts[4]}
+ ${to}
+ ${parts.slice(6).join(' ')}
+</span>`;
+ } else {
+ formattedLogs += `<span>${parts.join(' ')}</span>`;
+ }
+ });
+
+ return formattedLogs;
+ },
+ hide() {
+ this.visible = false;
+ },
+ };
+
const backupModal = {
visible: false,
show() {
@@ -629,10 +721,12 @@
status: new Status(),
versionModal,
logModal,
+ xraylogModal,
backupModal,
loadingTip: '{{ i18n "loading"}}',
showAlert: false,
- showIp: false
+ showIp: false,
+ ipLimitEnable: false,
},
methods: {
loading(spinning, tip = '{{ i18n "loading"}}') {
@@ -721,6 +815,16 @@
await PromiseUtil.sleep(500);
logModal.loading = false;
},
+ async openXrayLogs(){
+ xraylogModal.loading = true;
+ const msg = await HttpUtil.post('server/xraylogs/'+xraylogModal.rows);
+ if (!msg.success) {
+ return;
+ }
+ xraylogModal.show(msg.obj);
+ await PromiseUtil.sleep(500);
+ xraylogModal.loading = false;
+ },
async openConfig() {
this.loading(true);
const msg = await HttpUtil.post('server/getConfigJson');
@@ -773,6 +877,12 @@
if (window.location.protocol !== "https:") {
this.showAlert = true;
}
+
+ const msg = await HttpUtil.post('/panel/setting/defaultSettings');
+ if (msg.success) {
+ this.ipLimitEnable = msg.obj.ipLimitEnable;
+ }
+
while (true) {
try {
await this.getStatus();
diff --git a/web/service/server.go b/web/service/server.go
index f0be46c2..ade5b521 100644
--- a/web/service/server.go
+++ b/web/service/server.go
@@ -2,6 +2,7 @@ package service
import (
"archive/zip"
+ "bufio"
"bytes"
"encoding/json"
"fmt"
@@ -481,6 +482,37 @@ func (s *ServerService) GetLogs(count string, level string, syslog string) []str
return lines
}
+func (s *ServerService) GetXrayLogs(count string) []string {
+ c, _ := strconv.Atoi(count)
+ var lines []string
+
+ pathToAccessLog, err := xray.GetAccessLogPath()
+ if err != nil {
+ return lines
+ }
+
+ file, err := os.Open(pathToAccessLog)
+ if err != nil {
+ return lines
+ }
+ defer file.Close()
+
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ line := scanner.Text()
+ if strings.TrimSpace(line) == "" || strings.Contains(line, "api -> api") {
+ continue
+ }
+ lines = append(lines, line)
+ }
+
+ if len(lines) > c {
+ lines = lines[len(lines)-c:]
+ }
+
+ return lines
+}
+
func (s *ServerService) GetConfigJson() (any, error) {
config, err := s.xrayService.GetXrayConfig()
if err != nil {