add url test
This commit is contained in:
16 files changed
+270
-66
No files matched your search
@@ -4,9 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
|
||||
A "github.com/Dreamacro/clash/adapters/outbound"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
"github.com/Dreamacro/clash/tunnel"
|
||||
"github.com/kr328/cfa/profile"
|
||||
)
|
||||
|
||||
@@ -54,31 +52,8 @@ func handleProfileReload(client *net.UnixConn) {
|
||||
return
|
||||
}
|
||||
|
||||
proxies := tunnel.Instance().Proxies()
|
||||
|
||||
for k, v := range payload.Selected {
|
||||
p := proxies[k]
|
||||
|
||||
if p == nil {
|
||||
response.InvalidSelected = append(response.InvalidSelected, k)
|
||||
continue
|
||||
}
|
||||
|
||||
proxy, ok := p.(*A.Proxy)
|
||||
if !ok {
|
||||
response.InvalidSelected = append(response.InvalidSelected, k)
|
||||
continue
|
||||
}
|
||||
|
||||
selector, ok := proxy.ProxyAdapter.(*A.Selector)
|
||||
if !ok {
|
||||
response.InvalidSelected = append(response.InvalidSelected, k)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Infoln("Set selector " + k + " -> " + v)
|
||||
|
||||
selector.Set(v)
|
||||
setProxySelect(k, v)
|
||||
}
|
||||
|
||||
log.Infoln("Profile " + payload.Path + " loaded")
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/log"
|
||||
"github.com/Dreamacro/clash/proxy"
|
||||
@@ -95,8 +98,6 @@ func handleQueryProxies(client *net.UnixConn) {
|
||||
}
|
||||
|
||||
func handleSetProxy(client *net.UnixConn) {
|
||||
proxies := tunnel.Instance().Proxies()
|
||||
|
||||
var Request struct {
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
@@ -119,28 +120,101 @@ func handleSetProxy(client *net.UnixConn) {
|
||||
|
||||
json.Unmarshal(buf, &Request)
|
||||
|
||||
p := proxies[Request.Key]
|
||||
if err := setProxySelect(Request.Key, Request.Value); err != nil {
|
||||
Response.Error = err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
func handleUrlTest(client *net.UnixConn) {
|
||||
var request struct {
|
||||
URL string `json:"url"`
|
||||
Timeout int `json:"timeout"`
|
||||
Proxies []string `json:"proxies"`
|
||||
}
|
||||
|
||||
request.Proxies = make([]string, 0)
|
||||
|
||||
buf, err := readCommandPacket(client)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if json.Unmarshal(buf, &request) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Name string `json:"name"`
|
||||
Delay int `json:"delay"`
|
||||
}
|
||||
|
||||
proxies := tunnel.Instance().Proxies()
|
||||
channel := make(chan *Response, len(request.Proxies))
|
||||
|
||||
for _, p := range request.Proxies {
|
||||
go func(p string) {
|
||||
proxy := proxies[p]
|
||||
if proxy == nil {
|
||||
channel <- nil
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(request.Timeout)*time.Millisecond)
|
||||
|
||||
defer cancel()
|
||||
|
||||
delay, err := proxies[p].URLTest(ctx, request.URL)
|
||||
if err != nil {
|
||||
channel <- nil
|
||||
return
|
||||
}
|
||||
|
||||
channel <- &Response{
|
||||
Name: p,
|
||||
Delay: int(delay),
|
||||
}
|
||||
}(p)
|
||||
}
|
||||
|
||||
for range request.Proxies {
|
||||
response := <-channel
|
||||
|
||||
if response != nil {
|
||||
buf, _ := json.Marshal(&response)
|
||||
|
||||
writeCommandPacket(client, buf)
|
||||
}
|
||||
}
|
||||
|
||||
writeCommandPacket(client, nil)
|
||||
|
||||
log.Infoln("URLTest exited")
|
||||
}
|
||||
|
||||
func setProxySelect(name, selected string) error {
|
||||
proxies := tunnel.Instance().Proxies()
|
||||
|
||||
p := proxies[name]
|
||||
|
||||
if p == nil {
|
||||
Response.Error = "Unknown proxy " + Request.Key
|
||||
return
|
||||
return errors.New("Unknown proxy " + name)
|
||||
}
|
||||
|
||||
proxy, ok := p.(*A.Proxy)
|
||||
if !ok {
|
||||
Response.Error = "Invalid proxy " + Request.Key
|
||||
return
|
||||
return errors.New("Invalid proxy " + name)
|
||||
}
|
||||
|
||||
selector, ok := proxy.ProxyAdapter.(*A.Selector)
|
||||
if !ok {
|
||||
Response.Error = "Not selector"
|
||||
return
|
||||
return errors.New("Not selector")
|
||||
}
|
||||
|
||||
log.Infoln("Set selector " + Request.Key + " -> " + Request.Value)
|
||||
log.Infoln("Set selector " + name + " -> " + selected)
|
||||
|
||||
if err := selector.Set(Request.Value); err != nil {
|
||||
Response.Error = err.Error()
|
||||
if err := selector.Set(selected); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -19,6 +19,7 @@ const (
|
||||
commandPullBandwidth uint32 = 8
|
||||
commandSetProxy uint32 = 9
|
||||
commandQueryGeneral uint32 = 10
|
||||
commandUrlTest uint32 = 11
|
||||
)
|
||||
|
||||
var handlers map[uint32]func(*net.UnixConn) = make(map[uint32]func(*net.UnixConn))
|
||||
@@ -35,6 +36,7 @@ func init() {
|
||||
handlers[commandPullBandwidth] = handlePullBandwidthEvent // event.go
|
||||
handlers[commandSetProxy] = handleSetProxy // proxies.go
|
||||
handlers[commandQueryGeneral] = handleQueryGeneral // proxies.go
|
||||
handlers[commandUrlTest] = handleUrlTest // proxies.go
|
||||
}
|
||||
|
||||
// Start local control server
|
||||
|
||||
@@ -6,12 +6,11 @@ import com.github.kr328.clash.core.event.BandwidthEvent
|
||||
import com.github.kr328.clash.core.event.LogEvent
|
||||
import com.github.kr328.clash.core.event.ProcessEvent
|
||||
import com.github.kr328.clash.core.event.SpeedEvent
|
||||
import com.github.kr328.clash.core.model.GeneralPacket
|
||||
import com.github.kr328.clash.core.model.LoadProfilePacket
|
||||
import com.github.kr328.clash.core.model.RawProxyPacket
|
||||
import com.github.kr328.clash.core.model.SetProxyPacket
|
||||
import com.github.kr328.clash.core.model.*
|
||||
import com.github.kr328.clash.core.utils.Log
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonConfiguration
|
||||
import kotlinx.serialization.stringify
|
||||
import java.io.File
|
||||
import java.io.FileDescriptor
|
||||
import java.io.IOException
|
||||
@@ -33,8 +32,12 @@ class Clash(
|
||||
const val COMMAND_PULL_BANDWIDTH = 8
|
||||
const val COMMAND_SET_PROXY = 9
|
||||
const val COMMAND_QUERY_GENERAL = 10
|
||||
const val COMMAND_URL_TEST = 11
|
||||
|
||||
const val PING_REPLY = 233
|
||||
|
||||
const val DEFAULT_URL_TEST_TIMEOUT = 5000
|
||||
const val DEFAULT_URL_TEST_URL = "https://www.gstatic.com/generate_204"
|
||||
}
|
||||
|
||||
val process = ClashProcess(context, clashDir, controllerPath, listener)
|
||||
@@ -153,6 +156,27 @@ class Clash(
|
||||
}
|
||||
}
|
||||
|
||||
fun startUrlTest(proxies: List<String>, callback: (String, Long) -> Unit) {
|
||||
runControl(COMMAND_URL_TEST) { _, input, output ->
|
||||
output.writeString(Json(JsonConfiguration.Stable)
|
||||
.stringify(UrlTestPacket.Request.serializer(),
|
||||
UrlTestPacket.Request(proxies, DEFAULT_URL_TEST_TIMEOUT, DEFAULT_URL_TEST_URL)))
|
||||
|
||||
while ( true ) {
|
||||
val data = input.readString()
|
||||
if ( data.isEmpty() )
|
||||
return@runControl
|
||||
|
||||
val response = Json(JsonConfiguration.Stable)
|
||||
.parse(UrlTestPacket.Response.serializer(), data)
|
||||
|
||||
callback(response.name, response.delay)
|
||||
}
|
||||
}
|
||||
|
||||
Log.i("Url test exited")
|
||||
}
|
||||
|
||||
fun startTunDevice(fd: FileDescriptor, mtu: Int) {
|
||||
runControl(COMMAND_TUN_START) { socket, _, output ->
|
||||
socket.setFileDescriptorsForSend(arrayOf(fd))
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.github.kr328.clash.core.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
class UrlTestPacket {
|
||||
@Serializable
|
||||
data class Request(val proxies: List<String>, val timeout: Int, val url: String)
|
||||
@Serializable
|
||||
data class Response(val name: String, val delay: Long)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user