Compare commits
2 Commits
fac2c33e05
...
096a8275be
| Author | SHA1 | Date | |
|---|---|---|---|
| 096a8275be | |||
| 6f7fdef746 |
2
go.mod
2
go.mod
@@ -1,3 +1,3 @@
|
|||||||
module dragoncore-bridge
|
module dragoncore-bridge
|
||||||
|
|
||||||
go 1.21
|
go 1.13
|
||||||
|
|||||||
@@ -28,17 +28,75 @@ fi
|
|||||||
need_cmd() { command -v "$1" >/dev/null 2>&1; }
|
need_cmd() { command -v "$1" >/dev/null 2>&1; }
|
||||||
rand_hex() { openssl rand -hex "$1"; }
|
rand_hex() { openssl rand -hex "$1"; }
|
||||||
|
|
||||||
|
# The bridge source is intentionally Go 1.13-compatible so old VPS images
|
||||||
|
# such as Ubuntu 20.04 can compile it with their distro package.
|
||||||
|
# If the distro Go is older than 1.13, install a known-good official Go.
|
||||||
|
GO_MIN_MAJOR=1
|
||||||
|
GO_MIN_MINOR=13
|
||||||
|
GO_VERSION="${GO_VERSION:-1.21.13}"
|
||||||
|
GO_BIN=""
|
||||||
|
|
||||||
|
go_version_ok() {
|
||||||
|
if ! need_cmd go; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
ver="$(go version 2>/dev/null | awk '{print $3}' | sed 's/^go//; s/[^0-9.].*$//')"
|
||||||
|
major="$(printf '%s' "$ver" | cut -d. -f1)"
|
||||||
|
minor="$(printf '%s' "$ver" | cut -d. -f2)"
|
||||||
|
case "$major:$minor" in
|
||||||
|
*[!0-9:]*|:*) return 1 ;;
|
||||||
|
esac
|
||||||
|
if [ "$major" -gt "$GO_MIN_MAJOR" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [ "$major" -eq "$GO_MIN_MAJOR" ] && [ "$minor" -ge "$GO_MIN_MINOR" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
install_official_go() {
|
||||||
|
arch="$(uname -m)"
|
||||||
|
case "$arch" in
|
||||||
|
x86_64|amd64) goarch="amd64" ;;
|
||||||
|
aarch64|arm64) goarch="arm64" ;;
|
||||||
|
armv6l|armv7l) goarch="armv6l" ;;
|
||||||
|
i386|i686) goarch="386" ;;
|
||||||
|
*) echo "Unsupported CPU architecture for automatic Go install: $arch"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
url="https://go.dev/dl/go${GO_VERSION}.linux-${goarch}.tar.gz"
|
||||||
|
tmp="/tmp/go${GO_VERSION}.linux-${goarch}.tar.gz"
|
||||||
|
echo "Installing Go ${GO_VERSION} from ${url} ..."
|
||||||
|
curl -fsSL "$url" -o "$tmp"
|
||||||
|
rm -rf /usr/local/go
|
||||||
|
tar -C /usr/local -xzf "$tmp"
|
||||||
|
ln -sf /usr/local/go/bin/go /usr/local/bin/go
|
||||||
|
ln -sf /usr/local/go/bin/gofmt /usr/local/bin/gofmt
|
||||||
|
GO_BIN="/usr/local/go/bin/go"
|
||||||
|
}
|
||||||
|
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
if need_cmd apt-get; then
|
if need_cmd apt-get; then
|
||||||
apt-get update -y
|
apt-get update -y
|
||||||
apt-get install -y ca-certificates curl wget git openssl build-essential
|
apt-get install -y ca-certificates curl wget git openssl build-essential
|
||||||
if ! need_cmd go; then
|
if ! need_cmd go; then
|
||||||
apt-get install -y golang-go
|
apt-get install -y golang-go || true
|
||||||
fi
|
fi
|
||||||
elif need_cmd yum; then
|
elif need_cmd yum; then
|
||||||
yum install -y ca-certificates curl wget git openssl gcc make golang
|
yum install -y ca-certificates curl wget git openssl gcc make golang || yum install -y ca-certificates curl wget git openssl gcc make
|
||||||
elif need_cmd dnf; then
|
elif need_cmd dnf; then
|
||||||
dnf install -y ca-certificates curl wget git openssl gcc make golang
|
dnf install -y ca-certificates curl wget git openssl gcc make golang || dnf install -y ca-certificates curl wget git openssl gcc make
|
||||||
|
fi
|
||||||
|
|
||||||
|
if go_version_ok; then
|
||||||
|
GO_BIN="$(command -v go)"
|
||||||
|
else
|
||||||
|
install_official_go
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! "$GO_BIN" version >/dev/null 2>&1; then
|
||||||
|
echo "Go installation failed. Cannot build dragoncore-bridge."
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$INSTALL_DIR" "$CONFIG_DIR"
|
mkdir -p "$INSTALL_DIR" "$CONFIG_DIR"
|
||||||
@@ -56,7 +114,7 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
cd "$INSTALL_DIR/src"
|
cd "$INSTALL_DIR/src"
|
||||||
go build -trimpath -ldflags "-s -w" -o "$BIN" .
|
"$GO_BIN" build -trimpath -ldflags "-s -w" -o "$BIN" .
|
||||||
chmod 755 "$BIN"
|
chmod 755 "$BIN"
|
||||||
|
|
||||||
USER_NAME="admin"
|
USER_NAME="admin"
|
||||||
|
|||||||
109
main.go
109
main.go
@@ -8,6 +8,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -121,7 +122,7 @@ func getenv(k, def string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func loadConfig(path string) (Config, error) {
|
func loadConfig(path string) (Config, error) {
|
||||||
b, err := os.ReadFile(path)
|
b, err := ioutil.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Config{}, err
|
return Config{}, err
|
||||||
}
|
}
|
||||||
@@ -134,7 +135,7 @@ func loadConfig(path string) (Config, error) {
|
|||||||
|
|
||||||
func loadStore(path string) (*Store, error) {
|
func loadStore(path string) (*Store, error) {
|
||||||
st := &Store{path: path, Accounts: map[string]Account{}}
|
st := &Store{path: path, Accounts: map[string]Account{}}
|
||||||
b, err := os.ReadFile(path)
|
b, err := ioutil.ReadFile(path)
|
||||||
if errors.Is(err, os.ErrNotExist) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
return st, nil
|
return st, nil
|
||||||
}
|
}
|
||||||
@@ -157,7 +158,7 @@ func loadStore(path string) (*Store, error) {
|
|||||||
func (s *Store) saveLocked() error {
|
func (s *Store) saveLocked() error {
|
||||||
tmp := s.path + ".tmp"
|
tmp := s.path + ".tmp"
|
||||||
b, _ := json.MarshalIndent(s, "", " ")
|
b, _ := json.MarshalIndent(s, "", " ")
|
||||||
if err := os.WriteFile(tmp, b, 0600); err != nil {
|
if err := ioutil.WriteFile(tmp, b, 0600); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return os.Rename(tmp, s.path)
|
return os.Rename(tmp, s.path)
|
||||||
@@ -165,7 +166,7 @@ func (s *Store) saveLocked() error {
|
|||||||
|
|
||||||
func randToken(n int) string { b := make([]byte, n); _, _ = rand.Read(b); return hex.EncodeToString(b) }
|
func randToken(n int) string { b := make([]byte, n); _, _ = rand.Read(b); return hex.EncodeToString(b) }
|
||||||
|
|
||||||
func writeJSON(w http.ResponseWriter, v any) {
|
func writeJSON(w http.ResponseWriter, v interface{}) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
_ = json.NewEncoder(w).Encode(v)
|
_ = json.NewEncoder(w).Encode(v)
|
||||||
}
|
}
|
||||||
@@ -189,7 +190,7 @@ func (a *App) handleLogin(w http.ResponseWriter, r *http.Request) {
|
|||||||
a.sessMu.Lock()
|
a.sessMu.Lock()
|
||||||
a.sessions[tok] = time.Now().Add(12 * time.Hour)
|
a.sessions[tok] = time.Now().Add(12 * time.Hour)
|
||||||
a.sessMu.Unlock()
|
a.sessMu.Unlock()
|
||||||
writeJSON(w, map[string]any{"token": tok, "username": a.cfg.Username, "role": "admin"})
|
writeJSON(w, map[string]interface{}{"token": tok, "username": a.cfg.Username, "role": "admin"})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) auth(next http.Handler) http.Handler {
|
func (a *App) auth(next http.Handler) http.Handler {
|
||||||
@@ -215,7 +216,7 @@ func (a *App) auth(next http.Handler) http.Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) handleMe(w http.ResponseWriter, r *http.Request) {
|
func (a *App) handleMe(w http.ResponseWriter, r *http.Request) {
|
||||||
writeJSON(w, map[string]any{"username": a.cfg.Username, "role": "admin"})
|
writeJSON(w, map[string]interface{}{"username": a.cfg.Username, "role": "admin"})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) handleUsers(w http.ResponseWriter, r *http.Request) {
|
func (a *App) handleUsers(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -303,7 +304,7 @@ func (a *App) handleDragonCreate(w http.ResponseWriter, r *http.Request) {
|
|||||||
errText(w, 400, err.Error())
|
errText(w, 400, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
writeJSON(w, map[string]any{"ok": true})
|
writeJSON(w, map[string]interface{}{"ok": true})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) handleDragonDelete(w http.ResponseWriter, r *http.Request) {
|
func (a *App) handleDragonDelete(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -322,7 +323,7 @@ func (a *App) handleDragonDelete(w http.ResponseWriter, r *http.Request) {
|
|||||||
errText(w, 400, err.Error())
|
errText(w, 400, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
writeJSON(w, map[string]any{"ok": true})
|
writeJSON(w, map[string]interface{}{"ok": true})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) handleDragonSync(w http.ResponseWriter, r *http.Request) {
|
func (a *App) handleDragonSync(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -352,7 +353,7 @@ func (a *App) handleDragonSync(w http.ResponseWriter, r *http.Request) {
|
|||||||
ok++
|
ok++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeJSON(w, map[string]any{"ok": ok, "fail": fail})
|
writeJSON(w, map[string]interface{}{"ok": ok, "fail": fail})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) createSSH(username, password string, limit int, expiresAt *time.Time, uuid string, withXray bool) error {
|
func (a *App) createSSH(username, password string, limit int, expiresAt *time.Time, uuid string, withXray bool) error {
|
||||||
@@ -437,7 +438,7 @@ func passwordHash(password string) (string, error) {
|
|||||||
|
|
||||||
func writeCompatUserFiles(username, password string, limit int) error {
|
func writeCompatUserFiles(username, password string, limit int) error {
|
||||||
_ = os.MkdirAll("/etc/SSHPlus/senha", 0755)
|
_ = os.MkdirAll("/etc/SSHPlus/senha", 0755)
|
||||||
_ = os.WriteFile("/etc/SSHPlus/senha/"+username, []byte(password+"\n"), 0600)
|
_ = ioutil.WriteFile("/etc/SSHPlus/senha/"+username, []byte(password+"\n"), 0600)
|
||||||
upsertLine("/root/usuarios.db", username, fmt.Sprintf("%s %d", username, limit))
|
upsertLine("/root/usuarios.db", username, fmt.Sprintf("%s %d", username, limit))
|
||||||
if _, err := os.Stat("/opt/DragonCore/menu.php"); err == nil {
|
if _, err := os.Stat("/opt/DragonCore/menu.php"); err == nil {
|
||||||
_ = exec.Command("php", "/opt/DragonCore/menu.php", "deleteData", username).Run()
|
_ = exec.Command("php", "/opt/DragonCore/menu.php", "deleteData", username).Run()
|
||||||
@@ -464,7 +465,7 @@ func upsertLine(path, prefix, line string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
func removeLinePrefix(path, prefix string) {
|
func removeLinePrefix(path, prefix string) {
|
||||||
b, err := os.ReadFile(path)
|
b, err := ioutil.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -478,7 +479,7 @@ func removeLinePrefix(path, prefix string) {
|
|||||||
}
|
}
|
||||||
out = append(out, l)
|
out = append(out, l)
|
||||||
}
|
}
|
||||||
_ = os.WriteFile(path, []byte(strings.Join(out, "\n")+"\n"), 0644)
|
_ = ioutil.WriteFile(path, []byte(strings.Join(out, "\n")+"\n"), 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) expiryLoop() {
|
func (a *App) expiryLoop() {
|
||||||
@@ -500,12 +501,12 @@ func (a *App) expiryLoop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func listSystemUsers(st *Store) []map[string]any {
|
func listSystemUsers(st *Store) []map[string]interface{} {
|
||||||
st.mu.Lock()
|
st.mu.Lock()
|
||||||
defer st.mu.Unlock()
|
defer st.mu.Unlock()
|
||||||
out := make([]map[string]any, 0, len(st.Accounts))
|
out := make([]map[string]interface{}, 0, len(st.Accounts))
|
||||||
for _, ac := range st.Accounts {
|
for _, ac := range st.Accounts {
|
||||||
out = append(out, map[string]any{"username": ac.Username, "active_conns": activeProcCount(ac.Username), "max_connections": ac.MaxConnections, "expires_at": ac.ExpiresAt, "uuid": ac.UUID})
|
out = append(out, map[string]interface{}{"username": ac.Username, "active_conns": activeProcCount(ac.Username), "max_connections": ac.MaxConnections, "expires_at": ac.ExpiresAt, "uuid": ac.UUID})
|
||||||
}
|
}
|
||||||
sort.Slice(out, func(i, j int) bool { return fmt.Sprint(out[i]["username"]) < fmt.Sprint(out[j]["username"]) })
|
sort.Slice(out, func(i, j int) bool { return fmt.Sprint(out[i]["username"]) < fmt.Sprint(out[j]["username"]) })
|
||||||
return out
|
return out
|
||||||
@@ -541,22 +542,22 @@ func parseTimeMaybe(s string) (*time.Time, error) {
|
|||||||
func xrayConfigPaths() []string {
|
func xrayConfigPaths() []string {
|
||||||
return []string{"/usr/local/etc/xray/config.json", "/etc/xray/config.json", "/etc/v2ray/config.json"}
|
return []string{"/usr/local/etc/xray/config.json", "/etc/xray/config.json", "/etc/v2ray/config.json"}
|
||||||
}
|
}
|
||||||
func readJSONFile(path string) (map[string]any, error) {
|
func readJSONFile(path string) (map[string]interface{}, error) {
|
||||||
b, err := os.ReadFile(path)
|
b, err := ioutil.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var m map[string]any
|
var m map[string]interface{}
|
||||||
err = json.Unmarshal(b, &m)
|
err = json.Unmarshal(b, &m)
|
||||||
return m, err
|
return m, err
|
||||||
}
|
}
|
||||||
func writeJSONFile(path string, m map[string]any) error {
|
func writeJSONFile(path string, m map[string]interface{}) error {
|
||||||
b, err := json.MarshalIndent(m, "", " ")
|
b, err := json.MarshalIndent(m, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tmp := path + ".tmp"
|
tmp := path + ".tmp"
|
||||||
if err := os.WriteFile(tmp, b, 0644); err != nil {
|
if err := ioutil.WriteFile(tmp, b, 0644); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return os.Rename(tmp, path)
|
return os.Rename(tmp, path)
|
||||||
@@ -572,28 +573,28 @@ func addXrayClientAll(uuid, email string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
inb, _ := cfg["inbounds"].([]any)
|
inb, _ := cfg["inbounds"].([]interface{})
|
||||||
fileChanged := false
|
fileChanged := false
|
||||||
for _, it := range inb {
|
for _, it := range inb {
|
||||||
im, ok := it.(map[string]any)
|
im, ok := it.(map[string]interface{})
|
||||||
if !ok || fmt.Sprint(im["protocol"]) != "vless" {
|
if !ok || fmt.Sprint(im["protocol"]) != "vless" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
settings, _ := im["settings"].(map[string]any)
|
settings, _ := im["settings"].(map[string]interface{})
|
||||||
if settings == nil {
|
if settings == nil {
|
||||||
settings = map[string]any{}
|
settings = map[string]interface{}{}
|
||||||
im["settings"] = settings
|
im["settings"] = settings
|
||||||
}
|
}
|
||||||
clients, _ := settings["clients"].([]any)
|
clients, _ := settings["clients"].([]interface{})
|
||||||
exists := false
|
exists := false
|
||||||
for _, c := range clients {
|
for _, c := range clients {
|
||||||
cm, _ := c.(map[string]any)
|
cm, _ := c.(map[string]interface{})
|
||||||
if fmt.Sprint(cm["id"]) == uuid || fmt.Sprint(cm["email"]) == email {
|
if fmt.Sprint(cm["id"]) == uuid || fmt.Sprint(cm["email"]) == email {
|
||||||
exists = true
|
exists = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !exists {
|
if !exists {
|
||||||
settings["clients"] = append(clients, map[string]any{"id": uuid, "alterId": 0, "email": email})
|
settings["clients"] = append(clients, map[string]interface{}{"id": uuid, "alterId": 0, "email": email})
|
||||||
fileChanged = true
|
fileChanged = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -620,21 +621,21 @@ func removeXrayClientAll(uuid string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
inb, _ := cfg["inbounds"].([]any)
|
inb, _ := cfg["inbounds"].([]interface{})
|
||||||
fileChanged := false
|
fileChanged := false
|
||||||
for _, it := range inb {
|
for _, it := range inb {
|
||||||
im, ok := it.(map[string]any)
|
im, ok := it.(map[string]interface{})
|
||||||
if !ok || fmt.Sprint(im["protocol"]) != "vless" {
|
if !ok || fmt.Sprint(im["protocol"]) != "vless" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
settings, _ := im["settings"].(map[string]any)
|
settings, _ := im["settings"].(map[string]interface{})
|
||||||
if settings == nil {
|
if settings == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
clients, _ := settings["clients"].([]any)
|
clients, _ := settings["clients"].([]interface{})
|
||||||
out := make([]any, 0, len(clients))
|
out := make([]interface{}, 0, len(clients))
|
||||||
for _, c := range clients {
|
for _, c := range clients {
|
||||||
cm, _ := c.(map[string]any)
|
cm, _ := c.(map[string]interface{})
|
||||||
if fmt.Sprint(cm["id"]) == uuid {
|
if fmt.Sprint(cm["id"]) == uuid {
|
||||||
fileChanged = true
|
fileChanged = true
|
||||||
continue
|
continue
|
||||||
@@ -665,7 +666,7 @@ func (a *App) handleXrayInbounds(w http.ResponseWriter, r *http.Request) {
|
|||||||
type Inb struct {
|
type Inb struct {
|
||||||
Tag string `json:"tag"`
|
Tag string `json:"tag"`
|
||||||
Protocol string `json:"protocol"`
|
Protocol string `json:"protocol"`
|
||||||
Clients []map[string]any `json:"clients"`
|
Clients []map[string]interface{} `json:"clients"`
|
||||||
}
|
}
|
||||||
var out []Inb
|
var out []Inb
|
||||||
for _, path := range xrayConfigPaths() {
|
for _, path := range xrayConfigPaths() {
|
||||||
@@ -673,19 +674,19 @@ func (a *App) handleXrayInbounds(w http.ResponseWriter, r *http.Request) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
inb, _ := cfg["inbounds"].([]any)
|
inb, _ := cfg["inbounds"].([]interface{})
|
||||||
for i, it := range inb {
|
for i, it := range inb {
|
||||||
im, _ := it.(map[string]any)
|
im, _ := it.(map[string]interface{})
|
||||||
proto := fmt.Sprint(im["protocol"])
|
proto := fmt.Sprint(im["protocol"])
|
||||||
tag := fmt.Sprint(im["tag"])
|
tag := fmt.Sprint(im["tag"])
|
||||||
if tag == "<nil>" || tag == "" {
|
if tag == "<nil>" || tag == "" {
|
||||||
tag = fmt.Sprintf("%s-%d", proto, i)
|
tag = fmt.Sprintf("%s-%d", proto, i)
|
||||||
}
|
}
|
||||||
settings, _ := im["settings"].(map[string]any)
|
settings, _ := im["settings"].(map[string]interface{})
|
||||||
clientsAny, _ := settings["clients"].([]any)
|
clientsAny, _ := settings["clients"].([]interface{})
|
||||||
clients := []map[string]any{}
|
clients := []map[string]interface{}{}
|
||||||
for _, c := range clientsAny {
|
for _, c := range clientsAny {
|
||||||
if cm, ok := c.(map[string]any); ok {
|
if cm, ok := c.(map[string]interface{}); ok {
|
||||||
clients = append(clients, cm)
|
clients = append(clients, cm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -736,7 +737,7 @@ func (a *App) handleStats(w http.ResponseWriter, r *http.Request) { writeJSON(w,
|
|||||||
type cpuSample struct{ idle, total uint64 }
|
type cpuSample struct{ idle, total uint64 }
|
||||||
|
|
||||||
func readCPU() cpuSample {
|
func readCPU() cpuSample {
|
||||||
b, _ := os.ReadFile("/proc/stat")
|
b, _ := ioutil.ReadFile("/proc/stat")
|
||||||
fields := strings.Fields(strings.SplitN(string(b), "\n", 2)[0])
|
fields := strings.Fields(strings.SplitN(string(b), "\n", 2)[0])
|
||||||
var vals []uint64
|
var vals []uint64
|
||||||
for _, f := range fields[1:] {
|
for _, f := range fields[1:] {
|
||||||
@@ -753,7 +754,7 @@ func readCPU() cpuSample {
|
|||||||
}
|
}
|
||||||
return cpuSample{idle, total}
|
return cpuSample{idle, total}
|
||||||
}
|
}
|
||||||
func collectStats() map[string]any {
|
func collectStats() map[string]interface{} {
|
||||||
c1 := readCPU()
|
c1 := readCPU()
|
||||||
time.Sleep(150 * time.Millisecond)
|
time.Sleep(150 * time.Millisecond)
|
||||||
c2 := readCPU()
|
c2 := readCPU()
|
||||||
@@ -762,10 +763,10 @@ func collectStats() map[string]any {
|
|||||||
cpu = 100 * (1 - float64(c2.idle-c1.idle)/float64(c2.total-c1.total))
|
cpu = 100 * (1 - float64(c2.idle-c1.idle)/float64(c2.total-c1.total))
|
||||||
}
|
}
|
||||||
mem := readMem()
|
mem := readMem()
|
||||||
return map[string]any{"cpu_percent": cpu, "mem_total_bytes": mem["total"], "mem_used_bytes": mem["used"], "mem_avail_bytes": mem["avail"], "mem_percent": mem["percent"], "interfaces": readNet()}
|
return map[string]interface{}{"cpu_percent": cpu, "mem_total_bytes": mem["total"], "mem_used_bytes": mem["used"], "mem_avail_bytes": mem["avail"], "mem_percent": mem["percent"], "interfaces": readNet()}
|
||||||
}
|
}
|
||||||
func readMem() map[string]any {
|
func readMem() map[string]interface{} {
|
||||||
b, _ := os.ReadFile("/proc/meminfo")
|
b, _ := ioutil.ReadFile("/proc/meminfo")
|
||||||
vals := map[string]uint64{}
|
vals := map[string]uint64{}
|
||||||
for _, l := range strings.Split(string(b), "\n") {
|
for _, l := range strings.Split(string(b), "\n") {
|
||||||
f := strings.Fields(l)
|
f := strings.Fields(l)
|
||||||
@@ -782,11 +783,11 @@ func readMem() map[string]any {
|
|||||||
used = total - avail
|
used = total - avail
|
||||||
pct = 100 * float64(used) / float64(total)
|
pct = 100 * float64(used) / float64(total)
|
||||||
}
|
}
|
||||||
return map[string]any{"total": total, "used": used, "avail": avail, "percent": pct}
|
return map[string]interface{}{"total": total, "used": used, "avail": avail, "percent": pct}
|
||||||
}
|
}
|
||||||
func readNet() []map[string]any {
|
func readNet() []map[string]interface{} {
|
||||||
b, _ := os.ReadFile("/proc/net/dev")
|
b, _ := ioutil.ReadFile("/proc/net/dev")
|
||||||
var out []map[string]any
|
var out []map[string]interface{}
|
||||||
for _, l := range strings.Split(string(b), "\n") {
|
for _, l := range strings.Split(string(b), "\n") {
|
||||||
if !strings.Contains(l, ":") {
|
if !strings.Contains(l, ":") {
|
||||||
continue
|
continue
|
||||||
@@ -800,7 +801,7 @@ func readNet() []map[string]any {
|
|||||||
if len(f) >= 16 {
|
if len(f) >= 16 {
|
||||||
rx, _ := strconv.ParseUint(f[0], 10, 64)
|
rx, _ := strconv.ParseUint(f[0], 10, 64)
|
||||||
tx, _ := strconv.ParseUint(f[8], 10, 64)
|
tx, _ := strconv.ParseUint(f[8], 10, 64)
|
||||||
out = append(out, map[string]any{"name": name, "rx_bytes": rx, "tx_bytes": tx})
|
out = append(out, map[string]interface{}{"name": name, "rx_bytes": rx, "tx_bytes": tx})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
@@ -808,20 +809,20 @@ func readNet() []map[string]any {
|
|||||||
|
|
||||||
func (a *App) handleReboot(w http.ResponseWriter, r *http.Request) {
|
func (a *App) handleReboot(w http.ResponseWriter, r *http.Request) {
|
||||||
go exec.Command("shutdown", "-r", "+1", "DragonCore bridge reboot requested").Run()
|
go exec.Command("shutdown", "-r", "+1", "DragonCore bridge reboot requested").Run()
|
||||||
writeJSON(w, map[string]any{"ok": true})
|
writeJSON(w, map[string]interface{}{"ok": true})
|
||||||
}
|
}
|
||||||
func (a *App) handleRestartSSH(w http.ResponseWriter, r *http.Request) {
|
func (a *App) handleRestartSSH(w http.ResponseWriter, r *http.Request) {
|
||||||
_ = exec.Command("systemctl", "restart", "ssh").Run()
|
_ = exec.Command("systemctl", "restart", "ssh").Run()
|
||||||
_ = exec.Command("systemctl", "restart", "sshd").Run()
|
_ = exec.Command("systemctl", "restart", "sshd").Run()
|
||||||
writeJSON(w, map[string]any{"ok": true})
|
writeJSON(w, map[string]interface{}{"ok": true})
|
||||||
}
|
}
|
||||||
func (a *App) handleCleanup(w http.ResponseWriter, r *http.Request) {
|
func (a *App) handleCleanup(w http.ResponseWriter, r *http.Request) {
|
||||||
_ = exec.Command("sh", "-c", "apt-get clean 2>/dev/null; journalctl --vacuum-time=3d 2>/dev/null; rm -rf /tmp/* 2>/dev/null").Run()
|
_ = exec.Command("sh", "-c", "apt-get clean 2>/dev/null; journalctl --vacuum-time=3d 2>/dev/null; rm -rf /tmp/* 2>/dev/null").Run()
|
||||||
writeJSON(w, map[string]any{"ok": true})
|
writeJSON(w, map[string]interface{}{"ok": true})
|
||||||
}
|
}
|
||||||
func (a *App) handleXrayFix(w http.ResponseWriter, r *http.Request) {
|
func (a *App) handleXrayFix(w http.ResponseWriter, r *http.Request) {
|
||||||
restartXray()
|
restartXray()
|
||||||
writeJSON(w, map[string]any{"ok": true})
|
writeJSON(w, map[string]interface{}{"ok": true})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) handleLegacyCommand(w http.ResponseWriter, r *http.Request) {
|
func (a *App) handleLegacyCommand(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
Reference in New Issue
Block a user