diff --git a/config/version b/config/version
index 341cf11..9325c3c 100644
--- a/config/version
+++ b/config/version
@@ -1 +1 @@
-0.2.0
\ No newline at end of file
+0.3.0
\ No newline at end of file
diff --git a/logger/logger.go b/logger/logger.go
index bc7c3b7..cb5e836 100644
--- a/logger/logger.go
+++ b/logger/logger.go
@@ -7,16 +7,22 @@ import (
var logger *logging.Logger
+func init() {
+ InitLogger(logging.INFO)
+}
+
func InitLogger(level logging.Level) {
format := logging.MustStringFormatter(
`%{time:2006/01/02 15:04:05} %{level} - %{message}`,
)
- logger = logging.MustGetLogger("x-ui")
+ newLogger := logging.MustGetLogger("x-ui")
backend := logging.NewLogBackend(os.Stderr, "", 0)
backendFormatter := logging.NewBackendFormatter(backend, format)
backendLeveled := logging.AddModuleLevel(backendFormatter)
backendLeveled.SetLevel(level, "")
- logger.SetBackend(backendLeveled)
+ newLogger.SetBackend(backendLeveled)
+
+ logger = newLogger
}
func Debug(args ...interface{}) {
diff --git a/util/sys/a.s b/util/sys/a.s
new file mode 100644
index 0000000..e69de29
diff --git a/util/sys/psutil.go b/util/sys/psutil.go
new file mode 100644
index 0000000..645f839
--- /dev/null
+++ b/util/sys/psutil.go
@@ -0,0 +1,8 @@
+package sys
+
+import (
+ _ "unsafe"
+)
+
+//go:linkname HostProc github.com/shirou/gopsutil/internal/common.HostProc
+func HostProc(combineWith ...string) string
diff --git a/util/sys/sys_darwin.go b/util/sys/sys_darwin.go
new file mode 100644
index 0000000..d61a38a
--- /dev/null
+++ b/util/sys/sys_darwin.go
@@ -0,0 +1,23 @@
+// +build darwin
+
+package sys
+
+import (
+ "github.com/shirou/gopsutil/net"
+)
+
+func GetTCPCount() (int, error) {
+ stats, err := net.Connections("tcp")
+ if err != nil {
+ return 0, err
+ }
+ return len(stats), nil
+}
+
+func GetUDPCount() (int, error) {
+ stats, err := net.Connections("udp")
+ if err != nil {
+ return 0, err
+ }
+ return len(stats), nil
+}
diff --git a/util/sys/sys_linux.go b/util/sys/sys_linux.go
new file mode 100644
index 0000000..843d9b0
--- /dev/null
+++ b/util/sys/sys_linux.go
@@ -0,0 +1,70 @@
+// +build linux
+
+package sys
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os"
+)
+
+func getLinesNum(filename string) (int, error) {
+ file, err := os.Open(filename)
+ if err != nil {
+ return 0, err
+ }
+ defer file.Close()
+
+ sum := 0
+ buf := make([]byte, 8192)
+ for {
+ n, err := file.Read(buf)
+
+ var buffPosition int
+ for {
+ i := bytes.IndexByte(buf[buffPosition:], '\n')
+ if i < 0 || n == buffPosition {
+ break
+ }
+ buffPosition += i + 1
+ sum++
+ }
+
+ if err == io.EOF {
+ return sum, nil
+ } else if err != nil {
+ return sum, err
+ }
+ }
+}
+
+func GetTCPCount() (int, error) {
+ root := HostProc()
+
+ tcp4, err := getLinesNum(fmt.Sprintf("%v/net/tcp", root))
+ if err != nil {
+ return tcp4, err
+ }
+ tcp6, err := getLinesNum(fmt.Sprintf("%v/net/tcp6", root))
+ if err != nil {
+ return tcp4 + tcp6, nil
+ }
+
+ return tcp4 + tcp6, nil
+}
+
+func GetUDPCount() (int, error) {
+ root := HostProc()
+
+ udp4, err := getLinesNum(fmt.Sprintf("%v/net/udp", root))
+ if err != nil {
+ return udp4, err
+ }
+ udp6, err := getLinesNum(fmt.Sprintf("%v/net/udp6", root))
+ if err != nil {
+ return udp4 + udp6, nil
+ }
+
+ return udp4 + udp6, nil
+}
diff --git a/web/assets/js/model/models.js b/web/assets/js/model/models.js
index e0ad55d..4d26f1f 100644
--- a/web/assets/js/model/models.js
+++ b/web/assets/js/model/models.js
@@ -1,14 +1,18 @@
class User {
- username = "";
- password = "";
+
+ constructor() {
+ this.username = "";
+ this.password = "";
+ }
}
class Msg {
- success = false;
- msg = "";
- obj = null;
constructor(success, msg, obj) {
+ this.success = false;
+ this.msg = "";
+ this.obj = null;
+
if (success != null) {
this.success = success;
}
@@ -22,24 +26,25 @@ class Msg {
}
class DBInbound {
- id = 0;
- userId = 0;
- up = 0;
- down = 0;
- total = 0;
- remark = "";
- enable = true;
- expiryTime = 0;
-
- listen = "";
- port = 0;
- protocol = "";
- settings = "";
- streamSettings = "";
- tag = "";
- sniffing = "";
constructor(data) {
+ this.id = 0;
+ this.userId = 0;
+ this.up = 0;
+ this.down = 0;
+ this.total = 0;
+ this.remark = "";
+ this.enable = true;
+ this.expiryTime = 0;
+
+ this.listen = "";
+ this.port = 0;
+ this.protocol = "";
+ this.settings = "";
+ this.streamSettings = "";
+ this.tag = "";
+ this.sniffing = "";
+
if (data == null) {
return;
}
@@ -86,6 +91,25 @@ class DBInbound {
return address;
}
+ get _expiryTime() {
+ if (this.expiryTime === 0) {
+ return null;
+ }
+ return moment(this.expiryTime);
+ }
+
+ set _expiryTime(t) {
+ if (t == null) {
+ this.expiryTime = 0;
+ } else {
+ this.expiryTime = t.valueOf();
+ }
+ }
+
+ get isExpiry() {
+ return this.expiryTime < new Date().getTime();
+ }
+
toInbound() {
let settings = {};
if (!ObjectUtil.isEmpty(this.settings)) {
@@ -132,17 +156,18 @@ class DBInbound {
}
class AllSetting {
- webListen = "";
- webPort = 54321;
- webCertFile = "";
- webKeyFile = "";
- webBasePath = "/";
-
- xrayTemplateConfig = "";
-
- timeLocation = "Asia/Shanghai";
constructor(data) {
+ this.webListen = "";
+ this.webPort = 54321;
+ this.webCertFile = "";
+ this.webKeyFile = "";
+ this.webBasePath = "/";
+
+ this.xrayTemplateConfig = "";
+
+ this.timeLocation = "Asia/Shanghai";
+
if (data == null) {
return
}
diff --git a/web/assets/js/model/xray.js b/web/assets/js/model/xray.js
index 586a7b5..66a5980 100644
--- a/web/assets/js/model/xray.js
+++ b/web/assets/js/model/xray.js
@@ -1165,7 +1165,7 @@ Inbound.VmessSettings = class extends Inbound.Settings {
}
};
Inbound.VmessSettings.Vmess = class extends XrayCommonClass {
- constructor(id=RandomUtil.randomUUID(), alterId=64) {
+ constructor(id=RandomUtil.randomUUID(), alterId=0) {
super();
this.id = id;
this.alterId = alterId;
diff --git a/web/assets/js/util/utils.js b/web/assets/js/util/utils.js
index 9c6d38e..6b4e5ed 100644
--- a/web/assets/js/util/utils.js
+++ b/web/assets/js/util/utils.js
@@ -77,18 +77,19 @@ class PromiseUtil {
}
+const seq = [
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't',
+ 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N',
+ 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z'
+];
+
class RandomUtil {
- static seq = [
- 'a', 'b', 'c', 'd', 'e', 'f', 'g',
- 'h', 'i', 'j', 'k', 'l', 'm', 'n',
- 'o', 'p', 'q', 'r', 's', 't',
- 'u', 'v', 'w', 'x', 'y', 'z',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- 'A', 'B', 'C', 'D', 'E', 'F', 'G',
- 'H', 'I', 'J', 'K', 'L', 'M', 'N',
- 'O', 'P', 'Q', 'R', 'S', 'T',
- 'U', 'V', 'W', 'X', 'Y', 'Z'
- ];
static randomIntRange(min, max) {
return parseInt(Math.random() * (max - min) + min, 10);
@@ -101,7 +102,7 @@ class RandomUtil {
static randomSeq(count) {
let str = '';
for (let i = 0; i < count; ++i) {
- str += this.seq[this.randomInt(62)];
+ str += seq[this.randomInt(62)];
}
return str;
}
@@ -109,7 +110,7 @@ class RandomUtil {
static randomLowerAndNum(count) {
let str = '';
for (let i = 0; i < count; ++i) {
- str += this.seq[this.randomInt(36)];
+ str += seq[this.randomInt(36)];
}
return str;
}
@@ -121,7 +122,7 @@ class RandomUtil {
if (index <= 9) {
str += index;
} else {
- str += this.seq[index - 10];
+ str += seq[index - 10];
}
}
return str;
diff --git a/web/controller/inbound.go b/web/controller/inbound.go
index 07dacfe..3cb3b6b 100644
--- a/web/controller/inbound.go
+++ b/web/controller/inbound.go
@@ -37,7 +37,7 @@ func (a *InboundController) startTask() {
c := webServer.GetCron()
c.AddFunc("@every 10s", func() {
if a.xrayService.IsNeedRestartAndSetFalse() {
- err := a.xrayService.RestartXray()
+ err := a.xrayService.RestartXray(false)
if err != nil {
logger.Error("restart xray failed:", err)
}
diff --git a/web/html/xui/form/inbound.html b/web/html/xui/form/inbound.html
index 64da61e..30872e4 100644
--- a/web/html/xui/form/inbound.html
+++ b/web/html/xui/form/inbound.html
@@ -39,6 +39,19 @@