reorganize lib, nodep can be used by other project

This commit is contained in:
yiguo
2023-06-27 18:02:21 +08:00
parent 386e410e31
commit 78c813fbe2
13 changed files with 175 additions and 177 deletions

View File

@@ -12,10 +12,6 @@ This is an Xray wrapper focusing on improving the experience of [Xray-core](http
转换 Clash yamlClash.Meta yaml 为 Xray Json。
### controller.go
试验性的 Android Protect(fd)。
### file.go
文件写入。

View File

@@ -1,18 +0,0 @@
package libXray
import (
"syscall"
xinternet "github.com/xtls/xray-core/transport/internet"
)
type DialerController interface {
FdCallback(int) bool
}
func RegisterDialerController(controller DialerController) {
xinternet.RegisterDialerController(func(network, address string, conn syscall.RawConn) error {
//controller.FdCallback(int(fd))
return nil
})
}

9
geo.go
View File

@@ -7,11 +7,14 @@ import (
"strings"
"time"
"github.com/xtls/libxray/nodep"
"github.com/xtls/xray-core/app/router"
"github.com/xtls/xray-core/common/platform/filesystem"
"google.golang.org/protobuf/proto"
)
// Read geo data and write all codes to text file.
// dir means the dir which geosite.dat and geoip.dat are in.
func LoadGeoData(dir string) string {
if err := loadGeoSite(dir); err != nil {
return err.Error()
@@ -22,7 +25,7 @@ func LoadGeoData(dir string) string {
ts := time.Now().Unix()
tsText := strconv.FormatInt(ts, 10)
tsPath := path.Join(dir, "timestamp.txt")
if err := writeText(tsText, tsPath); err != nil {
if err := nodep.WriteText(tsText, tsPath); err != nil {
return err.Error()
}
return ""
@@ -53,7 +56,7 @@ func loadGeoSite(dir string) error {
}
}
text := strings.Join(countries, "\n")
if err := writeText(text, txtPath); err != nil {
if err := nodep.WriteText(text, txtPath); err != nil {
return err
}
@@ -78,7 +81,7 @@ func loadGeoIP(dir string) error {
}
text := strings.Join(countries, "\n")
if err := writeText(text, txtPath); err != nil {
if err := nodep.WriteText(text, txtPath); err != nil {
return err
}

View File

@@ -1,37 +0,0 @@
package libXray
import (
"runtime/debug"
"time"
"github.com/xtls/xray-core/common/platform"
)
func forceFree(interval time.Duration) {
go func() {
for {
time.Sleep(interval)
debug.FreeOSMemory()
}
}()
}
func readForceFreeInterval() int {
const key = "XRAY_MEMORY_FORCEFREE"
const defaultValue = 0
interval := platform.EnvFlag{
Name: key,
AltName: platform.NormalizeEnvName(key),
}.GetValueAsInt(defaultValue)
return interval
}
func initForceFree(maxMemory int64) {
debug.SetGCPercent(10)
debug.SetMemoryLimit(maxMemory)
interval := readForceFreeInterval()
if interval > 0 {
duration := time.Duration(interval) * time.Second
forceFree(duration)
}
}

View File

@@ -1,10 +1,10 @@
package libXray
package nodep
import (
"os"
)
func writeBytes(bytes []byte, path string) error {
func WriteBytes(bytes []byte, path string) error {
fi, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0664)
if err != nil {
return err
@@ -18,7 +18,7 @@ func writeBytes(bytes []byte, path string) error {
return nil
}
func writeText(text string, path string) error {
func WriteText(text string, path string) error {
fi, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0664)
if err != nil {
return err

101
nodep/measure.go Normal file
View File

@@ -0,0 +1,101 @@
package nodep
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"time"
)
const (
PingDelayTimeout int64 = 11000
PingDelayError int64 = 10000
)
type geoLocation struct {
Ip string `json:"ip,omitempty"`
Cc string `json:"cc,omitempty"`
}
// Find the delay and country code of some outbound.
// timeout means how long the http request will be cancelled if no response, in units of seconds.
// url means the website we use to test speed. "https://www.google.com/gen_204" is a good choice for most cases.
// times means how many times we should test the url.
// proxy means the local http/socks5 proxy, like "http://127.0.0.1:1080".
func MeasureDelay(timeout int, url string, times int, proxy string) string {
httpTimeout := time.Second * time.Duration(timeout)
c, err := coreHTTPClient(httpTimeout, proxy)
if err != nil {
return fmt.Sprintf("%d::%s", PingDelayError, err)
}
delaySum := int64(0)
count := int64(0)
isValid := false
lastErr := ""
for i := 0; i < times; i++ {
delay, err := pingHTTPRequest(c, url)
if delay != PingDelayTimeout {
delaySum += delay
count += 1
isValid = true
} else {
lastErr = err.Error()
}
}
if !isValid {
return fmt.Sprintf("%d::%s", PingDelayTimeout, lastErr)
}
country, err := geolocationHTTPRequest(c)
if err != nil {
fmt.Println("geolocation error: ", err)
}
return fmt.Sprintf("%d:%s:%s", delaySum/count, country, lastErr)
}
func coreHTTPClient(timeout time.Duration, proxy string) (*http.Client, error) {
tr := &http.Transport{
DisableKeepAlives: true,
Proxy: func(r *http.Request) (*url.URL, error) {
return url.Parse(proxy)
},
}
c := &http.Client{
Transport: tr,
Timeout: timeout,
}
return c, nil
}
func pingHTTPRequest(c *http.Client, url string) (int64, error) {
start := time.Now()
req, _ := http.NewRequest("GET", url, nil)
_, err := c.Do(req)
if err != nil {
return PingDelayTimeout, err
}
return time.Since(start).Milliseconds(), nil
}
func geolocationHTTPRequest(c *http.Client) (string, error) {
req, _ := http.NewRequest("GET", "https://ident.me/json", nil)
resp, err := c.Do(req)
if err != nil {
return "", err
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
var location geoLocation
if err = json.Unmarshal(body, &location); err != nil {
return "", err
}
return location.Cc, nil
}

24
nodep/memory.go Normal file
View File

@@ -0,0 +1,24 @@
package nodep
import (
"runtime/debug"
"time"
)
func forceFree(interval time.Duration) {
go func() {
for {
time.Sleep(interval)
debug.FreeOSMemory()
}
}()
}
func InitForceFree(maxMemory int64, interval int) {
debug.SetGCPercent(10)
debug.SetMemoryLimit(maxMemory)
if interval > 0 {
duration := time.Duration(interval) * time.Second
forceFree(duration)
}
}

View File

@@ -1,4 +1,4 @@
package libXray
package nodep
import (
"fmt"

122
ping.go
View File

@@ -1,123 +1,31 @@
package libXray
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net"
"net/http"
"time"
xnet "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/core"
"github.com/xtls/libxray/nodep"
)
const (
pingDelayTimeout int64 = 11000
pingDelayError int64 = 10000
)
type geoLocation struct {
Ip string `json:"ip,omitempty"`
Cc string `json:"cc,omitempty"`
}
func Ping(datDir string, config string, timeout int, url string, times int) string {
// Ping Xray config and find the delay and country code of its outbound.
// datDir means the dir which geosite.dat and geoip.dat are in.
// configPath means the config.json file path.
// timeout means how long the http request will be cancelled if no response, in units of seconds.
// url means the website we use to test speed. "https://www.google.com/gen_204" is a good choice for most cases.
// times means how many times we should test the url.
// proxy means the local http/socks5 proxy, like "http://127.0.0.1:1080".
//
// note: you must use http protocol as inbound.
func Ping(datDir string, configPath string, timeout int, url string, times int, proxy string) string {
initEnv(datDir)
server, err := startXray(config)
server, err := startXray(configPath)
if err != nil {
return fmt.Sprintf("%d::%s", pingDelayError, err)
return fmt.Sprintf("%d::%s", nodep.PingDelayError, err)
}
if err := server.Start(); err != nil {
return fmt.Sprintf("%d::%s", pingDelayError, err)
return fmt.Sprintf("%d::%s", nodep.PingDelayError, err)
}
defer server.Close()
return measureDelay(server, timeout, url, times)
}
func measureDelay(inst *core.Instance, timeout int, url string, times int) string {
httpTimeout := time.Second * time.Duration(timeout)
c, err := coreHTTPClient(inst, httpTimeout)
if err != nil {
return fmt.Sprintf("%d::%s", pingDelayError, err)
}
delaySum := int64(0)
count := int64(0)
isValid := false
lastErr := ""
for i := 0; i < times; i++ {
delay, err := pingHTTPRequest(c, url)
if delay != pingDelayTimeout {
delaySum += delay
count += 1
isValid = true
} else {
lastErr = err.Error()
}
}
if !isValid {
return fmt.Sprintf("%d::%s", pingDelayTimeout, lastErr)
}
country, err := geolocationHTTPRequest(c)
if err != nil {
fmt.Println("geolocation error: ", err)
}
return fmt.Sprintf("%d:%s:%s", delaySum/count, country, lastErr)
}
func coreHTTPClient(inst *core.Instance, timeout time.Duration) (*http.Client, error) {
if inst == nil {
return nil, errors.New("core instance nil")
}
tr := &http.Transport{
DisableKeepAlives: true,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dest, err := xnet.ParseDestination(fmt.Sprintf("%s:%s", network, addr))
if err != nil {
return nil, err
}
return core.Dial(ctx, inst, dest)
},
}
c := &http.Client{
Transport: tr,
Timeout: timeout,
}
return c, nil
}
func pingHTTPRequest(c *http.Client, url string) (int64, error) {
start := time.Now()
req, _ := http.NewRequest("GET", url, nil)
_, err := c.Do(req)
if err != nil {
return pingDelayTimeout, err
}
return time.Since(start).Milliseconds(), nil
}
func geolocationHTTPRequest(c *http.Client) (string, error) {
req, _ := http.NewRequest("GET", "https://ident.me/json", nil)
resp, err := c.Do(req)
if err != nil {
return "", err
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
var location geoLocation
if err = json.Unmarshal(body, &location); err != nil {
return "", err
}
return location.Cc, nil
return nodep.MeasureDelay(timeout, url, times, proxy)
}

View File

@@ -9,9 +9,12 @@ import (
"net/url"
"strconv"
"github.com/xtls/libxray/nodep"
"github.com/xtls/xray-core/common/platform/filesystem"
)
// Convert share text to xrayJson
// support xrayJson, v2rayN plain text, v2rayN base64 text, clash yaml, Clash.Meta yaml
func ParseShareText(textPath string, xrayPath string) string {
textBytes, err := filesystem.ReadFile(textPath)
if err != nil {
@@ -135,7 +138,7 @@ func writeXrayJson(xray *xrayJson, xrayPath string) error {
return err
}
return writeBytes(xrayBytes, xrayPath)
return nodep.WriteBytes(xrayBytes, xrayPath)
}
type xrayShareLink struct {

View File

@@ -8,9 +8,12 @@ import (
"net/url"
"github.com/xtls/libxray/nodep"
"github.com/xtls/xray-core/common/platform/filesystem"
)
// Convert XrayJson to share links.
// VMess will generate VMessAEAD link.
func ConvertXrayJsonToShareText(xrayPath string, textPath string) string {
xrayBytes, err := filesystem.ReadFile(xrayPath)
if err != nil {
@@ -40,7 +43,7 @@ func ConvertXrayJsonToShareText(xrayPath string, textPath string) string {
return "no valid outbounds"
}
text := strings.Join(links, "\n")
err = writeText(text, textPath)
err = nodep.WriteText(text, textPath)
if err != nil {
return err.Error()
}

View File

@@ -4,6 +4,7 @@ import (
"github.com/xtls/xray-core/common/uuid"
)
// convert text to uuid
func CustomUUID(text string) string {
id, err := uuid.ParseString(text)
if err != nil {

18
xray.go
View File

@@ -1,9 +1,11 @@
// libXray is an Xray wrapper focusing on improving the experience of Xray-core mobile development.
package libXray
import (
"os"
"runtime/debug"
"github.com/xtls/libxray/nodep"
"github.com/xtls/xray-core/common/cmdarg"
"github.com/xtls/xray-core/core"
_ "github.com/xtls/xray-core/main/distro/all"
@@ -33,10 +35,13 @@ func initEnv(datDir string) {
}
func setMaxMemory(maxMemory int64) {
os.Setenv("XRAY_MEMORY_FORCEFREE", "1")
initForceFree(maxMemory)
nodep.InitForceFree(maxMemory, 1)
}
// Run Xray instance.
// datDir means the dir which geosite.dat and geoip.dat are in.
// configPath means the config.json file path.
// maxMemory means the soft memory limit of golang, see SetMemoryLimit to find more information.
func RunXray(datDir string, configPath string, maxMemory int64) string {
initEnv(datDir)
if maxMemory > 0 {
@@ -55,6 +60,7 @@ func RunXray(datDir string, configPath string, maxMemory int64) string {
return ""
}
// Stop Xray instance.
func StopXray() string {
if coreServer != nil {
err := coreServer.Close()
@@ -66,6 +72,14 @@ func StopXray() string {
return ""
}
// Xray's version
func XrayVersion() string {
return core.Version()
}
// Wrapper of nodep.GetFreePorts
// count means how many ports you need.
// return ports divided by ":", like "1080:1081"
func GetFreePorts(count int) string {
return nodep.GetFreePorts(count)
}