add url test

This commit is contained in:
Kr328 committed 2019-12-07 01:30:35 +08:00
1 parent a72c2d8abb
commit bda542d2e5
16 files changed
+270 -66

No files matched your search

+1 -26
View File
@@ -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")
+86 -12
View File
@@ -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
}
+2
View File
@@ -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)
}