添加 -cvqxtvs 和 -eqxrs 命令,

分别意思是 convert QX to verysimple 和 extract QX remote servers

将圈叉的配置文件转换为verysimple格式,这样就可以更快地使用自己的vs客户端
This commit is contained in:
e1732a364fed
2000-01-01 00:00:00 +00:00
parent 12fcad3c22
commit 07b0a53a12
5 changed files with 189 additions and 16 deletions

View File

@@ -26,6 +26,9 @@ var (
cmdPrintVer bool
cmdGenerateUUid bool
cmdConvertQxToVs string
cmdExtractQX_remoteServer string
download bool
defaultApiServerConf machine.ApiServerConf
@@ -34,10 +37,13 @@ var (
)
func init() {
flag.BoolVar(&download, "d", false, " automatically download required mmdb file")
flag.BoolVar(&cmdPrintSupportedProtocols, "sp", false, "print supported protocols")
flag.BoolVar(&cmdPrintVer, "v", false, "print the version string then exit")
flag.BoolVar(&download, "d", false, " automatically download required mmdb file")
flag.BoolVar(&cmdGenerateUUid, "gu", false, " automatically generate a uuid for you")
flag.StringVar(&cmdConvertQxToVs, "cvqxtvs", "", "if given, convert qx server config string to vs toml config")
flag.StringVar(&cmdExtractQX_remoteServer, "eqxrs", "", "if given, automatically extract remote servers from quantumultX config for you")
//apiServer stuff
@@ -67,6 +73,18 @@ func runExitCommands() (atLeastOneCalled bool) {
generateAndPrintUUID()
}
if cmdConvertQxToVs != "" {
atLeastOneCalled = true
convertQxToVs()
}
if cmdExtractQX_remoteServer != "" {
atLeastOneCalled = true
extractQxRemoteServers()
}
return
}

View File

@@ -0,0 +1,63 @@
package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
"github.com/e1732a364fed/v2ray_simple/configAdapter"
"github.com/e1732a364fed/v2ray_simple/proxy"
"github.com/e1732a364fed/v2ray_simple/utils"
)
func convertQxToVs() {
dc := configAdapter.FromQX(cmdConvertQxToVs)
fmt.Println(utils.GetPurgedTomlStr(proxy.StandardConf{
Dial: []*proxy.DialConf{&dc},
}))
}
func extractQxRemoteServers() {
var bs []byte
var readE error
if strings.HasPrefix(cmdExtractQX_remoteServer, "http") {
fmt.Printf("downloading %s\n", cmdExtractQX_remoteServer)
resp, err := http.DefaultClient.Get(cmdExtractQX_remoteServer)
if err != nil {
fmt.Printf("Download failed %s\n", err.Error())
return
}
defer resp.Body.Close()
counter := &utils.DownloadPrintCounter{}
bs, readE = io.ReadAll(io.TeeReader(resp.Body, counter))
fmt.Printf("\n")
} else {
if utils.FileExist(cmdExtractQX_remoteServer) {
path := utils.GetFilePath(cmdExtractQX_remoteServer)
f, e := os.Open(path)
if e != nil {
fmt.Printf("Download failed %s\n", e.Error())
return
}
bs, readE = io.ReadAll(f)
} else {
fmt.Printf("file not exist %s\n", cmdExtractQX_remoteServer)
return
}
}
if readE != nil {
fmt.Printf("read failed %s\n", readE.Error())
return
}
configAdapter.ExtractQxRemoteServers(string(bs))
}

View File

@@ -1,8 +1,13 @@
package configAdapter
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"strconv"
"strings"
@@ -177,21 +182,64 @@ func ToQX(dc *proxy.DialConf) string {
return sb.String()
}
/* clash使用yaml作为配置格式。本函数中不导出整个yaml配置文件而只导出
func FromQX(str string) (dc proxy.DialConf) {
//qx 的配置应该是基本的逗号分隔值形式
str = utils.StandardizeSpaces(str)
strs := strings.Split(str, ",")
for i, p := range strs {
ss := strings.Split(p, "=")
n := ss[0]
v := ss[1]
n = strings.TrimSpace(n)
v = strings.TrimSpace(v)
if i == 0 {
dc.Protocol = n
hostport := v
host, port, err := net.SplitHostPort(hostport)
if err != nil {
fmt.Printf("FromQX: net.SplitHostPort err, %s\n", err.Error())
} else {
dc.Host = host
np, _ := strconv.Atoi(port)
dc.Port = np
}
} else {
switch n {
case "method":
dc.EncryptAlgo = v
case "password":
dc.Uuid = v
case "tag":
dc.Tag = v
}
}
}
if dc.Protocol == "shadowsocks" {
if dc.Uuid != "" && dc.EncryptAlgo != "" {
dc.Uuid = "method:" + dc.EncryptAlgo + "\n" + "pass:" + dc.Uuid
}
}
return
}
/*
clash使用yaml作为配置格式。本函数中不导出整个yaml配置文件而只导出
对应的proxies项下的子项比如
- name: "ss1"
type: ss
server: server
port: 443
cipher: chacha20-ietf-poly1305
password: "password"
- name: "ss1"
type: ss
server: server
port: 443
cipher: chacha20-ietf-poly1305
password: "password"
See https://github.com/Dreamacro/clash/wiki/Configuration
clash的配置对于不同的协议来说格式也有不同clash基本上尊重了每一个协议的约定, 但也不完全一致
*/
func ToClash(dc *proxy.DialConf) string {
//这里我们不使用外部yaml包可以减少依赖.
@@ -391,7 +439,7 @@ type V2rayNConfig struct {
Sni string `json:"sni"`
}
//See https://github.com/2dust/v2rayN/wiki/%E5%88%86%E4%BA%AB%E9%93%BE%E6%8E%A5%E6%A0%BC%E5%BC%8F%E8%AF%B4%E6%98%8E(ver-2)
// See https://github.com/2dust/v2rayN/wiki/%E5%88%86%E4%BA%AB%E9%93%BE%E6%8E%A5%E6%A0%BC%E5%BC%8F%E8%AF%B4%E6%98%8E(ver-2)
func ToV2rayN(dc *proxy.DialConf) string {
if dc.Protocol != "vmess" {
return "ToV2rayN doesn't support any protocol other than vmess, you give " + dc.Protocol
@@ -430,3 +478,47 @@ func ToV2rayN(dc *proxy.DialConf) string {
return "vmess://" + base64.URLEncoding.EncodeToString(bs)
}
func ExtractQxRemoteServers(configContentStr string) {
lines := strings.Split(configContentStr, "\n")
for i, l := range lines {
if strings.Contains(l, "[server_remote]") {
fmt.Printf("got [server_remote] field\n")
l = lines[i+1]
strs := strings.SplitN(l, ",", 2)
l = strs[0]
fmt.Printf("downloading %s\n", l)
resp, err := http.DefaultClient.Get(l)
if err != nil {
fmt.Printf("Download failed %s\n", err.Error())
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
fmt.Printf("Download got bad status: %s\n", resp.Status)
return
}
fmt.Printf("download ok, reading...\n")
buf := utils.GetBuf()
counter := &utils.DownloadPrintCounter{}
fmt.Printf("\nread ok\n")
io.Copy(buf, io.TeeReader(resp.Body, counter))
ls := bytes.Split(buf.Bytes(), []byte("\n"))
for _, v := range ls {
fmt.Println(string(v))
}
return
}
}
}

View File

@@ -127,7 +127,7 @@ func GetGatewayDeviceName() (string, error) {
// helper func, call GetGatewayDeviceName and utils.GetDarwinNetAdapterNameByInterfaceName.
//
// hardwarePort 和 interface的名称不同hardwareport是 Wi-Fi, 而interface.Name 是 eth0
// hardwarePort 和 interface的名称不同hardwareport是 Wi-Fi, 而interface.Name 是 en0
func GetDefaultHardwarePort() (string, error) {
n, e := GetGatewayDeviceName()
if e != nil {

View File

@@ -86,18 +86,18 @@ func SimpleDownloadFile(fname, downloadLink string) (ok bool) {
}
// https://golangcode.com/download-a-file-with-progress/
type downloadPrintCounter struct {
type DownloadPrintCounter struct {
Total uint64
}
func (wc *downloadPrintCounter) Write(p []byte) (int, error) {
func (wc *DownloadPrintCounter) Write(p []byte) (int, error) {
n := len(p)
wc.Total += uint64(n)
wc.PrintProgress()
return n, nil
}
func (wc downloadPrintCounter) PrintProgress() {
func (wc DownloadPrintCounter) PrintProgress() {
fmt.Printf("\r%s", strings.Repeat(" ", 35))
fmt.Printf("\rDownloading... %s complete", humanize.Bytes(wc.Total))
@@ -121,7 +121,7 @@ func DownloadAndUnzip(fname, downloadLink, dst string) (ok bool) {
return
}
buf := new(bytes.Buffer)
counter := &downloadPrintCounter{}
counter := &DownloadPrintCounter{}
io.Copy(buf, io.TeeReader(resp.Body, counter))
out := bytes.NewReader(buf.Bytes())