Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/src/main/java/com/github/kr328/clash/ProxyActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class ProxyActivity : BaseActivity<ProxyDesign>() {
design.updateGroup(
it.index,
group.proxies,
group.type == Proxy.Type.Selector,
group.type == "Selector",
state,
unorderedStates
)
Expand Down
1 change: 0 additions & 1 deletion core/src/main/golang/.idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

95 changes: 82 additions & 13 deletions core/src/main/golang/native/config/fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,58 +10,75 @@ import (
"os"
P "path"
"runtime"
"strconv"
"strings"
"time"

"cfa/native/app"

"github.com/metacubex/mihomo/adapter/provider"
clashHttp "github.com/metacubex/mihomo/component/http"
RB "github.com/metacubex/mihomo/rules/bundle"
)

type Status struct {
Action string `json:"action"`
Args []string `json:"args"`
Progress int `json:"progress"`
MaxProgress int `json:"max"`
Action string `json:"action"`
Args []string `json:"args"`
Progress int `json:"progress"`
MaxProgress int `json:"max"`
SubUpload *int64 `json:"subUpload,omitempty"`
SubDownload *int64 `json:"subDownload,omitempty"`
SubTotal *int64 `json:"subTotal,omitempty"`
SubExpire *int64 `json:"subExpire,omitempty"`
SubUpdateInterval *int64 `json:"subUpdateInterval,omitempty"`
}

func openUrl(ctx context.Context, url string) (io.ReadCloser, error) {
type fetchHeader struct {
SubscriptionUserInfo string
ProfileUpdateInterval string
}

func openUrl(ctx context.Context, url string) (io.ReadCloser, fetchHeader, error) {
response, err := clashHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {"ClashMetaForAndroid/" + app.VersionName()}}, nil)

if err != nil {
return nil, err
return nil, fetchHeader{}, err
}

return response.Body, nil
return response.Body, fetchHeader{
SubscriptionUserInfo: response.Header.Get("subscription-userinfo"),
ProfileUpdateInterval: response.Header.Get("profile-update-interval"),
}, nil
}

func openContent(url string) (io.ReadCloser, error) {
return app.OpenContent(url)
}

func fetch(url *U.URL, file string) error {
func fetch(url *U.URL, file string) (fetchHeader, error) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()

var reader io.ReadCloser
var header fetchHeader
var err error

switch url.Scheme {
case "http", "https":
reader, err = openUrl(ctx, url.String())
reader, header, err = openUrl(ctx, url.String())
case "content":
reader, err = openContent(url.String())
default:
err = fmt.Errorf("unsupported scheme %s of %s", url.Scheme, url)
}

if err != nil {
return err
return fetchHeader{}, err
}

defer reader.Close()

return writeFile(file, reader)
return header, writeFile(file, reader)
}

func writeFile(file string, reader io.Reader) error {
Expand All @@ -82,6 +99,55 @@ func writeFile(file string, reader io.Reader) error {
return err
}

func parseProfileUpdateInterval(value string) (int64, bool) {
hours, err := strconv.ParseInt(strings.TrimSpace(value), 10, 64)
if err != nil {
return 0, false
}

if hours <= 0 {
return 0, true
}

interval := time.Duration(hours) * time.Hour
if interval < 15*time.Minute {
interval = 15 * time.Minute
}

return int64(interval / time.Millisecond), true
}

func reportSubscriptionInfo(header fetchHeader, reportStatus func(string)) {
userinfo := header.SubscriptionUserInfo
updateIntervalHeader := header.ProfileUpdateInterval
if userinfo == "" && updateIntervalHeader == "" {
return
}

status := Status{
Action: "SubscriptionInfo",
Args: []string{},
Progress: -1,
MaxProgress: -1,
}

if userinfo != "" {
info := provider.NewSubscriptionInfo(userinfo)
expire := info.Expire * 1000
status.SubUpload = &info.Upload
status.SubDownload = &info.Download
status.SubTotal = &info.Total
status.SubExpire = &expire
}

if interval, ok := parseProfileUpdateInterval(updateIntervalHeader); ok {
status.SubUpdateInterval = &interval
}

bytes, _ := json.Marshal(&status)
reportStatus(string(bytes))
}

func FetchAndValid(
path string,
url string,
Expand All @@ -105,9 +171,12 @@ func FetchAndValid(

reportStatus(string(bytes))

if err := fetch(url, configPath); err != nil {
header, err := fetch(url, configPath)
if err != nil {
return err
}

reportSubscriptionInfo(header, reportStatus)
}

defer runtime.GC()
Expand Down Expand Up @@ -166,7 +235,7 @@ func FetchAndValid(
}
}

_ = fetch(url, ps)
_, _ = fetch(url, ps)
})

bytes, _ := json.Marshal(&Status{
Expand Down
5 changes: 5 additions & 0 deletions core/src/main/golang/native/tunnel/proxies.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type Proxy struct {
Subtitle string `json:"subtitle"`
Type string `json:"type"`
Delay int `json:"delay"`
IsGroup bool `json:"isGroup"`
}

type ProxyGroup struct {
Expand Down Expand Up @@ -189,13 +190,15 @@ func convertProxies(proxies []C.Proxy, uiSubtitlePattern *regexp2.Regexp) []*Pro
break
}
}
_, isGroup := p.Adapter().(outboundgroup.ProxyGroup)

result = append(result, &Proxy{
Name: name,
Title: strings.TrimSpace(title),
Subtitle: strings.TrimSpace(subtitle),
Type: p.Type().String(),
Delay: int(p.LastDelayForTestUrl(testURL)),
IsGroup: isGroup,
})
}
return result
Expand Down Expand Up @@ -228,13 +231,15 @@ func collectProviders(providers []provider.ProxyProvider, uiSubtitlePattern *reg
break
}
}
_, isGroup := px.Adapter().(outboundgroup.ProxyGroup)

result = append(result, &Proxy{
Name: name,
Title: strings.TrimSpace(title),
Subtitle: strings.TrimSpace(subtitle),
Type: px.Type().String(),
Delay: int(px.LastDelayForTestUrl(testURL)),
IsGroup: isGroup,
})
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/com/github/kr328/clash/core/Clash.kt
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ object Clash {
fun queryGroup(name: String, sort: ProxySort): ProxyGroup {
return Bridge.nativeQueryGroup(name, sort.name)
?.let { Json.Default.decodeFromString(ProxyGroup.serializer(), it) }
?: ProxyGroup(Proxy.Type.Unknown, emptyList(), "")
?: ProxyGroup("Unknown", emptyList(), "")
}

fun healthCheck(name: String): CompletableDeferred<Unit> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ data class ConfigurationOverride(

@SerialName("whitelist")
WhiteList,

@SerialName("rule")
Rule,
}

@Serializable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,17 @@ data class FetchStatus(
val action: Action,
val args: List<String>,
val progress: Int,
val max: Int
val max: Int,
val subUpload: Long? = null,
val subDownload: Long? = null,
val subTotal: Long? = null,
val subExpire: Long? = null,
val subUpdateInterval: Long? = null,
) : Parcelable {
enum class Action {
FetchConfiguration,
FetchProviders,
SubscriptionInfo,
Verifying,
}

Expand All @@ -35,4 +41,4 @@ data class FetchStatus(
return arrayOfNulls(size)
}
}
}
}
45 changes: 2 additions & 43 deletions core/src/main/java/com/github/kr328/clash/core/model/Proxy.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,51 +10,10 @@ data class Proxy(
val name: String,
val title: String,
val subtitle: String,
val type: Type,
val type: String,
val delay: Int,
var isGroup: Boolean,
) : Parcelable {
@Suppress("unused")
enum class Type(val group: Boolean) {
Direct(false),
Reject(false),
RejectDrop(false),
Compatible(false),
Pass(false),
PassRule(false),

Shadowsocks(false),
ShadowsocksR(false),
Snell(false),
Socks5(false),
Http(false),
Vmess(false),
Vless(false),
Trojan(false),
Hysteria(false),
Hysteria2(false),
Tuic(false),
WireGuard(false),
Dns(false),
Ssh(false),
Mieru(false),
AnyTLS(false),
Sudoku(false),
Masque(false),
TrustTunnel(false),
OpenVPN(false),
Tailscale(false),
GostRelay(false),


Relay(true),
Selector(true),
Fallback(true),
URLTest(true),
LoadBalance(true),

Unknown(false);
}

override fun writeToParcel(parcel: Parcel, flags: Int) {
Parcelizer.encodeToParcel(serializer(), parcel, this)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import kotlinx.serialization.Serializable

@Serializable
data class ProxyGroup(
val type: Proxy.Type,
val type: String,
val proxies: List<Proxy>,
val now: String,
) : Parcelable {
Expand All @@ -35,13 +35,13 @@ data class ProxyGroup(
}

constructor(parcel: Parcel) : this(
Proxy.Type.values()[parcel.readInt()],
parcel.readString()!!,
SliceProxyList(parcel),
parcel.readString()!!,
)

override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(type.ordinal)
parcel.writeString(type)
SliceProxyList(proxies).writeToParcel(parcel, 0)
parcel.writeString(now)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,12 +352,14 @@ class OverrideSettingsDesign(
values = arrayOf(
null,
ConfigurationOverride.FilterMode.BlackList,
ConfigurationOverride.FilterMode.WhiteList
ConfigurationOverride.FilterMode.WhiteList,
ConfigurationOverride.FilterMode.Rule
),
valuesText = arrayOf(
R.string.dont_modify,
R.string.blacklist,
R.string.whitelist
R.string.whitelist,
R.string.rule
),
title = R.string.fakeip_filter_mode,
configure = dnsDependencies::add,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ class PropertiesDesign(context: Context) : Design<PropertiesDesign.Request>(cont
max = status.max
progress = status.progress
}
FetchStatus.Action.SubscriptionInfo -> Unit
FetchStatus.Action.Verifying -> {
text = context.getString(R.string.verifying)
isIndeterminate = false
Expand All @@ -186,4 +187,4 @@ class PropertiesDesign(context: Context) : Design<PropertiesDesign.Request>(cont
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class ProxyPageAdapter(
) {
val states = withContext(Dispatchers.Default) {
proxies.map {
val link = if (it.type.group) links[it.name] else null
val link = if (it.isGroup) links[it.name] else null

ProxyViewState(config, it, parent, link)
}
Expand Down
Loading