mirror of
https://github.com/bolucat/Archive.git
synced 2025-09-26 20:21:35 +08:00
Update On Wed Aug 28 20:33:34 CEST 2024
This commit is contained in:
1
.github/update.log
vendored
1
.github/update.log
vendored
@@ -747,3 +747,4 @@ Update On Sat Aug 24 20:31:41 CEST 2024
|
||||
Update On Sun Aug 25 20:30:10 CEST 2024
|
||||
Update On Mon Aug 26 20:34:29 CEST 2024
|
||||
Update On Tue Aug 27 20:32:11 CEST 2024
|
||||
Update On Wed Aug 28 20:33:23 CEST 2024
|
||||
|
@@ -46,6 +46,14 @@ func (set *IpCidrSet) IsContain(ip netip.Addr) bool {
|
||||
return set.ToIPSet().Contains(ip.WithZone(""))
|
||||
}
|
||||
|
||||
// MatchIp implements C.IpMatcher
|
||||
func (set *IpCidrSet) MatchIp(ip netip.Addr) bool {
|
||||
if set.IsEmpty() {
|
||||
return false
|
||||
}
|
||||
return set.IsContain(ip)
|
||||
}
|
||||
|
||||
func (set *IpCidrSet) Merge() error {
|
||||
var b netipx.IPSetBuilder
|
||||
b.AddSet(set.ToIPSet())
|
||||
|
@@ -35,7 +35,7 @@ type Pool struct {
|
||||
offset netip.Addr
|
||||
cycle bool
|
||||
mux sync.Mutex
|
||||
host []C.Rule
|
||||
host []C.DomainMatcher
|
||||
ipnet netip.Prefix
|
||||
store store
|
||||
}
|
||||
@@ -66,8 +66,8 @@ func (p *Pool) LookBack(ip netip.Addr) (string, bool) {
|
||||
|
||||
// ShouldSkipped return if domain should be skipped
|
||||
func (p *Pool) ShouldSkipped(domain string) bool {
|
||||
for _, rule := range p.host {
|
||||
if match, _ := rule.Match(&C.Metadata{Host: domain}); match {
|
||||
for _, matcher := range p.host {
|
||||
if matcher.MatchDomain(domain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ func (p *Pool) restoreState() {
|
||||
|
||||
type Options struct {
|
||||
IPNet netip.Prefix
|
||||
Host []C.Rule
|
||||
Host []C.DomainMatcher
|
||||
|
||||
// Size sets the maximum number of entries in memory
|
||||
// and does not work if Persistence is true
|
||||
|
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/metacubex/mihomo/component/profile/cachefile"
|
||||
"github.com/metacubex/mihomo/component/trie"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
RP "github.com/metacubex/mihomo/rules/provider"
|
||||
|
||||
"github.com/metacubex/bbolt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -157,7 +156,7 @@ func TestPool_Skip(t *testing.T) {
|
||||
pools, tempfile, err := createPools(Options{
|
||||
IPNet: ipnet,
|
||||
Size: 10,
|
||||
Host: []C.Rule{RP.NewDomainSet(tree.NewDomainSet(), "")},
|
||||
Host: []C.DomainMatcher{tree.NewDomainSet()},
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
defer os.Remove(tempfile)
|
||||
|
@@ -22,23 +22,23 @@ var (
|
||||
type Dispatcher struct {
|
||||
enable bool
|
||||
sniffers map[sniffer.Sniffer]SnifferConfig
|
||||
forceDomain []C.Rule
|
||||
skipSrcAddress []C.Rule
|
||||
skipDstAddress []C.Rule
|
||||
skipDomain []C.Rule
|
||||
forceDomain []C.DomainMatcher
|
||||
skipSrcAddress []C.IpMatcher
|
||||
skipDstAddress []C.IpMatcher
|
||||
skipDomain []C.DomainMatcher
|
||||
skipList *lru.LruCache[netip.AddrPort, uint8]
|
||||
forceDnsMapping bool
|
||||
parsePureIp bool
|
||||
}
|
||||
|
||||
func (sd *Dispatcher) shouldOverride(metadata *C.Metadata) bool {
|
||||
for _, rule := range sd.skipDstAddress {
|
||||
if ok, _ := rule.Match(&C.Metadata{DstIP: metadata.DstIP}); ok {
|
||||
for _, matcher := range sd.skipDstAddress {
|
||||
if matcher.MatchIp(metadata.DstIP) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for _, rule := range sd.skipSrcAddress {
|
||||
if ok, _ := rule.Match(&C.Metadata{DstIP: metadata.SrcIP}); ok {
|
||||
for _, matcher := range sd.skipSrcAddress {
|
||||
if matcher.MatchIp(metadata.SrcIP) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -48,8 +48,8 @@ func (sd *Dispatcher) shouldOverride(metadata *C.Metadata) bool {
|
||||
if metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping {
|
||||
return true
|
||||
}
|
||||
for _, rule := range sd.forceDomain {
|
||||
if ok, _ := rule.Match(&C.Metadata{Host: metadata.Host}); ok {
|
||||
for _, matcher := range sd.forceDomain {
|
||||
if matcher.MatchDomain(metadata.Host) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -112,8 +112,8 @@ func (sd *Dispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata) bool
|
||||
return false
|
||||
}
|
||||
|
||||
for _, rule := range sd.skipDomain {
|
||||
if ok, _ := rule.Match(&C.Metadata{Host: host}); ok {
|
||||
for _, matcher := range sd.skipDomain {
|
||||
if matcher.MatchDomain(host) {
|
||||
log.Debugln("[Sniffer] Skip sni[%s]", host)
|
||||
return false
|
||||
}
|
||||
@@ -200,10 +200,10 @@ func (sd *Dispatcher) cacheSniffFailed(metadata *C.Metadata) {
|
||||
type Config struct {
|
||||
Enable bool
|
||||
Sniffers map[sniffer.Type]SnifferConfig
|
||||
ForceDomain []C.Rule
|
||||
SkipSrcAddress []C.Rule
|
||||
SkipDstAddress []C.Rule
|
||||
SkipDomain []C.Rule
|
||||
ForceDomain []C.DomainMatcher
|
||||
SkipSrcAddress []C.IpMatcher
|
||||
SkipDstAddress []C.IpMatcher
|
||||
SkipDomain []C.DomainMatcher
|
||||
ForceDnsMapping bool
|
||||
ParsePureIp bool
|
||||
}
|
||||
|
@@ -172,6 +172,11 @@ func (ss *DomainSet) Foreach(f func(key string) bool) {
|
||||
})
|
||||
}
|
||||
|
||||
// MatchDomain implements C.DomainMatcher
|
||||
func (ss *DomainSet) MatchDomain(domain string) bool {
|
||||
return ss.Has(domain)
|
||||
}
|
||||
|
||||
func setBit(bm *[]uint64, i int, v int) {
|
||||
for i>>6 >= len(*bm) {
|
||||
*bm = append(*bm, 0)
|
||||
|
@@ -143,8 +143,8 @@ type DNS struct {
|
||||
UseSystemHosts bool
|
||||
NameServer []dns.NameServer
|
||||
Fallback []dns.NameServer
|
||||
FallbackIPFilter []C.Rule
|
||||
FallbackDomainFilter []C.Rule
|
||||
FallbackIPFilter []C.IpMatcher
|
||||
FallbackDomainFilter []C.DomainMatcher
|
||||
Listen string
|
||||
EnhancedMode C.DNSMode
|
||||
DefaultNameserver []dns.NameServer
|
||||
@@ -640,7 +640,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
||||
}
|
||||
config.Hosts = hosts
|
||||
|
||||
dnsCfg, err := parseDNS(rawCfg, hosts, rules, ruleProviders)
|
||||
dnsCfg, err := parseDNS(rawCfg, hosts, ruleProviders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1297,7 +1297,7 @@ func parsePureDNSServer(server string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider, respectRules bool, preferH3 bool) ([]dns.Policy, error) {
|
||||
func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], ruleProviders map[string]providerTypes.RuleProvider, respectRules bool, preferH3 bool) ([]dns.Policy, error) {
|
||||
var policy []dns.Policy
|
||||
re := regexp.MustCompile(`[a-zA-Z0-9\-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?`)
|
||||
|
||||
@@ -1350,18 +1350,18 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rules [
|
||||
|
||||
if strings.HasPrefix(domain, "rule-set:") {
|
||||
domainSetName := domain[9:]
|
||||
rule, err := parseDomainRuleSet(domainSetName, "dns.nameserver-policy", ruleProviders)
|
||||
matcher, err := parseDomainRuleSet(domainSetName, "dns.nameserver-policy", ruleProviders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policy[idx] = dns.Policy{Rule: rule, NameServers: nameservers}
|
||||
policy[idx] = dns.Policy{Matcher: matcher, NameServers: nameservers}
|
||||
} else if strings.HasPrefix(domain, "geosite:") {
|
||||
country := domain[8:]
|
||||
rule, err := RC.NewGEOSITE(country, "dns.nameserver-policy")
|
||||
matcher, err := RC.NewGEOSITE(country, "dns.nameserver-policy")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policy[idx] = dns.Policy{Rule: rule, NameServers: nameservers}
|
||||
policy[idx] = dns.Policy{Matcher: matcher, NameServers: nameservers}
|
||||
} else {
|
||||
if _, valid := trie.ValidAndSplitDomain(domain); !valid {
|
||||
return nil, fmt.Errorf("DNS ResoverRule invalid domain: %s", domain)
|
||||
@@ -1372,7 +1372,7 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rules [
|
||||
return policy, nil
|
||||
}
|
||||
|
||||
func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider) (*DNS, error) {
|
||||
func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], ruleProviders map[string]providerTypes.RuleProvider) (*DNS, error) {
|
||||
cfg := rawCfg.DNS
|
||||
if cfg.Enable && len(cfg.NameServer) == 0 {
|
||||
return nil, fmt.Errorf("if DNS configuration is turned on, NameServer cannot be empty")
|
||||
@@ -1400,7 +1400,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy, rules, ruleProviders, cfg.RespectRules, cfg.PreferH3); err != nil {
|
||||
if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy, ruleProviders, cfg.RespectRules, cfg.PreferH3); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1467,14 +1467,13 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
||||
dnsCfg.FakeIPRange = pool
|
||||
}
|
||||
|
||||
var rule C.Rule
|
||||
if len(cfg.Fallback) != 0 {
|
||||
if cfg.FallbackFilter.GeoIP {
|
||||
rule, err = RC.NewGEOIP(cfg.FallbackFilter.GeoIPCode, "dns.fallback-filter.geoip", false, true)
|
||||
matcher, err := RC.NewGEOIP(cfg.FallbackFilter.GeoIPCode, "dns.fallback-filter.geoip", false, true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load GeoIP dns fallback filter error, %w", err)
|
||||
}
|
||||
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, rule)
|
||||
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, matcher)
|
||||
}
|
||||
if len(cfg.FallbackFilter.IPCIDR) > 0 {
|
||||
cidrSet := cidr.NewIpCidrSet()
|
||||
@@ -1488,8 +1487,8 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule = RP.NewIpCidrSet(cidrSet, "dns.fallback-filter.ipcidr")
|
||||
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, rule)
|
||||
matcher := cidrSet // dns.fallback-filter.ipcidr
|
||||
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, matcher)
|
||||
}
|
||||
if len(cfg.FallbackFilter.Domain) > 0 {
|
||||
domainTrie := trie.New[struct{}]()
|
||||
@@ -1499,17 +1498,17 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
||||
return nil, fmt.Errorf("DNS FallbackDomain[%d] format error: %w", idx, err)
|
||||
}
|
||||
}
|
||||
rule = RP.NewDomainSet(domainTrie.NewDomainSet(), "dns.fallback-filter.domain")
|
||||
dnsCfg.FallbackDomainFilter = append(dnsCfg.FallbackDomainFilter, rule)
|
||||
matcher := domainTrie.NewDomainSet() // dns.fallback-filter.domain
|
||||
dnsCfg.FallbackDomainFilter = append(dnsCfg.FallbackDomainFilter, matcher)
|
||||
}
|
||||
if len(cfg.FallbackFilter.GeoSite) > 0 {
|
||||
log.Warnln("replace fallback-filter.geosite with nameserver-policy, it will be removed in the future")
|
||||
for idx, geoSite := range cfg.FallbackFilter.GeoSite {
|
||||
rule, err = RC.NewGEOSITE(geoSite, "dns.fallback-filter.geosite")
|
||||
matcher, err := RC.NewGEOSITE(geoSite, "dns.fallback-filter.geosite")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("DNS FallbackGeosite[%d] format error: %w", idx, err)
|
||||
}
|
||||
dnsCfg.FallbackDomainFilter = append(dnsCfg.FallbackDomainFilter, rule)
|
||||
dnsCfg.FallbackDomainFilter = append(dnsCfg.FallbackDomainFilter, matcher)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1701,8 +1700,8 @@ func parseSniffer(snifferRaw RawSniffer, ruleProviders map[string]providerTypes.
|
||||
return snifferConfig, nil
|
||||
}
|
||||
|
||||
func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (ipRules []C.Rule, err error) {
|
||||
var rule C.Rule
|
||||
func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (matchers []C.IpMatcher, err error) {
|
||||
var matcher C.IpMatcher
|
||||
for _, ipcidr := range addresses {
|
||||
ipcidrLower := strings.ToLower(ipcidr)
|
||||
if strings.Contains(ipcidrLower, "geoip:") {
|
||||
@@ -1710,22 +1709,22 @@ func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, country := range subkeys {
|
||||
rule, err = RC.NewGEOIP(country, adapterName, false, false)
|
||||
matcher, err = RC.NewGEOIP(country, adapterName, false, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipRules = append(ipRules, rule)
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
} else if strings.Contains(ipcidrLower, "rule-set:") {
|
||||
subkeys := strings.Split(ipcidr, ":")
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, domainSetName := range subkeys {
|
||||
rule, err = parseIPRuleSet(domainSetName, adapterName, ruleProviders)
|
||||
matcher, err = parseIPRuleSet(domainSetName, adapterName, ruleProviders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipRules = append(ipRules, rule)
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
} else {
|
||||
if cidrSet == nil {
|
||||
@@ -1742,14 +1741,14 @@ func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule = RP.NewIpCidrSet(cidrSet, adapterName)
|
||||
ipRules = append(ipRules, rule)
|
||||
matcher = cidrSet
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (domainRules []C.Rule, err error) {
|
||||
var rule C.Rule
|
||||
func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (matchers []C.DomainMatcher, err error) {
|
||||
var matcher C.DomainMatcher
|
||||
for _, domain := range domains {
|
||||
domainLower := strings.ToLower(domain)
|
||||
if strings.Contains(domainLower, "geosite:") {
|
||||
@@ -1757,22 +1756,22 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapte
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, country := range subkeys {
|
||||
rule, err = RC.NewGEOSITE(country, adapterName)
|
||||
matcher, err = RC.NewGEOSITE(country, adapterName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domainRules = append(domainRules, rule)
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
} else if strings.Contains(domainLower, "rule-set:") {
|
||||
subkeys := strings.Split(domain, ":")
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, domainSetName := range subkeys {
|
||||
rule, err = parseDomainRuleSet(domainSetName, adapterName, ruleProviders)
|
||||
matcher, err = parseDomainRuleSet(domainSetName, adapterName, ruleProviders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domainRules = append(domainRules, rule)
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
} else {
|
||||
if domainTrie == nil {
|
||||
@@ -1785,13 +1784,13 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapte
|
||||
}
|
||||
}
|
||||
if !domainTrie.IsEmpty() {
|
||||
rule = RP.NewDomainSet(domainTrie.NewDomainSet(), adapterName)
|
||||
domainRules = append(domainRules, rule)
|
||||
matcher = domainTrie.NewDomainSet()
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func parseIPRuleSet(domainSetName string, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (C.Rule, error) {
|
||||
func parseIPRuleSet(domainSetName string, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (C.IpMatcher, error) {
|
||||
if rp, ok := ruleProviders[domainSetName]; !ok {
|
||||
return nil, fmt.Errorf("not found rule-set: %s", domainSetName)
|
||||
} else {
|
||||
@@ -1806,7 +1805,7 @@ func parseIPRuleSet(domainSetName string, adapterName string, ruleProviders map[
|
||||
return RP.NewRuleSet(domainSetName, adapterName, true)
|
||||
}
|
||||
|
||||
func parseDomainRuleSet(domainSetName string, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (C.Rule, error) {
|
||||
func parseDomainRuleSet(domainSetName string, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (C.DomainMatcher, error) {
|
||||
if rp, ok := ruleProviders[domainSetName]; !ok {
|
||||
return nil, fmt.Errorf("not found rule-set: %s", domainSetName)
|
||||
} else {
|
||||
|
11
clash-meta/constant/matcher.go
Normal file
11
clash-meta/constant/matcher.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package constant
|
||||
|
||||
import "net/netip"
|
||||
|
||||
type DomainMatcher interface {
|
||||
MatchDomain(domain string) bool
|
||||
}
|
||||
|
||||
type IpMatcher interface {
|
||||
MatchIp(ip netip.Addr) bool
|
||||
}
|
@@ -133,7 +133,9 @@ type Metadata struct {
|
||||
Type Type `json:"type"`
|
||||
SrcIP netip.Addr `json:"sourceIP"`
|
||||
DstIP netip.Addr `json:"destinationIP"`
|
||||
SrcGeoIP []string `json:"sourceGeoIP"` // can be nil if never queried, empty slice if got no result
|
||||
DstGeoIP []string `json:"destinationGeoIP"` // can be nil if never queried, empty slice if got no result
|
||||
SrcIPASN string `json:"sourceIPASN"`
|
||||
DstIPASN string `json:"destinationIPASN"`
|
||||
SrcPort uint16 `json:"sourcePort,string"` // `,string` is used to compatible with old version json output
|
||||
DstPort uint16 `json:"destinationPort,string"` // `,string` is used to compatible with old version json output
|
||||
|
@@ -27,8 +27,6 @@ const (
|
||||
ProcessNameRegex
|
||||
ProcessPathRegex
|
||||
RuleSet
|
||||
DomainSet
|
||||
IpCidrSet
|
||||
Network
|
||||
Uid
|
||||
SubRules
|
||||
@@ -92,10 +90,6 @@ func (rt RuleType) String() string {
|
||||
return "Match"
|
||||
case RuleSet:
|
||||
return "RuleSet"
|
||||
case DomainSet:
|
||||
return "DomainSet"
|
||||
case IpCidrSet:
|
||||
return "IpCidrSet"
|
||||
case Network:
|
||||
return "Network"
|
||||
case DSCP:
|
||||
|
@@ -21,13 +21,13 @@ func (p domainTriePolicy) Match(domain string) []dnsClient {
|
||||
return nil
|
||||
}
|
||||
|
||||
type domainRulePolicy struct {
|
||||
rule C.Rule
|
||||
type domainMatcherPolicy struct {
|
||||
matcher C.DomainMatcher
|
||||
dnsClients []dnsClient
|
||||
}
|
||||
|
||||
func (p domainRulePolicy) Match(domain string) []dnsClient {
|
||||
if ok, _ := p.rule.Match(&C.Metadata{Host: domain}); ok {
|
||||
func (p domainMatcherPolicy) Match(domain string) []dnsClient {
|
||||
if p.matcher.MatchDomain(domain) {
|
||||
return p.dnsClients
|
||||
}
|
||||
return nil
|
||||
|
@@ -42,8 +42,8 @@ type Resolver struct {
|
||||
hosts *trie.DomainTrie[resolver.HostValue]
|
||||
main []dnsClient
|
||||
fallback []dnsClient
|
||||
fallbackDomainFilters []C.Rule
|
||||
fallbackIPFilters []C.Rule
|
||||
fallbackDomainFilters []C.DomainMatcher
|
||||
fallbackIPFilters []C.IpMatcher
|
||||
group singleflight.Group[*D.Msg]
|
||||
cache dnsCache
|
||||
policy []dnsPolicy
|
||||
@@ -119,7 +119,7 @@ func (r *Resolver) LookupIPv6(ctx context.Context, host string) ([]netip.Addr, e
|
||||
|
||||
func (r *Resolver) shouldIPFallback(ip netip.Addr) bool {
|
||||
for _, filter := range r.fallbackIPFilters {
|
||||
if ok, _ := filter.Match(&C.Metadata{DstIP: ip}); ok {
|
||||
if filter.MatchIp(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -275,7 +275,7 @@ func (r *Resolver) shouldOnlyQueryFallback(m *D.Msg) bool {
|
||||
}
|
||||
|
||||
for _, df := range r.fallbackDomainFilters {
|
||||
if ok, _ := df.Match(&C.Metadata{Host: domain}); ok {
|
||||
if df.MatchDomain(domain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -398,7 +398,7 @@ func (ns NameServer) Equal(ns2 NameServer) bool {
|
||||
|
||||
type Policy struct {
|
||||
Domain string
|
||||
Rule C.Rule
|
||||
Matcher C.DomainMatcher
|
||||
NameServers []NameServer
|
||||
}
|
||||
|
||||
@@ -409,8 +409,8 @@ type Config struct {
|
||||
IPv6 bool
|
||||
IPv6Timeout uint
|
||||
EnhancedMode C.DNSMode
|
||||
FallbackIPFilter []C.Rule
|
||||
FallbackDomainFilter []C.Rule
|
||||
FallbackIPFilter []C.IpMatcher
|
||||
FallbackDomainFilter []C.DomainMatcher
|
||||
Pool *fakeip.Pool
|
||||
Hosts *trie.DomainTrie[resolver.HostValue]
|
||||
Policy []Policy
|
||||
@@ -495,8 +495,8 @@ func NewResolver(config Config) *Resolver {
|
||||
}
|
||||
|
||||
for _, policy := range config.Policy {
|
||||
if policy.Rule != nil {
|
||||
insertPolicy(domainRulePolicy{rule: policy.Rule, dnsClients: cacheTransform(policy.NameServers)})
|
||||
if policy.Matcher != nil {
|
||||
insertPolicy(domainMatcherPolicy{matcher: policy.Matcher, dnsClients: cacheTransform(policy.NameServers)})
|
||||
} else {
|
||||
if triePolicy == nil {
|
||||
triePolicy = trie.New[[]dnsClient]()
|
||||
|
@@ -3,6 +3,7 @@ package common
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"strings"
|
||||
|
||||
"github.com/metacubex/mihomo/component/geodata"
|
||||
@@ -11,6 +12,8 @@ import (
|
||||
"github.com/metacubex/mihomo/component/resolver"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
type GEOIP struct {
|
||||
@@ -41,52 +44,84 @@ func (g *GEOIP) Match(metadata *C.Metadata) (bool, string) {
|
||||
}
|
||||
|
||||
if g.country == "lan" {
|
||||
return ip.IsPrivate() ||
|
||||
ip.IsUnspecified() ||
|
||||
ip.IsLoopback() ||
|
||||
ip.IsMulticast() ||
|
||||
ip.IsLinkLocalUnicast() ||
|
||||
resolver.IsFakeBroadcastIP(ip), g.adapter
|
||||
return g.isLan(ip), g.adapter
|
||||
}
|
||||
|
||||
for _, code := range metadata.DstGeoIP {
|
||||
if g.country == code {
|
||||
return true, g.adapter
|
||||
}
|
||||
}
|
||||
|
||||
if !C.GeodataMode {
|
||||
if C.GeodataMode {
|
||||
if g.isSourceIP {
|
||||
codes := mmdb.IPInstance().LookupCode(ip.AsSlice())
|
||||
for _, code := range codes {
|
||||
if g.country == code {
|
||||
return true, g.adapter
|
||||
}
|
||||
if slices.Contains(metadata.SrcGeoIP, g.country) {
|
||||
return true, g.adapter
|
||||
}
|
||||
return false, g.adapter
|
||||
}
|
||||
|
||||
if metadata.DstGeoIP != nil {
|
||||
return false, g.adapter
|
||||
}
|
||||
metadata.DstGeoIP = mmdb.IPInstance().LookupCode(ip.AsSlice())
|
||||
for _, code := range metadata.DstGeoIP {
|
||||
if g.country == code {
|
||||
} else {
|
||||
if slices.Contains(metadata.DstGeoIP, g.country) {
|
||||
return true, g.adapter
|
||||
}
|
||||
}
|
||||
return false, g.adapter
|
||||
matcher, err := g.getIPMatcher()
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
match := matcher.Match(ip)
|
||||
if match {
|
||||
if g.isSourceIP {
|
||||
metadata.SrcGeoIP = append(metadata.SrcGeoIP, g.country)
|
||||
} else {
|
||||
metadata.DstGeoIP = append(metadata.DstGeoIP, g.country)
|
||||
}
|
||||
}
|
||||
return match, g.adapter
|
||||
}
|
||||
|
||||
matcher, err := g.GetIPMatcher()
|
||||
if err != nil {
|
||||
return false, ""
|
||||
if g.isSourceIP {
|
||||
if metadata.SrcGeoIP != nil {
|
||||
return slices.Contains(metadata.SrcGeoIP, g.country), g.adapter
|
||||
}
|
||||
} else {
|
||||
if metadata.DstGeoIP != nil {
|
||||
return slices.Contains(metadata.DstGeoIP, g.country), g.adapter
|
||||
}
|
||||
}
|
||||
match := matcher.Match(ip)
|
||||
if match && !g.isSourceIP {
|
||||
metadata.DstGeoIP = append(metadata.DstGeoIP, g.country)
|
||||
codes := mmdb.IPInstance().LookupCode(ip.AsSlice())
|
||||
if g.isSourceIP {
|
||||
metadata.SrcGeoIP = codes
|
||||
} else {
|
||||
metadata.DstGeoIP = codes
|
||||
}
|
||||
return match, g.adapter
|
||||
if slices.Contains(codes, g.country) {
|
||||
return true, g.adapter
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// MatchIp implements C.IpMatcher
|
||||
func (g *GEOIP) MatchIp(ip netip.Addr) bool {
|
||||
if !ip.IsValid() {
|
||||
return false
|
||||
}
|
||||
|
||||
if g.country == "lan" {
|
||||
return g.isLan(ip)
|
||||
}
|
||||
|
||||
if C.GeodataMode {
|
||||
matcher, err := g.getIPMatcher()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return matcher.Match(ip)
|
||||
}
|
||||
|
||||
codes := mmdb.IPInstance().LookupCode(ip.AsSlice())
|
||||
return slices.Contains(codes, g.country)
|
||||
}
|
||||
|
||||
func (g *GEOIP) isLan(ip netip.Addr) bool {
|
||||
return ip.IsPrivate() ||
|
||||
ip.IsUnspecified() ||
|
||||
ip.IsLoopback() ||
|
||||
ip.IsMulticast() ||
|
||||
ip.IsLinkLocalUnicast() ||
|
||||
resolver.IsFakeBroadcastIP(ip)
|
||||
}
|
||||
|
||||
func (g *GEOIP) Adapter() string {
|
||||
@@ -106,14 +141,19 @@ func (g *GEOIP) GetCountry() string {
|
||||
}
|
||||
|
||||
func (g *GEOIP) GetIPMatcher() (router.IPMatcher, error) {
|
||||
if g.geodata {
|
||||
geoIPMatcher, err := geodata.LoadGeoIPMatcher(g.country)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[GeoIP] %w", err)
|
||||
}
|
||||
return geoIPMatcher, nil
|
||||
if C.GeodataMode {
|
||||
return g.getIPMatcher()
|
||||
}
|
||||
return nil, errors.New("geoip country not set")
|
||||
return nil, errors.New("not geodata mode")
|
||||
}
|
||||
|
||||
func (g *GEOIP) getIPMatcher() (router.IPMatcher, error) {
|
||||
geoIPMatcher, err := geodata.LoadGeoIPMatcher(g.country)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[GeoIP] %w", err)
|
||||
}
|
||||
return geoIPMatcher, nil
|
||||
|
||||
}
|
||||
|
||||
func (g *GEOIP) GetRecodeSize() int {
|
||||
@@ -141,12 +181,13 @@ func NewGEOIP(country string, adapter string, isSrc, noResolveIP bool) (*GEOIP,
|
||||
return geoip, nil
|
||||
}
|
||||
|
||||
geoip.geodata = true
|
||||
geoIPMatcher, err := geoip.GetIPMatcher() // test load
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if C.GeodataMode {
|
||||
geoIPMatcher, err := geoip.getIPMatcher() // test load
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Infoln("Finished initial GeoIP rule %s => %s, records: %d", country, adapter, geoIPMatcher.Count())
|
||||
}
|
||||
|
||||
log.Infoln("Finished initial GeoIP rule %s => %s, records: %d", country, adapter, geoIPMatcher.Count())
|
||||
return geoip, nil
|
||||
}
|
||||
|
@@ -23,15 +23,19 @@ func (gs *GEOSITE) RuleType() C.RuleType {
|
||||
}
|
||||
|
||||
func (gs *GEOSITE) Match(metadata *C.Metadata) (bool, string) {
|
||||
domain := metadata.RuleHost()
|
||||
return gs.MatchDomain(metadata.RuleHost()), gs.adapter
|
||||
}
|
||||
|
||||
// MatchDomain implements C.DomainMatcher
|
||||
func (gs *GEOSITE) MatchDomain(domain string) bool {
|
||||
if len(domain) == 0 {
|
||||
return false, ""
|
||||
return false
|
||||
}
|
||||
matcher, err := gs.GetDomainMatcher()
|
||||
if err != nil {
|
||||
return false, ""
|
||||
return false
|
||||
}
|
||||
return matcher.ApplyDomain(domain), gs.adapter
|
||||
return matcher.ApplyDomain(domain)
|
||||
}
|
||||
|
||||
func (gs *GEOSITE) Adapter() string {
|
||||
|
@@ -28,8 +28,11 @@ func (a *ASN) Match(metadata *C.Metadata) (bool, string) {
|
||||
|
||||
result := mmdb.ASNInstance().LookupASN(ip.AsSlice())
|
||||
asnNumber := strconv.FormatUint(uint64(result.AutonomousSystemNumber), 10)
|
||||
if !a.isSourceIP {
|
||||
metadata.DstIPASN = asnNumber + " " + result.AutonomousSystemOrganization
|
||||
ipASN := asnNumber + " " + result.AutonomousSystemOrganization
|
||||
if a.isSourceIP {
|
||||
metadata.SrcIPASN = ipASN
|
||||
} else {
|
||||
metadata.DstIPASN = ipASN
|
||||
}
|
||||
|
||||
match := a.asn == asnNumber
|
||||
|
@@ -1,40 +0,0 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"github.com/metacubex/mihomo/component/trie"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
)
|
||||
|
||||
type DomainSet struct {
|
||||
*domainStrategy
|
||||
adapter string
|
||||
}
|
||||
|
||||
func (d *DomainSet) ProviderNames() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DomainSet) RuleType() C.RuleType {
|
||||
return C.DomainSet
|
||||
}
|
||||
|
||||
func (d *DomainSet) Match(metadata *C.Metadata) (bool, string) {
|
||||
return d.domainStrategy.Match(metadata), d.adapter
|
||||
}
|
||||
|
||||
func (d *DomainSet) Adapter() string {
|
||||
return d.adapter
|
||||
}
|
||||
|
||||
func (d *DomainSet) Payload() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func NewDomainSet(domainSet *trie.DomainSet, adapter string) *DomainSet {
|
||||
return &DomainSet{
|
||||
domainStrategy: &domainStrategy{domainSet: domainSet},
|
||||
adapter: adapter,
|
||||
}
|
||||
}
|
||||
|
||||
var _ C.Rule = (*DomainSet)(nil)
|
@@ -1,40 +0,0 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"github.com/metacubex/mihomo/component/cidr"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
)
|
||||
|
||||
type IpCidrSet struct {
|
||||
*ipcidrStrategy
|
||||
adapter string
|
||||
}
|
||||
|
||||
func (d *IpCidrSet) ProviderNames() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *IpCidrSet) RuleType() C.RuleType {
|
||||
return C.IpCidrSet
|
||||
}
|
||||
|
||||
func (d *IpCidrSet) Match(metadata *C.Metadata) (bool, string) {
|
||||
return d.ipcidrStrategy.Match(metadata), d.adapter
|
||||
}
|
||||
|
||||
func (d *IpCidrSet) Adapter() string {
|
||||
return d.adapter
|
||||
}
|
||||
|
||||
func (d *IpCidrSet) Payload() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func NewIpCidrSet(cidrSet *cidr.IpCidrSet, adapter string) *IpCidrSet {
|
||||
return &IpCidrSet{
|
||||
ipcidrStrategy: &ipcidrStrategy{cidrSet: cidrSet},
|
||||
adapter: adapter,
|
||||
}
|
||||
}
|
||||
|
||||
var _ C.Rule = (*IpCidrSet)(nil)
|
@@ -1,6 +1,8 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
P "github.com/metacubex/mihomo/constant/provider"
|
||||
"github.com/metacubex/mihomo/rules/common"
|
||||
@@ -35,6 +37,18 @@ func (rs *RuleSet) Match(metadata *C.Metadata) (bool, string) {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// MatchDomain implements C.DomainMatcher
|
||||
func (rs *RuleSet) MatchDomain(domain string) bool {
|
||||
ok, _ := rs.Match(&C.Metadata{Host: domain})
|
||||
return ok
|
||||
}
|
||||
|
||||
// MatchIp implements C.IpMatcher
|
||||
func (rs *RuleSet) MatchIp(ip netip.Addr) bool {
|
||||
ok, _ := rs.Match(&C.Metadata{DstIP: ip})
|
||||
return ok
|
||||
}
|
||||
|
||||
func (rs *RuleSet) Adapter() string {
|
||||
return rs.adapter
|
||||
}
|
||||
|
342
clash-nyanpasu/backend/Cargo.lock
generated
342
clash-nyanpasu/backend/Cargo.lock
generated
@@ -47,15 +47,6 @@ dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.6.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
@@ -199,7 +190,7 @@ dependencies = [
|
||||
"clipboard-win",
|
||||
"core-graphics 0.23.2",
|
||||
"image 0.25.2",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"objc2",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation",
|
||||
@@ -326,7 +317,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"futures-lite 1.13.0",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"parking",
|
||||
"polling 2.8.0",
|
||||
"rustix 0.37.27",
|
||||
@@ -348,7 +339,7 @@ dependencies = [
|
||||
"futures-lite 2.3.0",
|
||||
"parking",
|
||||
"polling 3.7.3",
|
||||
"rustix 0.38.34",
|
||||
"rustix 0.38.35",
|
||||
"slab",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
@@ -409,7 +400,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"event-listener 3.1.0",
|
||||
"futures-lite 1.13.0",
|
||||
"rustix 0.38.34",
|
||||
"rustix 0.38.35",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@@ -428,7 +419,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"event-listener 5.3.0",
|
||||
"futures-lite 2.3.0",
|
||||
"rustix 0.38.34",
|
||||
"rustix 0.38.35",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
@@ -456,7 +447,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"rustix 0.38.34",
|
||||
"rustix 0.38.35",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"windows-sys 0.59.0",
|
||||
@@ -545,7 +536,7 @@ checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arrayvec 0.7.6",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"nom 7.1.3",
|
||||
"num-rational",
|
||||
"v_frame",
|
||||
@@ -686,13 +677,13 @@ dependencies = [
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools 0.12.1",
|
||||
"lazy_static 1.5.0",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex 1.10.6",
|
||||
"regex",
|
||||
"rustc-hash 1.1.0",
|
||||
"shlex",
|
||||
"syn 2.0.76",
|
||||
@@ -971,9 +962,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.17.0"
|
||||
version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fd4c6dcc3b0aea2f5c0b4b82c2b15fe39ddbc76041a310848f4706edf76bb31"
|
||||
checksum = "773d90827bc3feecfb67fab12e24de0749aad83c74b9504ecde46237b5cd24e2"
|
||||
dependencies = [
|
||||
"bytemuck_derive",
|
||||
]
|
||||
@@ -1271,7 +1262,7 @@ dependencies = [
|
||||
"humansize",
|
||||
"image 0.25.2",
|
||||
"indexmap 2.4.0",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"md-5",
|
||||
"mime",
|
||||
"mlua",
|
||||
@@ -1293,14 +1284,14 @@ dependencies = [
|
||||
"port_scanner",
|
||||
"rand 0.8.5",
|
||||
"redb",
|
||||
"regex 1.10.6",
|
||||
"regex",
|
||||
"relative-path",
|
||||
"reqwest 0.12.7",
|
||||
"rfd",
|
||||
"rs-snowflake",
|
||||
"runas",
|
||||
"rust-i18n",
|
||||
"rustc_version 0.4.0",
|
||||
"rustc_version 0.4.1",
|
||||
"semver 1.0.23",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -1442,7 +1433,7 @@ version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
|
||||
dependencies = [
|
||||
"lazy_static 1.5.0",
|
||||
"lazy_static",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@@ -1855,7 +1846,7 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c7397f8c48906dd9b5afc75001368c979418e5dff5575998a831eb2319b424e"
|
||||
dependencies = [
|
||||
"lazy_static 1.5.0",
|
||||
"lazy_static",
|
||||
"pathsearch",
|
||||
"rand 0.8.5",
|
||||
"shared_library",
|
||||
@@ -1883,7 +1874,7 @@ dependencies = [
|
||||
"dashmap 5.5.3",
|
||||
"event-listener 5.3.0",
|
||||
"futures",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"lru",
|
||||
"once_cell",
|
||||
"rs-snowflake",
|
||||
@@ -1966,7 +1957,7 @@ dependencies = [
|
||||
"convert_case 0.4.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc_version 0.4.0",
|
||||
"rustc_version 0.4.1",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
@@ -2078,7 +2069,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"core-graphics 0.23.2",
|
||||
"fxhash",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"smithay-client-toolkit",
|
||||
"widestring 1.1.0",
|
||||
"windows 0.56.0",
|
||||
@@ -2167,7 +2158,7 @@ checksum = "4edcacde9351c33139a41e3c97eb2334351a81a2791bebb0b243df837128f602"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"memchr",
|
||||
"rustc_version 0.4.0",
|
||||
"rustc_version 0.4.1",
|
||||
"toml 0.8.19",
|
||||
"vswhom",
|
||||
"winreg 0.52.0",
|
||||
@@ -2221,7 +2212,7 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
|
||||
dependencies = [
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2233,7 +2224,7 @@ dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"env_filter",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2371,7 +2362,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f"
|
||||
dependencies = [
|
||||
"memoffset 0.9.1",
|
||||
"rustc_version 0.4.0",
|
||||
"rustc_version 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2387,9 +2378,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.24"
|
||||
version = "0.2.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550"
|
||||
checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@@ -2733,7 +2724,7 @@ checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"rustversion",
|
||||
"windows 0.48.0",
|
||||
]
|
||||
@@ -2885,9 +2876,9 @@ version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
|
||||
dependencies = [
|
||||
"aho-corasick 1.1.3",
|
||||
"aho-corasick",
|
||||
"bstr",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"regex-automata 0.4.7",
|
||||
"regex-syntax 0.8.4",
|
||||
]
|
||||
@@ -3029,15 +3020,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "handlebars"
|
||||
version = "0.29.1"
|
||||
version = "3.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb04af2006ea09d985fef82b81e0eb25337e51b691c76403332378a53d521edc"
|
||||
checksum = "4498fc115fa7d34de968184e473529abb40eeb6be8bc5f7faba3d08c316cb3e3"
|
||||
dependencies = [
|
||||
"lazy_static 0.2.11",
|
||||
"log 0.3.9",
|
||||
"pest 0.3.3",
|
||||
"quick-error 1.2.3",
|
||||
"regex 0.2.11",
|
||||
"log",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"quick-error",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
@@ -3121,7 +3111,7 @@ version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7"
|
||||
dependencies = [
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"mac",
|
||||
"markup5ever",
|
||||
"proc-macro2",
|
||||
@@ -3499,7 +3489,7 @@ checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"globset",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"memchr",
|
||||
"regex-automata 0.4.7",
|
||||
"same-file",
|
||||
@@ -3549,7 +3539,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f79afb8cbee2ef20f59ccd477a218c12a93943d075b492015ecb1bb81f8ee904"
|
||||
dependencies = [
|
||||
"byteorder-lite",
|
||||
"quick-error 2.0.1",
|
||||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3615,16 +3605,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "interfaces"
|
||||
version = "0.0.8"
|
||||
version = "0.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ec8f50a973916cac3da5057c986db05cd3346f38c78e9bc24f64cc9f6a3978f"
|
||||
checksum = "bb6250a98af259a26fd5a4a6081fccea9ac116e4c3178acf4aeb86d32d2b7715"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.6.0",
|
||||
"cc",
|
||||
"handlebars",
|
||||
"lazy_static 1.5.0",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"nix 0.23.2",
|
||||
"nix 0.26.4",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
]
|
||||
@@ -3683,13 +3673,13 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
|
||||
|
||||
[[package]]
|
||||
name = "iptools"
|
||||
version = "0.2.5"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c416c05ba2a10240e022887617af3128fccdbf69713214da0fc81a5690d00df7"
|
||||
checksum = "9bab2ab6edf9330906c4da149dddc19e850b14c682865d81fb21962bbfc2e0ae"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"once_cell",
|
||||
"regex 1.10.6",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3732,7 +3722,7 @@ dependencies = [
|
||||
"event-listener 2.5.3",
|
||||
"futures-lite 1.13.0",
|
||||
"http 0.2.12",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"mime",
|
||||
"once_cell",
|
||||
"polling 2.8.0",
|
||||
@@ -3824,7 +3814,7 @@ dependencies = [
|
||||
"cesu8",
|
||||
"combine",
|
||||
"jni-sys",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"thiserror",
|
||||
"walkdir",
|
||||
]
|
||||
@@ -3908,12 +3898,6 @@ dependencies = [
|
||||
"selectors",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
@@ -4006,7 +3990,7 @@ dependencies = [
|
||||
"gtk",
|
||||
"gtk-sys",
|
||||
"libappindicator-sys",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4142,15 +4126,6 @@ version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
|
||||
dependencies = [
|
||||
"log 0.4.22",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
@@ -4253,7 +4228,7 @@ version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016"
|
||||
dependencies = [
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"phf 0.10.1",
|
||||
"phf_codegen 0.10.0",
|
||||
"string_cache",
|
||||
@@ -4470,7 +4445,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
@@ -4537,6 +4512,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset 0.7.1",
|
||||
"pin-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4628,7 +4604,7 @@ version = "4.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26a1d03b6305ecefdd9c6c60150179bb8d9f0cd4e64bbcad1e41419e7bf5e414"
|
||||
dependencies = [
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"mac-notification-sys",
|
||||
"serde",
|
||||
"tauri-winrt-notification",
|
||||
@@ -4786,7 +4762,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "nyanpasu-ipc"
|
||||
version = "1.0.5"
|
||||
source = "git+https://github.com/LibNyanpasu/nyanpasu-service.git#ca20b17dcbccf65c92ae7c07dfa9319d8bc697a1"
|
||||
source = "git+https://github.com/LibNyanpasu/nyanpasu-service.git#2953e6e31663a9f742efbfd20d8c6f3f9c7641b5"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -5106,7 +5082,7 @@ version = "3.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092"
|
||||
dependencies = [
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"serde",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
@@ -5346,12 +5322,6 @@ version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.7.11"
|
||||
@@ -5363,6 +5333,40 @@ dependencies = [
|
||||
"ucd-trie",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_derive"
|
||||
version = "2.7.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_generator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.7.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.7.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"pest",
|
||||
"sha2 0.10.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "petgraph"
|
||||
version = "0.6.5"
|
||||
@@ -5603,7 +5607,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"libc",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
@@ -5618,7 +5622,7 @@ dependencies = [
|
||||
"concurrent-queue",
|
||||
"hermit-abi 0.4.0",
|
||||
"pin-project-lite",
|
||||
"rustix 0.38.34",
|
||||
"rustix 0.38.35",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
@@ -5758,12 +5762,6 @@ dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "2.0.1"
|
||||
@@ -5961,7 +5959,7 @@ dependencies = [
|
||||
"itertools 0.12.1",
|
||||
"libc",
|
||||
"libfuzzer-sys",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"maybe-rayon",
|
||||
"new_debug_unreachable",
|
||||
"noop_proc_macro",
|
||||
@@ -5988,7 +5986,7 @@ dependencies = [
|
||||
"avif-serialize",
|
||||
"imgref",
|
||||
"loop9",
|
||||
"quick-error 2.0.1",
|
||||
"quick-error",
|
||||
"rav1e",
|
||||
"rgb",
|
||||
]
|
||||
@@ -6089,26 +6087,13 @@ dependencies = [
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
|
||||
dependencies = [
|
||||
"aho-corasick 0.6.10",
|
||||
"memchr",
|
||||
"regex-syntax 0.5.6",
|
||||
"thread_local 0.3.6",
|
||||
"utf8-ranges",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
|
||||
dependencies = [
|
||||
"aho-corasick 1.1.3",
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata 0.4.7",
|
||||
"regex-syntax 0.8.4",
|
||||
@@ -6129,20 +6114,11 @@ version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
||||
dependencies = [
|
||||
"aho-corasick 1.1.3",
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax 0.8.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
|
||||
dependencies = [
|
||||
"ucd-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.29"
|
||||
@@ -6189,7 +6165,7 @@ dependencies = [
|
||||
"hyper-tls 0.5.0",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"mime",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
@@ -6234,7 +6210,7 @@ dependencies = [
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"mime",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
@@ -6275,8 +6251,8 @@ dependencies = [
|
||||
"gobject-sys",
|
||||
"gtk-sys",
|
||||
"js-sys",
|
||||
"lazy_static 1.5.0",
|
||||
"log 0.4.22",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"objc",
|
||||
"objc-foundation",
|
||||
"objc_id",
|
||||
@@ -6320,8 +6296,7 @@ checksum = "e60ef3b82994702bbe4e134d98aadca4b49ed04440148985678d415c68127666"
|
||||
[[package]]
|
||||
name = "runas"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b96d6b6c505282b007a9b009f2aa38b2fd0359b81a0430ceacc60f69ade4c6a0"
|
||||
source = "git+https://github.com/libnyanpasu/rust-runas.git#29bdb2501c05b7d78e63628bedbd4a190b71bad3"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
@@ -6337,7 +6312,7 @@ checksum = "039f57d22229db401af3458ca939300178e99e88b938573cea12b7c2b0f09724"
|
||||
dependencies = [
|
||||
"globwalk",
|
||||
"once_cell",
|
||||
"regex 1.10.6",
|
||||
"regex",
|
||||
"rust-i18n-macro",
|
||||
"rust-i18n-support",
|
||||
"smallvec",
|
||||
@@ -6370,11 +6345,11 @@ dependencies = [
|
||||
"base62",
|
||||
"globwalk",
|
||||
"itertools 0.11.0",
|
||||
"lazy_static 1.5.0",
|
||||
"lazy_static",
|
||||
"normpath",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"regex 1.10.6",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yml",
|
||||
@@ -6412,9 +6387,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||
dependencies = [
|
||||
"semver 1.0.23",
|
||||
]
|
||||
@@ -6435,9 +6410,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.34"
|
||||
version = "0.38.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
|
||||
checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"errno",
|
||||
@@ -6487,9 +6462,9 @@ checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.102.6"
|
||||
version = "0.102.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e"
|
||||
checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"rustls-pki-types",
|
||||
@@ -6577,7 +6552,7 @@ dependencies = [
|
||||
"cssparser",
|
||||
"derive_more",
|
||||
"fxhash",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"matches",
|
||||
"phf 0.8.0",
|
||||
"phf_codegen 0.8.0",
|
||||
@@ -6626,7 +6601,7 @@ version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
|
||||
dependencies = [
|
||||
"pest 2.7.11",
|
||||
"pest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6772,7 +6747,7 @@ dependencies = [
|
||||
"indexmap 2.4.0",
|
||||
"itoa 1.0.11",
|
||||
"libyml",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
@@ -6853,7 +6828,7 @@ version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||
dependencies = [
|
||||
"lazy_static 1.5.0",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6872,7 +6847,7 @@ version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11"
|
||||
dependencies = [
|
||||
"lazy_static 1.5.0",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@@ -7004,9 +6979,9 @@ dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"cursor-icon",
|
||||
"libc",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"memmap2",
|
||||
"rustix 0.38.34",
|
||||
"rustix 0.38.35",
|
||||
"thiserror",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
@@ -7248,13 +7223,13 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sysproxy"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/LibNyanpasu/sysproxy-rs.git#33b63f2a7550924cb6a7bc41b02a2738acca65db"
|
||||
source = "git+https://github.com/LibNyanpasu/sysproxy-rs.git#45fffb0cdddb7c2d0ce30300dd72a934bb458c09"
|
||||
dependencies = [
|
||||
"interfaces",
|
||||
"iptools",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"thiserror",
|
||||
"windows 0.52.0",
|
||||
"windows 0.58.0",
|
||||
"winreg 0.52.0",
|
||||
"xdg",
|
||||
]
|
||||
@@ -7354,10 +7329,10 @@ dependencies = [
|
||||
"image 0.24.9",
|
||||
"instant",
|
||||
"jni",
|
||||
"lazy_static 1.5.0",
|
||||
"lazy_static",
|
||||
"libappindicator",
|
||||
"libc",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"ndk",
|
||||
"ndk-context",
|
||||
"ndk-sys",
|
||||
@@ -7447,7 +7422,7 @@ dependencies = [
|
||||
"png",
|
||||
"rand 0.8.5",
|
||||
"raw-window-handle 0.5.2",
|
||||
"regex 1.10.6",
|
||||
"regex",
|
||||
"reqwest 0.11.27",
|
||||
"rfd",
|
||||
"semver 1.0.23",
|
||||
@@ -7508,7 +7483,7 @@ dependencies = [
|
||||
"png",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex 1.10.6",
|
||||
"regex",
|
||||
"semver 1.0.23",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -7540,7 +7515,7 @@ version = "0.1.2"
|
||||
dependencies = [
|
||||
"dirs 5.0.1",
|
||||
"interprocess",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"objc2",
|
||||
"once_cell",
|
||||
"tauri-utils",
|
||||
@@ -7606,7 +7581,7 @@ dependencies = [
|
||||
"infer",
|
||||
"json-patch",
|
||||
"kuchikiki",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"memchr",
|
||||
"phf 0.11.2",
|
||||
"proc-macro2",
|
||||
@@ -7651,7 +7626,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand 2.1.1",
|
||||
"once_cell",
|
||||
"rustix 0.38.34",
|
||||
"rustix 0.38.35",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@@ -7700,14 +7675,14 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"filedescriptor",
|
||||
"hex",
|
||||
"lazy_static 1.5.0",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"memmem",
|
||||
"num-derive 0.3.3",
|
||||
"num-traits",
|
||||
"ordered-float",
|
||||
"regex 1.10.6",
|
||||
"regex",
|
||||
"semver 0.11.0",
|
||||
"sha2 0.9.9",
|
||||
"signal-hook",
|
||||
@@ -7795,15 +7770,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
||||
dependencies = [
|
||||
"lazy_static 1.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.8"
|
||||
@@ -7951,7 +7917,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"tokio",
|
||||
"tungstenite",
|
||||
]
|
||||
@@ -8071,7 +8037,7 @@ version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
||||
dependencies = [
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
@@ -8137,7 +8103,7 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||
dependencies = [
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"once_cell",
|
||||
"tracing-core",
|
||||
]
|
||||
@@ -8162,12 +8128,12 @@ dependencies = [
|
||||
"nu-ansi-term",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"regex 1.10.6",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local 1.1.8",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
@@ -8216,7 +8182,7 @@ dependencies = [
|
||||
"data-encoding",
|
||||
"http 1.1.0",
|
||||
"httparse",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"rand 0.8.5",
|
||||
"sha1",
|
||||
"thiserror",
|
||||
@@ -8242,12 +8208,6 @@ version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-util"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abd2fc5d32b590614af8b0a20d837f32eca055edd0bbead59a9cfe80858be003"
|
||||
|
||||
[[package]]
|
||||
name = "uds_windows"
|
||||
version = "1.1.0"
|
||||
@@ -8340,12 +8300,6 @@ version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba"
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
@@ -8531,7 +8485,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -8601,7 +8555,7 @@ checksum = "f90e11ce2ca99c97b940ee83edbae9da2d56a08f9ea8158550fd77fa31722993"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"downcast-rs",
|
||||
"rustix 0.38.34",
|
||||
"rustix 0.38.35",
|
||||
"scoped-tls",
|
||||
"smallvec",
|
||||
"wayland-sys",
|
||||
@@ -8614,7 +8568,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e321577a0a165911bdcfb39cf029302479d7527b517ee58ab0f6ad09edf0943"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"rustix 0.38.34",
|
||||
"rustix 0.38.35",
|
||||
"wayland-backend",
|
||||
"wayland-scanner",
|
||||
]
|
||||
@@ -8636,7 +8590,7 @@ version = "0.31.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ef9489a8df197ebf3a8ce8a7a7f0a2320035c3743f3c1bd0bdbccf07ce64f95"
|
||||
dependencies = [
|
||||
"rustix 0.38.34",
|
||||
"rustix 0.38.35",
|
||||
"wayland-client",
|
||||
"xcursor",
|
||||
]
|
||||
@@ -8684,7 +8638,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43676fe2daf68754ecf1d72026e4e6c15483198b5d24e888b74d3f22f887a148"
|
||||
dependencies = [
|
||||
"dlib",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
@@ -8791,7 +8745,7 @@ version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aac48ef20ddf657755fdcda8dfed2a7b4fc7e4581acce6fe9b88c3d64f29dee7"
|
||||
dependencies = [
|
||||
"regex 1.10.6",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
@@ -8815,7 +8769,7 @@ dependencies = [
|
||||
"either",
|
||||
"home",
|
||||
"once_cell",
|
||||
"rustix 0.38.34",
|
||||
"rustix 0.38.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8826,7 +8780,7 @@ checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f"
|
||||
dependencies = [
|
||||
"either",
|
||||
"home",
|
||||
"rustix 0.38.34",
|
||||
"rustix 0.38.35",
|
||||
"winsafe",
|
||||
]
|
||||
|
||||
@@ -9503,7 +9457,7 @@ checksum = "12b41773911497b18ca8553c3daaf8ec9fe9819caf93d451d3055f69de028adb"
|
||||
dependencies = [
|
||||
"derive-new",
|
||||
"libc",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"nix 0.28.0",
|
||||
"os_pipe",
|
||||
"tempfile",
|
||||
@@ -9547,7 +9501,7 @@ dependencies = [
|
||||
"http 0.2.12",
|
||||
"kuchikiki",
|
||||
"libc",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"objc",
|
||||
"objc_id",
|
||||
"once_cell",
|
||||
@@ -9593,7 +9547,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12"
|
||||
dependencies = [
|
||||
"gethostname",
|
||||
"rustix 0.38.34",
|
||||
"rustix 0.38.35",
|
||||
"x11rb-protocol",
|
||||
]
|
||||
|
||||
@@ -9611,7 +9565,7 @@ checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.14",
|
||||
"rustix 0.38.34",
|
||||
"rustix 0.38.35",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9881,7 +9835,7 @@ dependencies = [
|
||||
"bumpalo",
|
||||
"crc32fast",
|
||||
"lockfree-object-pool",
|
||||
"log 0.4.22",
|
||||
"log",
|
||||
"once_cell",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
@@ -46,6 +46,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
reqwest = { version = "0.12", features = ["json", "rustls-tls", "stream"] }
|
||||
relative-path = "1.9"
|
||||
tauri = { version = "1.5.4", features = [
|
||||
"dialog-all",
|
||||
"updater",
|
||||
"fs-all",
|
||||
"clipboard-all",
|
||||
@@ -75,7 +76,7 @@ dyn-clone = "1.0.16"
|
||||
rs-snowflake = "0.6"
|
||||
thiserror = { workspace = true }
|
||||
simd-json = "0.13.8"
|
||||
runas = "1.2.0"
|
||||
runas = { git = "https://github.com/libnyanpasu/rust-runas.git" }
|
||||
backon = { version = "1.0.1", features = ["tokio-sleep"] }
|
||||
rust-i18n = "3"
|
||||
adler = "1.0.2"
|
||||
|
Binary file not shown.
@@ -28,3 +28,15 @@ pub static BUILD_INFO: Lazy<BuildInfo> = Lazy::new(|| BuildInfo {
|
||||
rustc_version: env!("RUSTC_VERSION"),
|
||||
llvm_version: env!("LLVM_VERSION"),
|
||||
});
|
||||
|
||||
pub static IS_APPIMAGE: Lazy<bool> = Lazy::new(|| std::env::var("APPIMAGE").is_ok());
|
||||
|
||||
pub static IS_PORTABLE: Lazy<bool> = Lazy::new(|| {
|
||||
if cfg!(windows) {
|
||||
let dir = crate::utils::dirs::app_install_dir().unwrap();
|
||||
let portable_file = dir.join(".config/PORTABLE");
|
||||
portable_file.exists()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
@@ -449,6 +449,11 @@ pub fn open_that(path: String) -> CmdResult {
|
||||
wrap_err!(crate::utils::open::that(path))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn is_appimage() -> CmdResult<bool> {
|
||||
Ok(*crate::consts::IS_APPIMAGE)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[tauri::command]
|
||||
pub fn get_custom_app_dir() -> CmdResult<Option<String>> {
|
||||
|
@@ -243,6 +243,7 @@ fn main() -> std::io::Result<()> {
|
||||
ipc::url_delay_test,
|
||||
ipc::get_ipsb_asn,
|
||||
ipc::open_that,
|
||||
ipc::is_appimage,
|
||||
]);
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
|
@@ -36,11 +36,6 @@ pub const NYANPASU_CONFIG: &str = "nyanpasu-config.yaml";
|
||||
pub const PROFILE_YAML: &str = "profiles.yaml";
|
||||
pub const STORAGE_DB: &str = "storage.db";
|
||||
|
||||
/// portable flag
|
||||
#[allow(unused)]
|
||||
#[cfg(target_os = "windows")]
|
||||
static PORTABLE_FLAG: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
|
||||
|
||||
pub static APP_VERSION: &str = env!("NYANPASU_VERSION");
|
||||
|
||||
pub fn get_app_version() -> &'static str {
|
||||
@@ -49,27 +44,14 @@ pub fn get_app_version() -> &'static str {
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn get_portable_flag() -> bool {
|
||||
*PORTABLE_FLAG.get().unwrap_or(&false)
|
||||
}
|
||||
|
||||
/// initialize portable flag
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn init_portable_flag() -> Result<()> {
|
||||
let dir = app_install_dir()?;
|
||||
let portable_file = dir.join(".config/PORTABLE");
|
||||
if portable_file.exists() {
|
||||
PORTABLE_FLAG.get_or_init(|| true);
|
||||
return Ok(());
|
||||
}
|
||||
PORTABLE_FLAG.get_or_init(|| false);
|
||||
Ok(())
|
||||
*crate::consts::IS_PORTABLE
|
||||
}
|
||||
|
||||
pub fn app_config_dir() -> Result<PathBuf> {
|
||||
let path: Option<PathBuf> = {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
if *PORTABLE_FLAG.get().unwrap_or(&false) {
|
||||
if get_portable_flag() {
|
||||
let app_dir = app_install_dir()?;
|
||||
Some(app_dir.join(".config").join(PREVIOUS_APP_NAME))
|
||||
} else if let Ok(Some(path)) = super::winreg::get_app_dir() {
|
||||
@@ -99,7 +81,7 @@ pub fn app_data_dir() -> Result<PathBuf> {
|
||||
let path: Option<PathBuf> = {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
if *PORTABLE_FLAG.get().unwrap_or(&false) {
|
||||
if get_portable_flag() {
|
||||
let app_dir = app_install_dir()?;
|
||||
Some(app_dir.join(".data").join(PREVIOUS_APP_NAME))
|
||||
} else {
|
||||
@@ -126,7 +108,7 @@ pub fn app_data_dir() -> Result<PathBuf> {
|
||||
pub fn old_app_home_dir() -> Result<PathBuf> {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
if !PORTABLE_FLAG.get().unwrap_or(&false) {
|
||||
if !get_portable_flag() {
|
||||
Ok(home_dir()
|
||||
.ok_or(anyhow::anyhow!("failed to check old app home dir"))?
|
||||
.join(".config")
|
||||
@@ -160,7 +142,7 @@ pub fn app_home_dir() -> Result<PathBuf> {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
use crate::utils::winreg::get_app_dir;
|
||||
if !PORTABLE_FLAG.get().unwrap_or(&false) {
|
||||
if !get_portable_flag() {
|
||||
let reg_app_dir = get_app_dir()?;
|
||||
if let Some(reg_app_dir) = reg_app_dir {
|
||||
return Ok(reg_app_dir);
|
||||
|
@@ -103,9 +103,6 @@ pub fn run_pending_migrations() -> Result<()> {
|
||||
/// Initialize all the config files
|
||||
/// before tauri setup
|
||||
pub fn init_config() -> Result<()> {
|
||||
#[cfg(target_os = "windows")]
|
||||
let _ = dirs::init_portable_flag();
|
||||
|
||||
// Check if old config dir exist and new config dir is not exist
|
||||
let mut old_app_dir: Option<PathBuf> = None;
|
||||
let mut app_dir: Option<PathBuf> = None;
|
||||
|
@@ -212,108 +212,105 @@ pub fn create_window(app_handle: &AppHandle) {
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
use tauri::{PhysicalPosition, PhysicalSize};
|
||||
use window_shadows::set_shadow;
|
||||
#[cfg(windows)]
|
||||
let win_res = builder
|
||||
.decorations(false)
|
||||
.transparent(true)
|
||||
.visible(false)
|
||||
.build();
|
||||
#[cfg(target_os = "macos")]
|
||||
let win_res = builder
|
||||
.decorations(true)
|
||||
.hidden_title(true)
|
||||
.title_bar_style(tauri::TitleBarStyle::Overlay)
|
||||
.build();
|
||||
#[cfg(target_os = "linux")]
|
||||
let win_res = builder.decorations(true).transparent(true).build();
|
||||
|
||||
match builder
|
||||
.decorations(false)
|
||||
.transparent(true)
|
||||
.visible(false)
|
||||
.build()
|
||||
{
|
||||
Ok(win) => {
|
||||
if win_state.is_some() {
|
||||
let state = win_state.as_ref().unwrap();
|
||||
win.set_position(PhysicalPosition {
|
||||
x: state.x,
|
||||
y: state.y,
|
||||
})
|
||||
.unwrap();
|
||||
win.set_size(PhysicalSize {
|
||||
width: state.width,
|
||||
height: state.height,
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if let Some(state) = win_state {
|
||||
if state.maximized {
|
||||
trace_err!(win.maximize(), "set win maximize");
|
||||
}
|
||||
if state.fullscreen {
|
||||
trace_err!(win.set_fullscreen(true), "set win fullscreen");
|
||||
}
|
||||
}
|
||||
trace_err!(set_shadow(&win, true), "set win shadow");
|
||||
log::trace!("try to calculate the monitor size");
|
||||
let center = (|| -> Result<bool> {
|
||||
let center;
|
||||
if let Some(state) = win_state {
|
||||
let monitor = win.current_monitor()?.ok_or(anyhow::anyhow!(""))?;
|
||||
let PhysicalPosition { x, y } = *monitor.position();
|
||||
let PhysicalSize { width, height } = *monitor.size();
|
||||
let left = x;
|
||||
let right = x + width as i32;
|
||||
let top = y;
|
||||
let bottom = y + height as i32;
|
||||
|
||||
let x = state.x;
|
||||
let y = state.y;
|
||||
let width = state.width as i32;
|
||||
let height = state.height as i32;
|
||||
center = ![
|
||||
(x, y),
|
||||
(x + width, y),
|
||||
(x, y + height),
|
||||
(x + width, y + height),
|
||||
]
|
||||
.into_iter()
|
||||
.any(|(x, y)| x >= left && x < right && y >= top && y < bottom);
|
||||
} else {
|
||||
center = true;
|
||||
}
|
||||
Ok(center)
|
||||
})();
|
||||
|
||||
if center.unwrap_or(true) {
|
||||
trace_err!(win.center(), "set win center");
|
||||
}
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
win.open_devtools();
|
||||
}
|
||||
OPEN_WINDOWS_COUNTER.fetch_add(1, Ordering::Release);
|
||||
#[cfg(target_os = "macos")]
|
||||
fn set_controls_and_log_error(app_handle: &tauri::AppHandle, window_name: &str) {
|
||||
match app_handle.get_window(window_name).unwrap().ns_window() {
|
||||
Ok(raw_window) => {
|
||||
let window_id: cocoa::base::id = raw_window as _;
|
||||
set_window_controls_pos(window_id, 26.0, 26.0);
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!(target: "app", "failed to get ns_window, {err}");
|
||||
}
|
||||
Err(err) => log::error!(target: "app", "failed to create window, {err}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
fn set_controls_and_log_error(app_handle: &tauri::AppHandle, window_name: &str) {
|
||||
match app_handle.get_window(window_name).unwrap().ns_window() {
|
||||
Ok(raw_window) => {
|
||||
let window_id: cocoa::base::id = raw_window as _;
|
||||
set_window_controls_pos(window_id, 33.0, 26.0);
|
||||
match win_res {
|
||||
Ok(win) => {
|
||||
use tauri::{PhysicalPosition, PhysicalSize};
|
||||
#[cfg(windows)]
|
||||
use window_shadows::set_shadow;
|
||||
|
||||
if win_state.is_some() {
|
||||
let state = win_state.as_ref().unwrap();
|
||||
win.set_position(PhysicalPosition {
|
||||
x: state.x,
|
||||
y: state.y,
|
||||
})
|
||||
.unwrap();
|
||||
win.set_size(PhysicalSize {
|
||||
width: state.width,
|
||||
height: state.height,
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if let Some(state) = win_state {
|
||||
if state.maximized {
|
||||
trace_err!(win.maximize(), "set win maximize");
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!(target: "app", "failed to get ns_window, {err}");
|
||||
if state.fullscreen {
|
||||
trace_err!(win.set_fullscreen(true), "set win fullscreen");
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
trace_err!(set_shadow(&win, true), "set win shadow");
|
||||
log::trace!("try to calculate the monitor size");
|
||||
let center = (|| -> Result<bool> {
|
||||
let center;
|
||||
if let Some(state) = win_state {
|
||||
let monitor = win.current_monitor()?.ok_or(anyhow::anyhow!(""))?;
|
||||
let PhysicalPosition { x, y } = *monitor.position();
|
||||
let PhysicalSize { width, height } = *monitor.size();
|
||||
let left = x;
|
||||
let right = x + width as i32;
|
||||
let top = y;
|
||||
let bottom = y + height as i32;
|
||||
|
||||
match builder
|
||||
.decorations(true)
|
||||
.hidden_title(true)
|
||||
.title_bar_style(tauri::TitleBarStyle::Overlay)
|
||||
.build()
|
||||
{
|
||||
Ok(win) => {
|
||||
#[cfg(debug_assertions)]
|
||||
let x = state.x;
|
||||
let y = state.y;
|
||||
let width = state.width as i32;
|
||||
let height = state.height as i32;
|
||||
center = ![
|
||||
(x, y),
|
||||
(x + width, y),
|
||||
(x, y + height),
|
||||
(x + width, y + height),
|
||||
]
|
||||
.into_iter()
|
||||
.any(|(x, y)| x >= left && x < right && y >= top && y < bottom);
|
||||
} else {
|
||||
center = true;
|
||||
}
|
||||
Ok(center)
|
||||
})();
|
||||
|
||||
if center.unwrap_or(true) {
|
||||
trace_err!(win.center(), "set win center");
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
win.open_devtools();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
set_controls_and_log_error(&app_handle, "main");
|
||||
|
||||
let app_handle_clone = app_handle.clone();
|
||||
@@ -322,17 +319,8 @@ pub fn create_window(app_handle: &AppHandle) {
|
||||
set_controls_and_log_error(&app_handle_clone, "main");
|
||||
}
|
||||
});
|
||||
OPEN_WINDOWS_COUNTER.fetch_add(1, Ordering::Release);
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!(target: "app", "failed to create window, {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
match builder.decorations(true).transparent(false).build() {
|
||||
Ok(_) => {
|
||||
OPEN_WINDOWS_COUNTER.fetch_add(1, Ordering::Release);
|
||||
}
|
||||
Err(err) => {
|
||||
|
@@ -105,6 +105,9 @@
|
||||
},
|
||||
"fs": {
|
||||
"all": true
|
||||
},
|
||||
"dialog": {
|
||||
"all": true
|
||||
}
|
||||
},
|
||||
"windows": [],
|
||||
|
@@ -20,8 +20,13 @@ export const VALID_CORE: Core[] = [
|
||||
export const fetchCoreVersion = async () => {
|
||||
return await Promise.all(
|
||||
VALID_CORE.map(async (item) => {
|
||||
const version = await getCoreVersion(item.core);
|
||||
return { ...item, version };
|
||||
try {
|
||||
const version = await getCoreVersion(item.core);
|
||||
return { ...item, version };
|
||||
} catch (e) {
|
||||
console.error("failed to fetch core version", e);
|
||||
return { ...item, version: "N/A" };
|
||||
}
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
@@ -251,3 +251,7 @@ export const getIpsbASN = async () => invoke<IPSBResponse>("get_ipsb_asn");
|
||||
export const openThat = async (path: string) => {
|
||||
return await invoke<void>("open_that", { path });
|
||||
};
|
||||
|
||||
export const isAppImage = async () => {
|
||||
return await invoke<boolean>("is_appimage");
|
||||
};
|
||||
|
@@ -43,13 +43,13 @@
|
||||
"react-split-grid": "1.0.4",
|
||||
"react-use": "17.5.1",
|
||||
"swr": "2.2.5",
|
||||
"virtua": "0.33.7"
|
||||
"virtua": "0.34.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@csstools/normalize.css": "12.1.1",
|
||||
"@emotion/babel-plugin": "11.12.0",
|
||||
"@emotion/react": "11.13.3",
|
||||
"@iconify/json": "2.2.241",
|
||||
"@iconify/json": "2.2.242",
|
||||
"@types/react": "18.3.4",
|
||||
"@types/react-dom": "18.3.0",
|
||||
"@vitejs/plugin-react": "4.3.1",
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 57 KiB |
@@ -1,4 +1,3 @@
|
||||
@import "./layout.scss";
|
||||
@import "./fonts.scss";
|
||||
|
||||
body {
|
||||
|
@@ -1,9 +0,0 @@
|
||||
.the-content {
|
||||
position: absolute;
|
||||
inset: 36px calc(var(--border-radius) * 2) calc(var(--border-radius) * 2) 0;
|
||||
}
|
||||
|
||||
.the-content-small {
|
||||
position: absolute;
|
||||
inset: 36px calc(var(--border-radius) * 2) calc(var(--border-radius) * 2);
|
||||
}
|
@@ -51,12 +51,12 @@ export const AppContainer = ({
|
||||
|
||||
<Allotment.Pane visible={true} className={styles.container}>
|
||||
{OS === "windows" && (
|
||||
<LayoutControl className="!z-top fixed right-6 top-1.5" />
|
||||
<LayoutControl className="!z-top fixed right-4 top-2" />
|
||||
)}
|
||||
|
||||
{OS === "macos" && (
|
||||
<div
|
||||
className="z-top fixed left-6 top-3 h-8 w-[4.5rem] rounded-full"
|
||||
className="z-top fixed left-4 top-3 h-8 w-[4.5rem] rounded-full"
|
||||
style={{ backgroundColor: alpha(palette.primary.main, 0.1) }}
|
||||
/>
|
||||
)}
|
||||
|
@@ -17,7 +17,7 @@ export const AppDrawer = () => {
|
||||
<div
|
||||
className={classNames(
|
||||
"fixed z-10 flex items-center gap-2",
|
||||
getSystem() === "macos" ? "left-[6.5rem] top-3" : "left-6 top-1.5",
|
||||
getSystem() === "macos" ? "left-24 top-3" : "left-6 top-1.5",
|
||||
)}
|
||||
data-windrag
|
||||
>
|
||||
|
@@ -1,6 +1,8 @@
|
||||
import { useSize } from "ahooks";
|
||||
import clsx from "clsx";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useAtom } from "jotai";
|
||||
import { useCallback, useEffect, useRef } from "react";
|
||||
import { atomIsDrawerOnlyIcon } from "@/store";
|
||||
import getSystem from "@/utils/get-system";
|
||||
import { languageQuirks } from "@/utils/language";
|
||||
import { getRoutesWithIcon } from "@/utils/routes-utils";
|
||||
@@ -9,7 +11,7 @@ import AnimatedLogo from "../layout/animated-logo";
|
||||
import RouteListItem from "./modules/route-list-item";
|
||||
|
||||
export const DrawerContent = ({ className }: { className?: string }) => {
|
||||
const [onlyIcon, setOnlyIcon] = useState(false);
|
||||
const [onlyIcon, setOnlyIcon] = useAtom(atomIsDrawerOnlyIcon);
|
||||
|
||||
const { nyanpasuConfig } = useNyanpasu();
|
||||
|
||||
@@ -34,7 +36,7 @@ export const DrawerContent = ({ className }: { className?: string }) => {
|
||||
setOnlyIcon(false);
|
||||
}
|
||||
},
|
||||
[nyanpasuConfig?.language],
|
||||
[nyanpasuConfig?.language, setOnlyIcon],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
@@ -6,8 +6,6 @@ import { LogMessage, useClashWS } from "@nyanpasu/interface";
|
||||
|
||||
const MAX_LOG_NUM = 1000;
|
||||
|
||||
const time = dayjs().format("MM-DD HH:mm:ss");
|
||||
|
||||
export const LogProvider = () => {
|
||||
const {
|
||||
logs: { latestMessage },
|
||||
@@ -23,12 +21,11 @@ export const LogProvider = () => {
|
||||
}
|
||||
|
||||
const data = JSON.parse(latestMessage?.data) as LogMessage;
|
||||
|
||||
const time = dayjs(data.time).format("MM-DD HH:mm:ss");
|
||||
setLogData((prev) => {
|
||||
if (prev.length >= MAX_LOG_NUM) {
|
||||
prev.shift();
|
||||
}
|
||||
|
||||
return [...prev, { ...data, time }];
|
||||
});
|
||||
}, [enableLog, latestMessage?.data, setLogData]);
|
||||
|
@@ -238,7 +238,10 @@ export const ProfileDialog = ({
|
||||
) : (
|
||||
!isEdit && (
|
||||
<>
|
||||
<ReadProfile onSelected={handleProfileSelected} />
|
||||
<ReadProfile
|
||||
key="read_profile"
|
||||
onSelected={handleProfileSelected}
|
||||
/>
|
||||
|
||||
{localProfileMessage && (
|
||||
<div className="ml-2 text-red-500">{localProfileMessage}</div>
|
||||
|
@@ -25,7 +25,7 @@ export const ReadProfile = ({ onSelected }: ReadProfileProps) => {
|
||||
filters: [
|
||||
{
|
||||
name: "profile",
|
||||
extensions: ["yaml"],
|
||||
extensions: ["yaml", "yml"],
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -42,6 +42,8 @@ export const ReadProfile = ({ onSelected }: ReadProfileProps) => {
|
||||
} else {
|
||||
setLabel(selected.split("/").at(-1) as string);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -51,6 +53,7 @@ export const ReadProfile = ({ onSelected }: ReadProfileProps) => {
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
loading={loading}
|
||||
disabled={loading}
|
||||
onClick={handleSelectFile}
|
||||
color={label ? "success" : "primary"}
|
||||
>
|
||||
|
@@ -2,6 +2,7 @@ import { useLockFn, useReactive } from "ahooks";
|
||||
import { motion } from "framer-motion";
|
||||
import { useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { OS } from "@/consts";
|
||||
import { formatError } from "@/utils";
|
||||
import { message } from "@/utils/notification";
|
||||
import { Box, List, ListItem } from "@mui/material";
|
||||
@@ -17,7 +18,6 @@ export const SettingClashCore = () => {
|
||||
});
|
||||
|
||||
const [expand, setExpand] = useState(false);
|
||||
|
||||
const {
|
||||
nyanpasuConfig,
|
||||
setClashCore,
|
||||
@@ -122,12 +122,12 @@ export const SettingClashCore = () => {
|
||||
labelChildren={<span>{version}</span>}
|
||||
>
|
||||
<List disablePadding>
|
||||
{mergeCores?.map((item, index) => {
|
||||
{mergeCores?.map((item) => {
|
||||
const show = expand || item.core == nyanpasuConfig?.clash_core;
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
key={index}
|
||||
key={item.name}
|
||||
animate={show ? "open" : "closed"}
|
||||
variants={{
|
||||
open: {
|
||||
@@ -169,13 +169,16 @@ export const SettingClashCore = () => {
|
||||
{t("Restart")}
|
||||
</LoadingButton>
|
||||
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
loading={getLatestCore.isLoading}
|
||||
onClick={handleCheckUpdates}
|
||||
>
|
||||
{t("Check Updates")}
|
||||
</LoadingButton>
|
||||
{/** TODO: Support Linux when Manifest v2 released */}
|
||||
{OS !== "linux" && (
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
loading={getLatestCore.isLoading}
|
||||
onClick={handleCheckUpdates}
|
||||
>
|
||||
{t("Check Updates")}
|
||||
</LoadingButton>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<ExpandMore expand={expand} onClick={() => setExpand(!expand)} />
|
||||
|
@@ -4,6 +4,7 @@ import { useSetAtom } from "jotai";
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import LogoSvg from "@/assets/image/logo.svg?react";
|
||||
import { useUpdaterPlatformSupported } from "@/hooks/use-updater";
|
||||
import { UpdaterManifestAtom } from "@/store/updater";
|
||||
import { formatError } from "@/utils";
|
||||
import { message } from "@/utils/notification";
|
||||
@@ -47,8 +48,8 @@ export const SettingNyanpasuVersion = () => {
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const { nyanpasuConfig, setNyanpasuConfig } = useNyanpasu();
|
||||
const setUpdaterManifest = useSetAtom(UpdaterManifestAtom);
|
||||
const isPlatformSupported = useUpdaterPlatformSupported();
|
||||
const onCheckUpdate = useLockFn(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
@@ -109,21 +110,24 @@ export const SettingNyanpasuVersion = () => {
|
||||
</Paper>
|
||||
</ListItem>
|
||||
|
||||
<div className="mb-1 mt-1">
|
||||
<AutoCheckUpdate />
|
||||
</div>
|
||||
|
||||
<ListItem sx={{ pl: 0, pr: 0 }}>
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
size="large"
|
||||
loading={loading}
|
||||
onClick={onCheckUpdate}
|
||||
sx={{ width: "100%" }}
|
||||
>
|
||||
{t("Check for Updates")}
|
||||
</LoadingButton>
|
||||
</ListItem>
|
||||
{isPlatformSupported && (
|
||||
<>
|
||||
<div className="mb-1 mt-1">
|
||||
<AutoCheckUpdate />
|
||||
</div>
|
||||
<ListItem sx={{ pl: 0, pr: 0 }}>
|
||||
<LoadingButton
|
||||
variant="contained"
|
||||
size="large"
|
||||
loading={loading}
|
||||
onClick={onCheckUpdate}
|
||||
sx={{ width: "100%" }}
|
||||
>
|
||||
{t("Check for Updates")}
|
||||
</LoadingButton>
|
||||
</ListItem>
|
||||
</>
|
||||
)}
|
||||
</List>
|
||||
</BaseCard>
|
||||
);
|
||||
|
@@ -1,3 +1,7 @@
|
||||
import { useAtomValue } from "jotai";
|
||||
import { useWindowSize } from "react-use";
|
||||
import { useIsAppImage } from "@/hooks/use-consts";
|
||||
import { atomIsDrawerOnlyIcon } from "@/store";
|
||||
import Masonry from "@mui/lab/Masonry";
|
||||
import SettingClashBase from "./setting-clash-base";
|
||||
import SettingClashCore from "./setting-clash-core";
|
||||
@@ -15,10 +19,22 @@ import SettingSystemProxy from "./setting-system-proxy";
|
||||
import SettingSystemService from "./setting-system-service";
|
||||
|
||||
export const SettingPage = () => {
|
||||
const isAppImage = useIsAppImage();
|
||||
|
||||
const isDrawerOnlyIcon = useAtomValue(atomIsDrawerOnlyIcon);
|
||||
|
||||
const { width } = useWindowSize();
|
||||
|
||||
return (
|
||||
<Masonry
|
||||
className="w-full"
|
||||
columns={{ xs: 1, sm: 1, md: 2 }}
|
||||
columns={{
|
||||
xs: 1,
|
||||
sm: 1,
|
||||
md: isDrawerOnlyIcon ? 2 : width > 1000 ? 2 : 1,
|
||||
lg: 2,
|
||||
xl: 2,
|
||||
}}
|
||||
spacing={3}
|
||||
sequential
|
||||
sx={{ width: "calc(100% + 24px)" }}
|
||||
@@ -41,7 +57,7 @@ export const SettingPage = () => {
|
||||
|
||||
<SettingSystemBehavior />
|
||||
|
||||
<SettingSystemService />
|
||||
{!isAppImage.data && <SettingSystemService />}
|
||||
|
||||
<SettingNyanpasuTasks />
|
||||
|
||||
|
@@ -6,6 +6,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { UpdaterIgnoredAtom } from "@/store/updater";
|
||||
import { formatError } from "@/utils";
|
||||
import { message } from "@/utils/notification";
|
||||
import { Button } from "@mui/material";
|
||||
import { BaseDialog, BaseDialogProps, cn } from "@nyanpasu/ui";
|
||||
import { relaunch } from "@tauri-apps/api/process";
|
||||
import { open as openThat } from "@tauri-apps/api/shell";
|
||||
@@ -61,11 +62,26 @@ export default function UpdaterDialog({
|
||||
styles.UpdaterDialog,
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-3 px-2 py-2">
|
||||
<span className="text-xl font-bold">{manifest.version}</span>
|
||||
<span className="text-xs text-slate-500">
|
||||
{dayjs(manifest.date).format("YYYY-MM-DD HH:mm:ss")}
|
||||
</span>
|
||||
<div className="flex items-center justify-between px-2 py-2">
|
||||
<div className="flex gap-3">
|
||||
<span className="text-xl font-bold">{manifest.version}</span>
|
||||
<span className="text-xs text-slate-500">
|
||||
{dayjs(manifest.date, "YYYY-MM-DD H:mm:ss Z").format(
|
||||
"YYYY-MM-DD HH:mm:ss",
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
onClick={() => {
|
||||
openThat(
|
||||
`https://github.com/LibNyanpasu/clash-nyanpasu/releases/tag/v${manifest.version}`,
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t("updater.go")}
|
||||
</Button>
|
||||
</div>
|
||||
<div
|
||||
className={cn("h-[50vh] overflow-y-auto p-4", styles.MarkdownContent)}
|
||||
@@ -90,7 +106,7 @@ export default function UpdaterDialog({
|
||||
},
|
||||
}}
|
||||
>
|
||||
{manifest.body}
|
||||
{manifest.body || "New version available."}
|
||||
</Markdown>
|
||||
</Suspense>
|
||||
</div>
|
||||
|
3
clash-nyanpasu/frontend/nyanpasu/src/consts.ts
Normal file
3
clash-nyanpasu/frontend/nyanpasu/src/consts.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { getSystem } from "@nyanpasu/ui";
|
||||
|
||||
export const OS = getSystem();
|
11
clash-nyanpasu/frontend/nyanpasu/src/hooks/use-consts.ts
Normal file
11
clash-nyanpasu/frontend/nyanpasu/src/hooks/use-consts.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import useSWR, { SWRConfiguration } from "swr";
|
||||
import { isAppImage } from "@nyanpasu/interface";
|
||||
|
||||
export const useIsAppImage = (config?: Partial<SWRConfiguration>) => {
|
||||
return useSWR<boolean>("/api/is_appimage", isAppImage, {
|
||||
...(config || {}),
|
||||
revalidateOnFocus: false,
|
||||
revalidateOnReconnect: false,
|
||||
refreshInterval: 0,
|
||||
});
|
||||
};
|
@@ -1,17 +1,37 @@
|
||||
import { useAtomValue, useSetAtom } from "jotai";
|
||||
import { useMount } from "react-use";
|
||||
import { useEffect, useState } from "react";
|
||||
import { OS } from "@/consts";
|
||||
import { UpdaterIgnoredAtom, UpdaterManifestAtom } from "@/store/updater";
|
||||
import { useNyanpasu } from "@nyanpasu/interface";
|
||||
import { checkUpdate } from "@tauri-apps/api/updater";
|
||||
import { useIsAppImage } from "./use-consts";
|
||||
|
||||
export function useUpdaterPlatformSupported() {
|
||||
const [supported, setSupported] = useState(false);
|
||||
const isAppImage = useIsAppImage();
|
||||
useEffect(() => {
|
||||
switch (OS) {
|
||||
case "macos":
|
||||
case "windows":
|
||||
setSupported(true);
|
||||
break;
|
||||
case "linux":
|
||||
setSupported(!!isAppImage.data);
|
||||
break;
|
||||
}
|
||||
}, [isAppImage.data]);
|
||||
return supported;
|
||||
}
|
||||
|
||||
export default function useUpdater() {
|
||||
const { nyanpasuConfig } = useNyanpasu();
|
||||
const updaterIgnored = useAtomValue(UpdaterIgnoredAtom);
|
||||
const setUpdaterManifest = useSetAtom(UpdaterManifestAtom);
|
||||
const isPlatformSupported = useUpdaterPlatformSupported();
|
||||
|
||||
useMount(() => {
|
||||
useEffect(() => {
|
||||
const run = async () => {
|
||||
if (nyanpasuConfig?.enable_auto_check_update) {
|
||||
if (nyanpasuConfig?.enable_auto_check_update && isPlatformSupported) {
|
||||
const info = await checkUpdate();
|
||||
if (info?.shouldUpdate && updaterIgnored !== info.manifest?.version) {
|
||||
setUpdaterManifest(info.manifest || null);
|
||||
@@ -19,5 +39,10 @@ export default function useUpdater() {
|
||||
}
|
||||
};
|
||||
run().catch(console.error);
|
||||
});
|
||||
}, [
|
||||
isPlatformSupported,
|
||||
nyanpasuConfig?.enable_auto_check_update,
|
||||
setUpdaterManifest,
|
||||
updaterIgnored,
|
||||
]);
|
||||
}
|
||||
|
@@ -175,6 +175,7 @@
|
||||
"updater": {
|
||||
"title": "New version available",
|
||||
"close": "Ignore",
|
||||
"update": "Update Now"
|
||||
"update": "Update Now",
|
||||
"go": "View on GitHub"
|
||||
}
|
||||
}
|
||||
|
@@ -158,6 +158,7 @@
|
||||
"updater": {
|
||||
"title": "Доступно обновление",
|
||||
"close": "Закрыть",
|
||||
"update": "Обновить"
|
||||
"update": "Обновить",
|
||||
"go": "Посмотреть на GitHub"
|
||||
}
|
||||
}
|
||||
|
@@ -177,6 +177,7 @@
|
||||
"updater": {
|
||||
"title": "发现新版本",
|
||||
"close": "忽略",
|
||||
"update": "立即更新"
|
||||
"update": "立即更新",
|
||||
"go": "查看发布页"
|
||||
}
|
||||
}
|
||||
|
@@ -17,10 +17,11 @@ import { atomIsDrawer } from "@/store";
|
||||
import { classNames } from "@/utils";
|
||||
import { useTheme } from "@mui/material";
|
||||
import { Experimental_CssVarsProvider as CssVarsProvider } from "@mui/material/styles";
|
||||
import { useBreakpoint } from "@nyanpasu/ui";
|
||||
import { cn, useBreakpoint } from "@nyanpasu/ui";
|
||||
import { emit } from "@tauri-apps/api/event";
|
||||
import "dayjs/locale/ru";
|
||||
import "dayjs/locale/zh-cn";
|
||||
import customParseFormat from "dayjs/plugin/customParseFormat";
|
||||
import relativeTime from "dayjs/plugin/relativeTime";
|
||||
import { useAtom } from "jotai";
|
||||
import { useEffect } from "react";
|
||||
@@ -29,6 +30,7 @@ import { SWRConfig } from "swr";
|
||||
import styles from "./_app.module.scss";
|
||||
|
||||
dayjs.extend(relativeTime);
|
||||
dayjs.extend(customParseFormat);
|
||||
|
||||
export default function App() {
|
||||
const { theme } = useCustomTheme();
|
||||
@@ -73,7 +75,7 @@ export default function App() {
|
||||
|
||||
<AppContainer isDrawer={isDrawer}>
|
||||
<PageTransition
|
||||
className={isDrawer ? "the-content-small" : "the-content"}
|
||||
className={cn("absolute inset-4 top-10", !isDrawer && "left-0")}
|
||||
/>
|
||||
</AppContainer>
|
||||
</CssVarsProvider>
|
||||
|
@@ -136,6 +136,7 @@ export default function ProxyPage() {
|
||||
className={cn(
|
||||
"absolute z-10 flex w-full items-center justify-between px-4 py-2 backdrop-blur",
|
||||
"bg-gray-200/30 dark:bg-gray-900/30",
|
||||
"!rounded-t-2xl",
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
|
@@ -56,6 +56,8 @@ export const atomEnableLog = atomWithLocalStorage<boolean>(
|
||||
|
||||
export const atomIsDrawer = atom<boolean>();
|
||||
|
||||
export const atomIsDrawerOnlyIcon = atom<boolean>();
|
||||
|
||||
// save the state of each profile item loading
|
||||
export const atomLoadingCache = atom<Record<string, boolean>>({});
|
||||
|
||||
|
@@ -174,7 +174,7 @@ export const BaseDialog = ({
|
||||
<div
|
||||
className={cn(
|
||||
"text-xl",
|
||||
!full ? "m-4" : OS === "macos" ? "ml-20 p-3" : "m-2 ml-6",
|
||||
!full ? "m-4" : OS === "macos" ? "ml-20 p-3.5" : "m-2 ml-6",
|
||||
)}
|
||||
data-windrag={full}
|
||||
>
|
||||
@@ -189,7 +189,9 @@ export const BaseDialog = ({
|
||||
full && "h-full px-6",
|
||||
)}
|
||||
style={{
|
||||
maxHeight: full ? "calc(100vh - 100px)" : "calc(100vh - 200px)",
|
||||
maxHeight: full
|
||||
? `calc(100vh - ${OS === "macos" ? 114 : 100}px)`
|
||||
: "calc(100vh - 200px)",
|
||||
...contentStyle,
|
||||
}}
|
||||
>
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"manifest_version": 1,
|
||||
"latest": {
|
||||
"mihomo": "v1.18.7",
|
||||
"mihomo_alpha": "alpha-3e2c9ce",
|
||||
"mihomo_alpha": "alpha-8483178",
|
||||
"clash_rs": "v0.3.0",
|
||||
"clash_premium": "2023-09-05-gdcc8d87"
|
||||
},
|
||||
@@ -36,5 +36,5 @@
|
||||
"darwin-x64": "clash-darwin-amd64-n{}.gz"
|
||||
}
|
||||
},
|
||||
"updated_at": "2024-08-26T22:20:34.296Z"
|
||||
"updated_at": "2024-08-27T22:20:48.985Z"
|
||||
}
|
||||
|
@@ -61,7 +61,7 @@
|
||||
"@tauri-apps/cli": "1.6.1",
|
||||
"@types/fs-extra": "11.0.4",
|
||||
"@types/lodash-es": "4.17.12",
|
||||
"@types/node": "22.5.0",
|
||||
"@types/node": "22.5.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.2.0",
|
||||
"@typescript-eslint/parser": "8.2.0",
|
||||
"autoprefixer": "10.4.20",
|
||||
|
155
clash-nyanpasu/pnpm-lock.yaml
generated
155
clash-nyanpasu/pnpm-lock.yaml
generated
@@ -24,7 +24,7 @@ importers:
|
||||
devDependencies:
|
||||
'@commitlint/cli':
|
||||
specifier: 19.4.0
|
||||
version: 19.4.0(@types/node@22.5.0)(typescript@5.5.4)
|
||||
version: 19.4.0(@types/node@22.5.1)(typescript@5.5.4)
|
||||
'@commitlint/config-conventional':
|
||||
specifier: 19.2.2
|
||||
version: 19.2.2
|
||||
@@ -41,8 +41,8 @@ importers:
|
||||
specifier: 4.17.12
|
||||
version: 4.17.12
|
||||
'@types/node':
|
||||
specifier: 22.5.0
|
||||
version: 22.5.0
|
||||
specifier: 22.5.1
|
||||
version: 22.5.1
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: 8.2.0
|
||||
version: 8.2.0(@typescript-eslint/parser@8.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4)
|
||||
@@ -99,7 +99,7 @@ importers:
|
||||
version: 4.6.2(eslint@8.57.0)
|
||||
knip:
|
||||
specifier: 5.27.4
|
||||
version: 5.27.4(@types/node@22.5.0)(typescript@5.5.4)
|
||||
version: 5.27.4(@types/node@22.5.1)(typescript@5.5.4)
|
||||
lint-staged:
|
||||
specifier: 15.2.9
|
||||
version: 15.2.9
|
||||
@@ -199,7 +199,7 @@ importers:
|
||||
version: 11.13.0(@emotion/react@11.13.3(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1)
|
||||
'@generouted/react-router':
|
||||
specifier: 1.19.6
|
||||
version: 1.19.6(react-router-dom@6.26.1(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
version: 1.19.6(react-router-dom@6.26.1(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
'@juggle/resize-observer':
|
||||
specifier: 3.4.0
|
||||
version: 3.4.0
|
||||
@@ -288,8 +288,8 @@ importers:
|
||||
specifier: 2.2.5
|
||||
version: 2.2.5(react@19.0.0-rc-e948a5ac-20240807)
|
||||
virtua:
|
||||
specifier: 0.33.7
|
||||
version: 0.33.7(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)
|
||||
specifier: 0.34.0
|
||||
version: 0.34.0(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)
|
||||
devDependencies:
|
||||
'@csstools/normalize.css':
|
||||
specifier: 12.1.1
|
||||
@@ -301,8 +301,8 @@ importers:
|
||||
specifier: 11.13.3
|
||||
version: 11.13.3(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1)
|
||||
'@iconify/json':
|
||||
specifier: 2.2.241
|
||||
version: 2.2.241
|
||||
specifier: 2.2.242
|
||||
version: 2.2.242
|
||||
'@types/react':
|
||||
specifier: npm:types-react@rc
|
||||
version: types-react@19.0.0-rc.1
|
||||
@@ -311,10 +311,10 @@ importers:
|
||||
version: types-react-dom@19.0.0-rc.1
|
||||
'@vitejs/plugin-react':
|
||||
specifier: 4.3.1
|
||||
version: 4.3.1(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
version: 4.3.1(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
'@vitejs/plugin-react-swc':
|
||||
specifier: 3.7.0
|
||||
version: 3.7.0(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
version: 3.7.0(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
clsx:
|
||||
specifier: 2.1.1
|
||||
version: 2.1.1
|
||||
@@ -335,19 +335,19 @@ importers:
|
||||
version: 0.19.2(@svgr/core@8.1.0(typescript@5.5.4))
|
||||
vite:
|
||||
specifier: 5.4.2
|
||||
version: 5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
version: 5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite-plugin-monaco-editor:
|
||||
specifier: npm:vite-plugin-monaco-editor-new@1.1.3
|
||||
version: vite-plugin-monaco-editor-new@1.1.3(monaco-editor@0.51.0)
|
||||
vite-plugin-sass-dts:
|
||||
specifier: 1.3.25
|
||||
version: 1.3.25(postcss@8.4.41)(prettier@3.3.3)(sass@1.77.8)(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
version: 1.3.25(postcss@8.4.41)(prettier@3.3.3)(sass@1.77.8)(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
vite-plugin-svgr:
|
||||
specifier: 4.2.0
|
||||
version: 4.2.0(rollup@4.21.0)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
version: 4.2.0(rollup@4.21.0)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
vite-tsconfig-paths:
|
||||
specifier: 5.0.1
|
||||
version: 5.0.1(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
version: 5.0.1(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
|
||||
frontend/ui:
|
||||
dependencies:
|
||||
@@ -380,7 +380,7 @@ importers:
|
||||
version: types-react@19.0.0-rc.1
|
||||
'@vitejs/plugin-react':
|
||||
specifier: 4.3.1
|
||||
version: 4.3.1(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
version: 4.3.1(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
ahooks:
|
||||
specifier: 3.8.1
|
||||
version: 3.8.1(react@19.0.0-rc-e948a5ac-20240807)
|
||||
@@ -404,10 +404,10 @@ importers:
|
||||
version: 17.5.1(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)
|
||||
vite:
|
||||
specifier: 5.4.2
|
||||
version: 5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
version: 5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite-tsconfig-paths:
|
||||
specifier: 5.0.1
|
||||
version: 5.0.1(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
version: 5.0.1(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
devDependencies:
|
||||
'@emotion/react':
|
||||
specifier: 11.13.3
|
||||
@@ -432,7 +432,7 @@ importers:
|
||||
version: 5.1.0(typescript@5.5.4)
|
||||
vite-plugin-dts:
|
||||
specifier: 4.0.3
|
||||
version: 4.0.3(@types/node@22.5.0)(rollup@4.21.0)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
version: 4.0.3(@types/node@22.5.1)(rollup@4.21.0)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
|
||||
scripts:
|
||||
dependencies:
|
||||
@@ -1389,8 +1389,8 @@ packages:
|
||||
'@vue/compiler-sfc':
|
||||
optional: true
|
||||
|
||||
'@iconify/json@2.2.241':
|
||||
resolution: {integrity: sha512-zpeIjmIrTjl0ra6BYTYDfoK/hXn++xT5Hllc87K5SQwnqKs9RJeToSBzjF1gAsrxia+ilkhtGCcqbFF0ppDXiw==}
|
||||
'@iconify/json@2.2.242':
|
||||
resolution: {integrity: sha512-cS6eYdx1C1GhqaZm25ztH5yoghCaTXGJBeseUkS259GxxX9obtGLLk0yy+twxpNCD5/F9gjbgxh46BjNWsHtwg==}
|
||||
|
||||
'@iconify/types@2.0.0':
|
||||
resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==}
|
||||
@@ -2492,6 +2492,9 @@ packages:
|
||||
'@types/node@22.5.0':
|
||||
resolution: {integrity: sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==}
|
||||
|
||||
'@types/node@22.5.1':
|
||||
resolution: {integrity: sha512-KkHsxej0j9IW1KKOOAA/XBA0z08UFSrRQHErzEfA3Vgq57eXIMYboIlHJuYIfd+lwCQjtKqUu3UnmKbtUc9yRw==}
|
||||
|
||||
'@types/parse-json@4.0.2':
|
||||
resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
|
||||
|
||||
@@ -6550,8 +6553,8 @@ packages:
|
||||
vfile@6.0.1:
|
||||
resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==}
|
||||
|
||||
virtua@0.33.7:
|
||||
resolution: {integrity: sha512-IepZaMD/oeEh/ymTqokeQGLrMuRV25+lizPegxVIhOwqX+dEeV9ml1P57Eosok4qiZaeBeQIbIkF9QZrT+EeRQ==}
|
||||
virtua@0.34.0:
|
||||
resolution: {integrity: sha512-tcIehi5MXW5TrJyPiwZXyPIquw5lSNMBlFVwZMomnuwn4bsTx3T2FB7knfY1VB53T9poGd9OPX3zpqh7gu1WyQ==}
|
||||
peerDependencies:
|
||||
react: npm:react@rc
|
||||
react-dom: npm:react-dom@rc
|
||||
@@ -7119,11 +7122,11 @@ snapshots:
|
||||
'@babel/helper-validator-identifier': 7.24.7
|
||||
to-fast-properties: 2.0.0
|
||||
|
||||
'@commitlint/cli@19.4.0(@types/node@22.5.0)(typescript@5.5.4)':
|
||||
'@commitlint/cli@19.4.0(@types/node@22.5.1)(typescript@5.5.4)':
|
||||
dependencies:
|
||||
'@commitlint/format': 19.3.0
|
||||
'@commitlint/lint': 19.2.2
|
||||
'@commitlint/load': 19.4.0(@types/node@22.5.0)(typescript@5.5.4)
|
||||
'@commitlint/load': 19.4.0(@types/node@22.5.1)(typescript@5.5.4)
|
||||
'@commitlint/read': 19.4.0
|
||||
'@commitlint/types': 19.0.3
|
||||
execa: 8.0.1
|
||||
@@ -7170,7 +7173,7 @@ snapshots:
|
||||
'@commitlint/rules': 19.0.3
|
||||
'@commitlint/types': 19.0.3
|
||||
|
||||
'@commitlint/load@19.4.0(@types/node@22.5.0)(typescript@5.5.4)':
|
||||
'@commitlint/load@19.4.0(@types/node@22.5.1)(typescript@5.5.4)':
|
||||
dependencies:
|
||||
'@commitlint/config-validator': 19.0.3
|
||||
'@commitlint/execute-rule': 19.0.0
|
||||
@@ -7178,7 +7181,7 @@ snapshots:
|
||||
'@commitlint/types': 19.0.3
|
||||
chalk: 5.3.0
|
||||
cosmiconfig: 9.0.0(typescript@5.5.4)
|
||||
cosmiconfig-typescript-loader: 5.0.0(@types/node@22.5.0)(cosmiconfig@9.0.0(typescript@5.5.4))(typescript@5.5.4)
|
||||
cosmiconfig-typescript-loader: 5.0.0(@types/node@22.5.1)(cosmiconfig@9.0.0(typescript@5.5.4))(typescript@5.5.4)
|
||||
lodash.isplainobject: 4.0.6
|
||||
lodash.merge: 4.6.2
|
||||
lodash.uniq: 4.5.0
|
||||
@@ -7636,13 +7639,13 @@ snapshots:
|
||||
postcss: 7.0.32
|
||||
purgecss: 2.3.0
|
||||
|
||||
'@generouted/react-router@1.19.6(react-router-dom@6.26.1(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
|
||||
'@generouted/react-router@1.19.6(react-router-dom@6.26.1(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
|
||||
dependencies:
|
||||
fast-glob: 3.3.2
|
||||
generouted: 1.19.6(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
generouted: 1.19.6(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))
|
||||
react: 19.0.0-rc-e948a5ac-20240807
|
||||
react-router-dom: 6.26.1(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)
|
||||
vite: 5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite: 5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
|
||||
'@humanwhocodes/config-array@0.11.14':
|
||||
dependencies:
|
||||
@@ -7668,7 +7671,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@iconify/json@2.2.241':
|
||||
'@iconify/json@2.2.242':
|
||||
dependencies:
|
||||
'@iconify/types': 2.0.0
|
||||
pathe: 1.1.2
|
||||
@@ -7728,23 +7731,23 @@ snapshots:
|
||||
|
||||
'@material/material-color-utilities@0.3.0': {}
|
||||
|
||||
'@microsoft/api-extractor-model@7.29.4(@types/node@22.5.0)':
|
||||
'@microsoft/api-extractor-model@7.29.4(@types/node@22.5.1)':
|
||||
dependencies:
|
||||
'@microsoft/tsdoc': 0.15.0
|
||||
'@microsoft/tsdoc-config': 0.17.0
|
||||
'@rushstack/node-core-library': 5.5.1(@types/node@22.5.0)
|
||||
'@rushstack/node-core-library': 5.5.1(@types/node@22.5.1)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
|
||||
'@microsoft/api-extractor@7.47.4(@types/node@22.5.0)':
|
||||
'@microsoft/api-extractor@7.47.4(@types/node@22.5.1)':
|
||||
dependencies:
|
||||
'@microsoft/api-extractor-model': 7.29.4(@types/node@22.5.0)
|
||||
'@microsoft/api-extractor-model': 7.29.4(@types/node@22.5.1)
|
||||
'@microsoft/tsdoc': 0.15.0
|
||||
'@microsoft/tsdoc-config': 0.17.0
|
||||
'@rushstack/node-core-library': 5.5.1(@types/node@22.5.0)
|
||||
'@rushstack/node-core-library': 5.5.1(@types/node@22.5.1)
|
||||
'@rushstack/rig-package': 0.5.3
|
||||
'@rushstack/terminal': 0.13.3(@types/node@22.5.0)
|
||||
'@rushstack/ts-command-line': 4.22.3(@types/node@22.5.0)
|
||||
'@rushstack/terminal': 0.13.3(@types/node@22.5.1)
|
||||
'@rushstack/ts-command-line': 4.22.3(@types/node@22.5.1)
|
||||
lodash: 4.17.21
|
||||
minimatch: 3.0.8
|
||||
resolve: 1.22.8
|
||||
@@ -8300,7 +8303,7 @@ snapshots:
|
||||
'@rollup/rollup-win32-x64-msvc@4.21.0':
|
||||
optional: true
|
||||
|
||||
'@rushstack/node-core-library@5.5.1(@types/node@22.5.0)':
|
||||
'@rushstack/node-core-library@5.5.1(@types/node@22.5.1)':
|
||||
dependencies:
|
||||
ajv: 8.13.0
|
||||
ajv-draft-04: 1.0.0(ajv@8.13.0)
|
||||
@@ -8311,23 +8314,23 @@ snapshots:
|
||||
resolve: 1.22.8
|
||||
semver: 7.5.4
|
||||
optionalDependencies:
|
||||
'@types/node': 22.5.0
|
||||
'@types/node': 22.5.1
|
||||
|
||||
'@rushstack/rig-package@0.5.3':
|
||||
dependencies:
|
||||
resolve: 1.22.8
|
||||
strip-json-comments: 3.1.1
|
||||
|
||||
'@rushstack/terminal@0.13.3(@types/node@22.5.0)':
|
||||
'@rushstack/terminal@0.13.3(@types/node@22.5.1)':
|
||||
dependencies:
|
||||
'@rushstack/node-core-library': 5.5.1(@types/node@22.5.0)
|
||||
'@rushstack/node-core-library': 5.5.1(@types/node@22.5.1)
|
||||
supports-color: 8.1.1
|
||||
optionalDependencies:
|
||||
'@types/node': 22.5.0
|
||||
'@types/node': 22.5.1
|
||||
|
||||
'@rushstack/ts-command-line@4.22.3(@types/node@22.5.0)':
|
||||
'@rushstack/ts-command-line@4.22.3(@types/node@22.5.1)':
|
||||
dependencies:
|
||||
'@rushstack/terminal': 0.13.3(@types/node@22.5.0)
|
||||
'@rushstack/terminal': 0.13.3(@types/node@22.5.1)
|
||||
'@types/argparse': 1.0.38
|
||||
argparse: 1.0.10
|
||||
string-argv: 0.3.2
|
||||
@@ -8589,12 +8592,12 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/http-cache-semantics': 4.0.4
|
||||
'@types/keyv': 3.1.4
|
||||
'@types/node': 22.5.0
|
||||
'@types/node': 22.5.1
|
||||
'@types/responselike': 1.0.3
|
||||
|
||||
'@types/conventional-commits-parser@5.0.0':
|
||||
dependencies:
|
||||
'@types/node': 22.5.0
|
||||
'@types/node': 22.5.1
|
||||
|
||||
'@types/d3-array@3.2.1': {}
|
||||
|
||||
@@ -8730,7 +8733,7 @@ snapshots:
|
||||
'@types/fs-extra@11.0.4':
|
||||
dependencies:
|
||||
'@types/jsonfile': 6.1.4
|
||||
'@types/node': 22.5.0
|
||||
'@types/node': 22.5.1
|
||||
|
||||
'@types/geojson@7946.0.14': {}
|
||||
|
||||
@@ -8746,11 +8749,11 @@ snapshots:
|
||||
|
||||
'@types/jsonfile@6.1.4':
|
||||
dependencies:
|
||||
'@types/node': 22.5.0
|
||||
'@types/node': 22.5.1
|
||||
|
||||
'@types/keyv@3.1.4':
|
||||
dependencies:
|
||||
'@types/node': 22.5.0
|
||||
'@types/node': 22.5.1
|
||||
|
||||
'@types/lodash-es@4.17.12':
|
||||
dependencies:
|
||||
@@ -8770,6 +8773,10 @@ snapshots:
|
||||
dependencies:
|
||||
undici-types: 6.19.6
|
||||
|
||||
'@types/node@22.5.1':
|
||||
dependencies:
|
||||
undici-types: 6.19.6
|
||||
|
||||
'@types/parse-json@4.0.2': {}
|
||||
|
||||
'@types/postcss-modules-local-by-default@4.0.2':
|
||||
@@ -8788,7 +8795,7 @@ snapshots:
|
||||
|
||||
'@types/responselike@1.0.3':
|
||||
dependencies:
|
||||
'@types/node': 22.5.0
|
||||
'@types/node': 22.5.1
|
||||
|
||||
'@types/unist@2.0.10': {}
|
||||
|
||||
@@ -8796,7 +8803,7 @@ snapshots:
|
||||
|
||||
'@types/yauzl@2.10.3':
|
||||
dependencies:
|
||||
'@types/node': 22.5.0
|
||||
'@types/node': 22.5.1
|
||||
optional: true
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.2.0(@typescript-eslint/parser@8.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4)':
|
||||
@@ -8882,21 +8889,21 @@ snapshots:
|
||||
|
||||
'@ungap/structured-clone@1.2.0': {}
|
||||
|
||||
'@vitejs/plugin-react-swc@3.7.0(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
|
||||
'@vitejs/plugin-react-swc@3.7.0(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
|
||||
dependencies:
|
||||
'@swc/core': 1.6.1
|
||||
vite: 5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite: 5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- '@swc/helpers'
|
||||
|
||||
'@vitejs/plugin-react@4.3.1(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
|
||||
'@vitejs/plugin-react@4.3.1(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))':
|
||||
dependencies:
|
||||
'@babel/core': 7.24.5
|
||||
'@babel/plugin-transform-react-jsx-self': 7.24.5(@babel/core@7.24.5)
|
||||
'@babel/plugin-transform-react-jsx-source': 7.24.1(@babel/core@7.24.5)
|
||||
'@types/babel__core': 7.20.5
|
||||
react-refresh: 0.14.2
|
||||
vite: 5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite: 5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -9460,9 +9467,9 @@ snapshots:
|
||||
dependencies:
|
||||
toggle-selection: 1.0.6
|
||||
|
||||
cosmiconfig-typescript-loader@5.0.0(@types/node@22.5.0)(cosmiconfig@9.0.0(typescript@5.5.4))(typescript@5.5.4):
|
||||
cosmiconfig-typescript-loader@5.0.0(@types/node@22.5.1)(cosmiconfig@9.0.0(typescript@5.5.4))(typescript@5.5.4):
|
||||
dependencies:
|
||||
'@types/node': 22.5.0
|
||||
'@types/node': 22.5.1
|
||||
cosmiconfig: 9.0.0(typescript@5.5.4)
|
||||
jiti: 1.21.6
|
||||
typescript: 5.5.4
|
||||
@@ -10545,9 +10552,9 @@ snapshots:
|
||||
|
||||
functions-have-names@1.2.3: {}
|
||||
|
||||
generouted@1.19.6(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
generouted@1.19.6(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
vite: 5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite: 5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
|
||||
gensync@1.0.0-beta.2: {}
|
||||
|
||||
@@ -11158,11 +11165,11 @@ snapshots:
|
||||
|
||||
kind-of@6.0.3: {}
|
||||
|
||||
knip@5.27.4(@types/node@22.5.0)(typescript@5.5.4):
|
||||
knip@5.27.4(@types/node@22.5.1)(typescript@5.5.4):
|
||||
dependencies:
|
||||
'@nodelib/fs.walk': 1.2.8
|
||||
'@snyk/github-codeowners': 1.1.0
|
||||
'@types/node': 22.5.0
|
||||
'@types/node': 22.5.1
|
||||
easy-table: 1.2.0
|
||||
enhanced-resolve: 5.17.1
|
||||
fast-glob: 3.3.2
|
||||
@@ -13358,14 +13365,14 @@ snapshots:
|
||||
unist-util-stringify-position: 4.0.0
|
||||
vfile-message: 4.0.2
|
||||
|
||||
virtua@0.33.7(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807):
|
||||
virtua@0.34.0(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807):
|
||||
optionalDependencies:
|
||||
react: 19.0.0-rc-e948a5ac-20240807
|
||||
react-dom: 19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807)
|
||||
|
||||
vite-plugin-dts@4.0.3(@types/node@22.5.0)(rollup@4.21.0)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
vite-plugin-dts@4.0.3(@types/node@22.5.1)(rollup@4.21.0)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
'@microsoft/api-extractor': 7.47.4(@types/node@22.5.0)
|
||||
'@microsoft/api-extractor': 7.47.4(@types/node@22.5.1)
|
||||
'@rollup/pluginutils': 5.1.0(rollup@4.21.0)
|
||||
'@volar/typescript': 2.4.0
|
||||
'@vue/language-core': 2.0.29(typescript@5.5.4)
|
||||
@@ -13377,7 +13384,7 @@ snapshots:
|
||||
typescript: 5.5.4
|
||||
vue-tsc: 2.0.29(typescript@5.5.4)
|
||||
optionalDependencies:
|
||||
vite: 5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite: 5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- rollup
|
||||
@@ -13388,43 +13395,43 @@ snapshots:
|
||||
esbuild: 0.19.12
|
||||
monaco-editor: 0.51.0
|
||||
|
||||
vite-plugin-sass-dts@1.3.25(postcss@8.4.41)(prettier@3.3.3)(sass@1.77.8)(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
vite-plugin-sass-dts@1.3.25(postcss@8.4.41)(prettier@3.3.3)(sass@1.77.8)(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
postcss: 8.4.41
|
||||
postcss-js: 4.0.1(postcss@8.4.41)
|
||||
prettier: 3.3.3
|
||||
sass: 1.77.8
|
||||
vite: 5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite: 5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
|
||||
vite-plugin-svgr@4.2.0(rollup@4.21.0)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
vite-plugin-svgr@4.2.0(rollup@4.21.0)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.1.0(rollup@4.21.0)
|
||||
'@svgr/core': 8.1.0(typescript@5.5.4)
|
||||
'@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.5.4))
|
||||
vite: 5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite: 5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite-tsconfig-paths@5.0.1(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
vite-tsconfig-paths@5.0.1(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)):
|
||||
dependencies:
|
||||
debug: 4.3.6
|
||||
globrex: 0.1.2
|
||||
tsconfck: 3.0.3(typescript@5.5.4)
|
||||
optionalDependencies:
|
||||
vite: 5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
vite: 5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite@5.4.2(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0):
|
||||
vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0):
|
||||
dependencies:
|
||||
esbuild: 0.21.5
|
||||
postcss: 8.4.41
|
||||
rollup: 4.21.0
|
||||
optionalDependencies:
|
||||
'@types/node': 22.5.0
|
||||
'@types/node': 22.5.1
|
||||
fsevents: 2.3.3
|
||||
less: 4.2.0
|
||||
sass: 1.77.8
|
||||
|
@@ -4,17 +4,15 @@
|
||||
[](https://pkg.go.dev/github.com/Ehco1996/ehco)
|
||||
[](https://hub.docker.com/r/ehco1996/ehco)
|
||||
|
||||
[see Readme in English here](README_EN.md)
|
||||
|
||||
## Ehco Relay - 让流量转发更简单
|
||||
|
||||
ehco 现在提供 SaaS(软件即服务)版本!这是一个全托管的解决方案,旨在为那些希望在不搭建和管理自己的服务器的情况下享受 ehco 强大流量转发能力的用户提供服务。
|
||||
|
||||
- [Ehco Relay 官方网站](https://ehco-relay.cc)
|
||||
- [Ehco Relay 文档](https://docs.ehco-relay.cc/)
|
||||
- [Ehco Relay 官方网站](https://ehco-relay.cc)
|
||||
- [Ehco Relay 文档](https://docs.ehco-relay.cc/)
|
||||
|
||||
## 主要功能
|
||||
|
||||
- tcp/udp relay
|
||||
- tunnel relay (ws/wss/mwss/mtcp)
|
||||
- [更多功能请探索文档](https://docs.ehco-relay.cc/)
|
||||
- tcp/udp relay
|
||||
- tunnel relay (ws/wss/)
|
||||
- [更多功能请探索文档](https://docs.ehco-relay.cc/)
|
||||
|
@@ -1,23 +0,0 @@
|
||||
# Ehco
|
||||
|
||||
ehco is a network relay tool and a typo :)
|
||||
|
||||
[](https://goreportcard.com/report/github.com/Ehco1996/ehco)
|
||||
[](https://pkg.go.dev/github.com/Ehco1996/ehco)
|
||||
[](https://hub.docker.com/r/ehco1996/ehco)
|
||||
|
||||
## Quick Start
|
||||
|
||||
let's see some examples
|
||||
|
||||
> relay all tcp traffic from `0.0.0.0:1234` to `0.0.0.0:5201`
|
||||
|
||||
`ehco -l 0.0.0.0:1234 -r 0.0.0.0:5201`
|
||||
|
||||
> also relay udp traffic to `0.0.0.0:5201`
|
||||
|
||||
`ehco -l 0.0.0.0:1234 -r 0.0.0.0:5201 -ur 0.0.0.0:5201`
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
TBD, for now, you can see more examples in [ReadmeCN](README.md)
|
@@ -9,15 +9,18 @@
|
||||
"listen_type": "raw",
|
||||
"transport_type": "raw",
|
||||
"label": "relay1",
|
||||
"tcp_remotes": [
|
||||
"remotes": [
|
||||
"0.0.0.0:5201"
|
||||
]
|
||||
],
|
||||
"options": {
|
||||
"enable_udp": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"listen": "127.0.0.1:1235",
|
||||
"listen_type": "raw",
|
||||
"transport_type": "ws",
|
||||
"tcp_remotes": [
|
||||
"remotes": [
|
||||
"ws://0.0.0.0:2443"
|
||||
]
|
||||
},
|
||||
@@ -25,7 +28,7 @@
|
||||
"listen": "127.0.0.1:1236",
|
||||
"listen_type": "raw",
|
||||
"transport_type": "wss",
|
||||
"tcp_remotes": [
|
||||
"remotes": [
|
||||
"wss://0.0.0.0:3443"
|
||||
]
|
||||
},
|
||||
@@ -33,7 +36,7 @@
|
||||
"listen": "127.0.0.1:2443",
|
||||
"listen_type": "ws",
|
||||
"transport_type": "raw",
|
||||
"tcp_remotes": [
|
||||
"remotes": [
|
||||
"0.0.0.0:5201"
|
||||
]
|
||||
},
|
||||
@@ -41,7 +44,7 @@
|
||||
"listen": "127.0.0.1:3443",
|
||||
"listen_type": "wss",
|
||||
"transport_type": "raw",
|
||||
"tcp_remotes": [
|
||||
"remotes": [
|
||||
"0.0.0.0:5201"
|
||||
]
|
||||
}
|
||||
|
@@ -28,8 +28,7 @@ type RoundRobin interface {
|
||||
type roundrobin struct {
|
||||
nodeList []*Node
|
||||
next *atomic.Int64
|
||||
|
||||
len int
|
||||
len int
|
||||
}
|
||||
|
||||
func NewRoundRobin(nodeList []*Node) RoundRobin {
|
||||
|
@@ -114,10 +114,10 @@ func (r *Config) Adjust() error {
|
||||
if r.Options == nil {
|
||||
r.Options = newDefaultOptions()
|
||||
} else {
|
||||
r.Options.DialTimeout = getDuration(r.Options.DialTimeoutSec, r.Options.DialTimeout)
|
||||
r.Options.IdleTimeout = getDuration(r.Options.IdleTimeoutSec, r.Options.IdleTimeout)
|
||||
r.Options.ReadTimeout = getDuration(r.Options.ReadTimeoutSec, r.Options.ReadTimeout)
|
||||
r.Options.SniffTimeout = getDuration(r.Options.SniffTimeoutSec, r.Options.SniffTimeout)
|
||||
r.Options.DialTimeout = getDuration(r.Options.DialTimeoutSec, constant.DefaultDialTimeOut)
|
||||
r.Options.IdleTimeout = getDuration(r.Options.IdleTimeoutSec, constant.DefaultIdleTimeOut)
|
||||
r.Options.ReadTimeout = getDuration(r.Options.ReadTimeoutSec, constant.DefaultReadTimeOut)
|
||||
r.Options.SniffTimeout = getDuration(r.Options.SniffTimeoutSec, constant.DefaultSniffTimeOut)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -5,17 +5,17 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/sagernet/sing-box/common/sniff"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/Ehco1996/ehco/internal/cmgr"
|
||||
"github.com/Ehco1996/ehco/internal/conn"
|
||||
"github.com/Ehco1996/ehco/internal/constant"
|
||||
"github.com/Ehco1996/ehco/internal/lb"
|
||||
"github.com/Ehco1996/ehco/internal/metrics"
|
||||
"github.com/Ehco1996/ehco/internal/relay/conf"
|
||||
"github.com/sagernet/sing-box/common/sniff"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var _ RelayServer = &BaseRelayServer{}
|
||||
@@ -43,8 +43,10 @@ func newBaseRelayServer(cfg *conf.Config, cmgr cmgr.Cmgr) (*BaseRelayServer, err
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (b *BaseRelayServer) RelayTCPConn(ctx context.Context, c net.Conn) error {
|
||||
remote := b.remotes.Next().Clone()
|
||||
func (b *BaseRelayServer) RelayTCPConn(ctx context.Context, c net.Conn, remote *lb.Node) error {
|
||||
if remote == nil {
|
||||
remote = b.remotes.Next().Clone()
|
||||
}
|
||||
metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Inc()
|
||||
defer metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_TCP).Dec()
|
||||
|
||||
@@ -69,8 +71,10 @@ func (b *BaseRelayServer) RelayTCPConn(ctx context.Context, c net.Conn) error {
|
||||
return b.handleRelayConn(c, rc, remote, metrics.METRIC_CONN_TYPE_TCP)
|
||||
}
|
||||
|
||||
func (b *BaseRelayServer) RelayUDPConn(ctx context.Context, c net.Conn) error {
|
||||
remote := b.remotes.Next().Clone()
|
||||
func (b *BaseRelayServer) RelayUDPConn(ctx context.Context, c net.Conn, remote *lb.Node) error {
|
||||
if remote == nil {
|
||||
remote = b.remotes.Next().Clone()
|
||||
}
|
||||
metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_UDP).Inc()
|
||||
defer metrics.CurConnectionCount.WithLabelValues(remote.Label, metrics.METRIC_CONN_TYPE_UDP).Dec()
|
||||
|
||||
|
@@ -33,8 +33,8 @@ type RelayServer interface {
|
||||
ListenAndServe(ctx context.Context) error
|
||||
Close() error
|
||||
|
||||
RelayTCPConn(ctx context.Context, c net.Conn) error
|
||||
RelayUDPConn(ctx context.Context, c net.Conn) error
|
||||
RelayTCPConn(ctx context.Context, c net.Conn, remote *lb.Node) error
|
||||
RelayUDPConn(ctx context.Context, c net.Conn, remote *lb.Node) error
|
||||
HealthCheck(ctx context.Context) (int64, error) // latency in ms
|
||||
}
|
||||
|
||||
|
@@ -99,7 +99,7 @@ func (s *RawServer) ListenAndServe(ctx context.Context) error {
|
||||
}
|
||||
go func(c net.Conn) {
|
||||
defer c.Close()
|
||||
if err := s.RelayTCPConn(ctx, c); err != nil {
|
||||
if err := s.RelayTCPConn(ctx, c, nil); err != nil {
|
||||
s.l.Errorf("RelayTCPConn meet error: %s", err.Error())
|
||||
}
|
||||
}(c)
|
||||
@@ -118,7 +118,7 @@ func (s *RawServer) listenUDP(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
if err := s.RelayUDPConn(ctx, c); err != nil {
|
||||
if err := s.RelayUDPConn(ctx, c, nil); err != nil {
|
||||
s.l.Errorf("RelayUDPConn meet error: %s", err.Error())
|
||||
}
|
||||
}()
|
||||
|
@@ -97,15 +97,21 @@ func (s *WsServer) handleRequest(w http.ResponseWriter, req *http.Request) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var remote *lb.Node
|
||||
if addr := req.URL.Query().Get(conf.WS_QUERY_REMOTE_ADDR); addr != "" {
|
||||
remote = &lb.Node{Address: addr, Label: addr}
|
||||
}
|
||||
|
||||
if req.URL.Query().Get("type") == "udp" {
|
||||
if !s.cfg.Options.EnableUDP {
|
||||
s.l.Error("udp not support but request with udp type")
|
||||
wsc.Close()
|
||||
return
|
||||
}
|
||||
err = s.RelayUDPConn(req.Context(), conn.NewWSConn(wsc, true))
|
||||
err = s.RelayUDPConn(req.Context(), conn.NewWSConn(wsc, true), remote)
|
||||
} else {
|
||||
err = s.RelayTCPConn(req.Context(), conn.NewWSConn(wsc, true))
|
||||
err = s.RelayTCPConn(req.Context(), conn.NewWSConn(wsc, true), remote)
|
||||
}
|
||||
if err != nil {
|
||||
s.l.Errorf("handleRequest meet error:%s", err)
|
||||
|
@@ -46,6 +46,14 @@ func (set *IpCidrSet) IsContain(ip netip.Addr) bool {
|
||||
return set.ToIPSet().Contains(ip.WithZone(""))
|
||||
}
|
||||
|
||||
// MatchIp implements C.IpMatcher
|
||||
func (set *IpCidrSet) MatchIp(ip netip.Addr) bool {
|
||||
if set.IsEmpty() {
|
||||
return false
|
||||
}
|
||||
return set.IsContain(ip)
|
||||
}
|
||||
|
||||
func (set *IpCidrSet) Merge() error {
|
||||
var b netipx.IPSetBuilder
|
||||
b.AddSet(set.ToIPSet())
|
||||
|
@@ -35,7 +35,7 @@ type Pool struct {
|
||||
offset netip.Addr
|
||||
cycle bool
|
||||
mux sync.Mutex
|
||||
host []C.Rule
|
||||
host []C.DomainMatcher
|
||||
ipnet netip.Prefix
|
||||
store store
|
||||
}
|
||||
@@ -66,8 +66,8 @@ func (p *Pool) LookBack(ip netip.Addr) (string, bool) {
|
||||
|
||||
// ShouldSkipped return if domain should be skipped
|
||||
func (p *Pool) ShouldSkipped(domain string) bool {
|
||||
for _, rule := range p.host {
|
||||
if match, _ := rule.Match(&C.Metadata{Host: domain}); match {
|
||||
for _, matcher := range p.host {
|
||||
if matcher.MatchDomain(domain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ func (p *Pool) restoreState() {
|
||||
|
||||
type Options struct {
|
||||
IPNet netip.Prefix
|
||||
Host []C.Rule
|
||||
Host []C.DomainMatcher
|
||||
|
||||
// Size sets the maximum number of entries in memory
|
||||
// and does not work if Persistence is true
|
||||
|
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/metacubex/mihomo/component/profile/cachefile"
|
||||
"github.com/metacubex/mihomo/component/trie"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
RP "github.com/metacubex/mihomo/rules/provider"
|
||||
|
||||
"github.com/metacubex/bbolt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -157,7 +156,7 @@ func TestPool_Skip(t *testing.T) {
|
||||
pools, tempfile, err := createPools(Options{
|
||||
IPNet: ipnet,
|
||||
Size: 10,
|
||||
Host: []C.Rule{RP.NewDomainSet(tree.NewDomainSet(), "")},
|
||||
Host: []C.DomainMatcher{tree.NewDomainSet()},
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
defer os.Remove(tempfile)
|
||||
|
@@ -22,23 +22,23 @@ var (
|
||||
type Dispatcher struct {
|
||||
enable bool
|
||||
sniffers map[sniffer.Sniffer]SnifferConfig
|
||||
forceDomain []C.Rule
|
||||
skipSrcAddress []C.Rule
|
||||
skipDstAddress []C.Rule
|
||||
skipDomain []C.Rule
|
||||
forceDomain []C.DomainMatcher
|
||||
skipSrcAddress []C.IpMatcher
|
||||
skipDstAddress []C.IpMatcher
|
||||
skipDomain []C.DomainMatcher
|
||||
skipList *lru.LruCache[netip.AddrPort, uint8]
|
||||
forceDnsMapping bool
|
||||
parsePureIp bool
|
||||
}
|
||||
|
||||
func (sd *Dispatcher) shouldOverride(metadata *C.Metadata) bool {
|
||||
for _, rule := range sd.skipDstAddress {
|
||||
if ok, _ := rule.Match(&C.Metadata{DstIP: metadata.DstIP}); ok {
|
||||
for _, matcher := range sd.skipDstAddress {
|
||||
if matcher.MatchIp(metadata.DstIP) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
for _, rule := range sd.skipSrcAddress {
|
||||
if ok, _ := rule.Match(&C.Metadata{DstIP: metadata.SrcIP}); ok {
|
||||
for _, matcher := range sd.skipSrcAddress {
|
||||
if matcher.MatchIp(metadata.SrcIP) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -48,8 +48,8 @@ func (sd *Dispatcher) shouldOverride(metadata *C.Metadata) bool {
|
||||
if metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping {
|
||||
return true
|
||||
}
|
||||
for _, rule := range sd.forceDomain {
|
||||
if ok, _ := rule.Match(&C.Metadata{Host: metadata.Host}); ok {
|
||||
for _, matcher := range sd.forceDomain {
|
||||
if matcher.MatchDomain(metadata.Host) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -112,8 +112,8 @@ func (sd *Dispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata) bool
|
||||
return false
|
||||
}
|
||||
|
||||
for _, rule := range sd.skipDomain {
|
||||
if ok, _ := rule.Match(&C.Metadata{Host: host}); ok {
|
||||
for _, matcher := range sd.skipDomain {
|
||||
if matcher.MatchDomain(host) {
|
||||
log.Debugln("[Sniffer] Skip sni[%s]", host)
|
||||
return false
|
||||
}
|
||||
@@ -200,10 +200,10 @@ func (sd *Dispatcher) cacheSniffFailed(metadata *C.Metadata) {
|
||||
type Config struct {
|
||||
Enable bool
|
||||
Sniffers map[sniffer.Type]SnifferConfig
|
||||
ForceDomain []C.Rule
|
||||
SkipSrcAddress []C.Rule
|
||||
SkipDstAddress []C.Rule
|
||||
SkipDomain []C.Rule
|
||||
ForceDomain []C.DomainMatcher
|
||||
SkipSrcAddress []C.IpMatcher
|
||||
SkipDstAddress []C.IpMatcher
|
||||
SkipDomain []C.DomainMatcher
|
||||
ForceDnsMapping bool
|
||||
ParsePureIp bool
|
||||
}
|
||||
|
@@ -172,6 +172,11 @@ func (ss *DomainSet) Foreach(f func(key string) bool) {
|
||||
})
|
||||
}
|
||||
|
||||
// MatchDomain implements C.DomainMatcher
|
||||
func (ss *DomainSet) MatchDomain(domain string) bool {
|
||||
return ss.Has(domain)
|
||||
}
|
||||
|
||||
func setBit(bm *[]uint64, i int, v int) {
|
||||
for i>>6 >= len(*bm) {
|
||||
*bm = append(*bm, 0)
|
||||
|
@@ -143,8 +143,8 @@ type DNS struct {
|
||||
UseSystemHosts bool
|
||||
NameServer []dns.NameServer
|
||||
Fallback []dns.NameServer
|
||||
FallbackIPFilter []C.Rule
|
||||
FallbackDomainFilter []C.Rule
|
||||
FallbackIPFilter []C.IpMatcher
|
||||
FallbackDomainFilter []C.DomainMatcher
|
||||
Listen string
|
||||
EnhancedMode C.DNSMode
|
||||
DefaultNameserver []dns.NameServer
|
||||
@@ -640,7 +640,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
|
||||
}
|
||||
config.Hosts = hosts
|
||||
|
||||
dnsCfg, err := parseDNS(rawCfg, hosts, rules, ruleProviders)
|
||||
dnsCfg, err := parseDNS(rawCfg, hosts, ruleProviders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1297,7 +1297,7 @@ func parsePureDNSServer(server string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider, respectRules bool, preferH3 bool) ([]dns.Policy, error) {
|
||||
func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], ruleProviders map[string]providerTypes.RuleProvider, respectRules bool, preferH3 bool) ([]dns.Policy, error) {
|
||||
var policy []dns.Policy
|
||||
re := regexp.MustCompile(`[a-zA-Z0-9\-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?`)
|
||||
|
||||
@@ -1350,18 +1350,18 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rules [
|
||||
|
||||
if strings.HasPrefix(domain, "rule-set:") {
|
||||
domainSetName := domain[9:]
|
||||
rule, err := parseDomainRuleSet(domainSetName, "dns.nameserver-policy", ruleProviders)
|
||||
matcher, err := parseDomainRuleSet(domainSetName, "dns.nameserver-policy", ruleProviders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policy[idx] = dns.Policy{Rule: rule, NameServers: nameservers}
|
||||
policy[idx] = dns.Policy{Matcher: matcher, NameServers: nameservers}
|
||||
} else if strings.HasPrefix(domain, "geosite:") {
|
||||
country := domain[8:]
|
||||
rule, err := RC.NewGEOSITE(country, "dns.nameserver-policy")
|
||||
matcher, err := RC.NewGEOSITE(country, "dns.nameserver-policy")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
policy[idx] = dns.Policy{Rule: rule, NameServers: nameservers}
|
||||
policy[idx] = dns.Policy{Matcher: matcher, NameServers: nameservers}
|
||||
} else {
|
||||
if _, valid := trie.ValidAndSplitDomain(domain); !valid {
|
||||
return nil, fmt.Errorf("DNS ResoverRule invalid domain: %s", domain)
|
||||
@@ -1372,7 +1372,7 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rules [
|
||||
return policy, nil
|
||||
}
|
||||
|
||||
func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider) (*DNS, error) {
|
||||
func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], ruleProviders map[string]providerTypes.RuleProvider) (*DNS, error) {
|
||||
cfg := rawCfg.DNS
|
||||
if cfg.Enable && len(cfg.NameServer) == 0 {
|
||||
return nil, fmt.Errorf("if DNS configuration is turned on, NameServer cannot be empty")
|
||||
@@ -1400,7 +1400,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy, rules, ruleProviders, cfg.RespectRules, cfg.PreferH3); err != nil {
|
||||
if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy, ruleProviders, cfg.RespectRules, cfg.PreferH3); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1467,14 +1467,13 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
||||
dnsCfg.FakeIPRange = pool
|
||||
}
|
||||
|
||||
var rule C.Rule
|
||||
if len(cfg.Fallback) != 0 {
|
||||
if cfg.FallbackFilter.GeoIP {
|
||||
rule, err = RC.NewGEOIP(cfg.FallbackFilter.GeoIPCode, "dns.fallback-filter.geoip", false, true)
|
||||
matcher, err := RC.NewGEOIP(cfg.FallbackFilter.GeoIPCode, "dns.fallback-filter.geoip", false, true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load GeoIP dns fallback filter error, %w", err)
|
||||
}
|
||||
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, rule)
|
||||
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, matcher)
|
||||
}
|
||||
if len(cfg.FallbackFilter.IPCIDR) > 0 {
|
||||
cidrSet := cidr.NewIpCidrSet()
|
||||
@@ -1488,8 +1487,8 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule = RP.NewIpCidrSet(cidrSet, "dns.fallback-filter.ipcidr")
|
||||
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, rule)
|
||||
matcher := cidrSet // dns.fallback-filter.ipcidr
|
||||
dnsCfg.FallbackIPFilter = append(dnsCfg.FallbackIPFilter, matcher)
|
||||
}
|
||||
if len(cfg.FallbackFilter.Domain) > 0 {
|
||||
domainTrie := trie.New[struct{}]()
|
||||
@@ -1499,17 +1498,17 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
||||
return nil, fmt.Errorf("DNS FallbackDomain[%d] format error: %w", idx, err)
|
||||
}
|
||||
}
|
||||
rule = RP.NewDomainSet(domainTrie.NewDomainSet(), "dns.fallback-filter.domain")
|
||||
dnsCfg.FallbackDomainFilter = append(dnsCfg.FallbackDomainFilter, rule)
|
||||
matcher := domainTrie.NewDomainSet() // dns.fallback-filter.domain
|
||||
dnsCfg.FallbackDomainFilter = append(dnsCfg.FallbackDomainFilter, matcher)
|
||||
}
|
||||
if len(cfg.FallbackFilter.GeoSite) > 0 {
|
||||
log.Warnln("replace fallback-filter.geosite with nameserver-policy, it will be removed in the future")
|
||||
for idx, geoSite := range cfg.FallbackFilter.GeoSite {
|
||||
rule, err = RC.NewGEOSITE(geoSite, "dns.fallback-filter.geosite")
|
||||
matcher, err := RC.NewGEOSITE(geoSite, "dns.fallback-filter.geosite")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("DNS FallbackGeosite[%d] format error: %w", idx, err)
|
||||
}
|
||||
dnsCfg.FallbackDomainFilter = append(dnsCfg.FallbackDomainFilter, rule)
|
||||
dnsCfg.FallbackDomainFilter = append(dnsCfg.FallbackDomainFilter, matcher)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1701,8 +1700,8 @@ func parseSniffer(snifferRaw RawSniffer, ruleProviders map[string]providerTypes.
|
||||
return snifferConfig, nil
|
||||
}
|
||||
|
||||
func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (ipRules []C.Rule, err error) {
|
||||
var rule C.Rule
|
||||
func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (matchers []C.IpMatcher, err error) {
|
||||
var matcher C.IpMatcher
|
||||
for _, ipcidr := range addresses {
|
||||
ipcidrLower := strings.ToLower(ipcidr)
|
||||
if strings.Contains(ipcidrLower, "geoip:") {
|
||||
@@ -1710,22 +1709,22 @@ func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, country := range subkeys {
|
||||
rule, err = RC.NewGEOIP(country, adapterName, false, false)
|
||||
matcher, err = RC.NewGEOIP(country, adapterName, false, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipRules = append(ipRules, rule)
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
} else if strings.Contains(ipcidrLower, "rule-set:") {
|
||||
subkeys := strings.Split(ipcidr, ":")
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, domainSetName := range subkeys {
|
||||
rule, err = parseIPRuleSet(domainSetName, adapterName, ruleProviders)
|
||||
matcher, err = parseIPRuleSet(domainSetName, adapterName, ruleProviders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipRules = append(ipRules, rule)
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
} else {
|
||||
if cidrSet == nil {
|
||||
@@ -1742,14 +1741,14 @@ func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule = RP.NewIpCidrSet(cidrSet, adapterName)
|
||||
ipRules = append(ipRules, rule)
|
||||
matcher = cidrSet
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (domainRules []C.Rule, err error) {
|
||||
var rule C.Rule
|
||||
func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (matchers []C.DomainMatcher, err error) {
|
||||
var matcher C.DomainMatcher
|
||||
for _, domain := range domains {
|
||||
domainLower := strings.ToLower(domain)
|
||||
if strings.Contains(domainLower, "geosite:") {
|
||||
@@ -1757,22 +1756,22 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapte
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, country := range subkeys {
|
||||
rule, err = RC.NewGEOSITE(country, adapterName)
|
||||
matcher, err = RC.NewGEOSITE(country, adapterName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domainRules = append(domainRules, rule)
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
} else if strings.Contains(domainLower, "rule-set:") {
|
||||
subkeys := strings.Split(domain, ":")
|
||||
subkeys = subkeys[1:]
|
||||
subkeys = strings.Split(subkeys[0], ",")
|
||||
for _, domainSetName := range subkeys {
|
||||
rule, err = parseDomainRuleSet(domainSetName, adapterName, ruleProviders)
|
||||
matcher, err = parseDomainRuleSet(domainSetName, adapterName, ruleProviders)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
domainRules = append(domainRules, rule)
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
} else {
|
||||
if domainTrie == nil {
|
||||
@@ -1785,13 +1784,13 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapte
|
||||
}
|
||||
}
|
||||
if !domainTrie.IsEmpty() {
|
||||
rule = RP.NewDomainSet(domainTrie.NewDomainSet(), adapterName)
|
||||
domainRules = append(domainRules, rule)
|
||||
matcher = domainTrie.NewDomainSet()
|
||||
matchers = append(matchers, matcher)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func parseIPRuleSet(domainSetName string, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (C.Rule, error) {
|
||||
func parseIPRuleSet(domainSetName string, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (C.IpMatcher, error) {
|
||||
if rp, ok := ruleProviders[domainSetName]; !ok {
|
||||
return nil, fmt.Errorf("not found rule-set: %s", domainSetName)
|
||||
} else {
|
||||
@@ -1806,7 +1805,7 @@ func parseIPRuleSet(domainSetName string, adapterName string, ruleProviders map[
|
||||
return RP.NewRuleSet(domainSetName, adapterName, true)
|
||||
}
|
||||
|
||||
func parseDomainRuleSet(domainSetName string, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (C.Rule, error) {
|
||||
func parseDomainRuleSet(domainSetName string, adapterName string, ruleProviders map[string]providerTypes.RuleProvider) (C.DomainMatcher, error) {
|
||||
if rp, ok := ruleProviders[domainSetName]; !ok {
|
||||
return nil, fmt.Errorf("not found rule-set: %s", domainSetName)
|
||||
} else {
|
||||
|
11
mihomo/constant/matcher.go
Normal file
11
mihomo/constant/matcher.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package constant
|
||||
|
||||
import "net/netip"
|
||||
|
||||
type DomainMatcher interface {
|
||||
MatchDomain(domain string) bool
|
||||
}
|
||||
|
||||
type IpMatcher interface {
|
||||
MatchIp(ip netip.Addr) bool
|
||||
}
|
@@ -133,7 +133,9 @@ type Metadata struct {
|
||||
Type Type `json:"type"`
|
||||
SrcIP netip.Addr `json:"sourceIP"`
|
||||
DstIP netip.Addr `json:"destinationIP"`
|
||||
SrcGeoIP []string `json:"sourceGeoIP"` // can be nil if never queried, empty slice if got no result
|
||||
DstGeoIP []string `json:"destinationGeoIP"` // can be nil if never queried, empty slice if got no result
|
||||
SrcIPASN string `json:"sourceIPASN"`
|
||||
DstIPASN string `json:"destinationIPASN"`
|
||||
SrcPort uint16 `json:"sourcePort,string"` // `,string` is used to compatible with old version json output
|
||||
DstPort uint16 `json:"destinationPort,string"` // `,string` is used to compatible with old version json output
|
||||
|
@@ -27,8 +27,6 @@ const (
|
||||
ProcessNameRegex
|
||||
ProcessPathRegex
|
||||
RuleSet
|
||||
DomainSet
|
||||
IpCidrSet
|
||||
Network
|
||||
Uid
|
||||
SubRules
|
||||
@@ -92,10 +90,6 @@ func (rt RuleType) String() string {
|
||||
return "Match"
|
||||
case RuleSet:
|
||||
return "RuleSet"
|
||||
case DomainSet:
|
||||
return "DomainSet"
|
||||
case IpCidrSet:
|
||||
return "IpCidrSet"
|
||||
case Network:
|
||||
return "Network"
|
||||
case DSCP:
|
||||
|
@@ -21,13 +21,13 @@ func (p domainTriePolicy) Match(domain string) []dnsClient {
|
||||
return nil
|
||||
}
|
||||
|
||||
type domainRulePolicy struct {
|
||||
rule C.Rule
|
||||
type domainMatcherPolicy struct {
|
||||
matcher C.DomainMatcher
|
||||
dnsClients []dnsClient
|
||||
}
|
||||
|
||||
func (p domainRulePolicy) Match(domain string) []dnsClient {
|
||||
if ok, _ := p.rule.Match(&C.Metadata{Host: domain}); ok {
|
||||
func (p domainMatcherPolicy) Match(domain string) []dnsClient {
|
||||
if p.matcher.MatchDomain(domain) {
|
||||
return p.dnsClients
|
||||
}
|
||||
return nil
|
||||
|
@@ -42,8 +42,8 @@ type Resolver struct {
|
||||
hosts *trie.DomainTrie[resolver.HostValue]
|
||||
main []dnsClient
|
||||
fallback []dnsClient
|
||||
fallbackDomainFilters []C.Rule
|
||||
fallbackIPFilters []C.Rule
|
||||
fallbackDomainFilters []C.DomainMatcher
|
||||
fallbackIPFilters []C.IpMatcher
|
||||
group singleflight.Group[*D.Msg]
|
||||
cache dnsCache
|
||||
policy []dnsPolicy
|
||||
@@ -119,7 +119,7 @@ func (r *Resolver) LookupIPv6(ctx context.Context, host string) ([]netip.Addr, e
|
||||
|
||||
func (r *Resolver) shouldIPFallback(ip netip.Addr) bool {
|
||||
for _, filter := range r.fallbackIPFilters {
|
||||
if ok, _ := filter.Match(&C.Metadata{DstIP: ip}); ok {
|
||||
if filter.MatchIp(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -275,7 +275,7 @@ func (r *Resolver) shouldOnlyQueryFallback(m *D.Msg) bool {
|
||||
}
|
||||
|
||||
for _, df := range r.fallbackDomainFilters {
|
||||
if ok, _ := df.Match(&C.Metadata{Host: domain}); ok {
|
||||
if df.MatchDomain(domain) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -398,7 +398,7 @@ func (ns NameServer) Equal(ns2 NameServer) bool {
|
||||
|
||||
type Policy struct {
|
||||
Domain string
|
||||
Rule C.Rule
|
||||
Matcher C.DomainMatcher
|
||||
NameServers []NameServer
|
||||
}
|
||||
|
||||
@@ -409,8 +409,8 @@ type Config struct {
|
||||
IPv6 bool
|
||||
IPv6Timeout uint
|
||||
EnhancedMode C.DNSMode
|
||||
FallbackIPFilter []C.Rule
|
||||
FallbackDomainFilter []C.Rule
|
||||
FallbackIPFilter []C.IpMatcher
|
||||
FallbackDomainFilter []C.DomainMatcher
|
||||
Pool *fakeip.Pool
|
||||
Hosts *trie.DomainTrie[resolver.HostValue]
|
||||
Policy []Policy
|
||||
@@ -495,8 +495,8 @@ func NewResolver(config Config) *Resolver {
|
||||
}
|
||||
|
||||
for _, policy := range config.Policy {
|
||||
if policy.Rule != nil {
|
||||
insertPolicy(domainRulePolicy{rule: policy.Rule, dnsClients: cacheTransform(policy.NameServers)})
|
||||
if policy.Matcher != nil {
|
||||
insertPolicy(domainMatcherPolicy{matcher: policy.Matcher, dnsClients: cacheTransform(policy.NameServers)})
|
||||
} else {
|
||||
if triePolicy == nil {
|
||||
triePolicy = trie.New[[]dnsClient]()
|
||||
|
@@ -3,6 +3,7 @@ package common
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"strings"
|
||||
|
||||
"github.com/metacubex/mihomo/component/geodata"
|
||||
@@ -11,6 +12,8 @@ import (
|
||||
"github.com/metacubex/mihomo/component/resolver"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
"github.com/metacubex/mihomo/log"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
type GEOIP struct {
|
||||
@@ -41,52 +44,84 @@ func (g *GEOIP) Match(metadata *C.Metadata) (bool, string) {
|
||||
}
|
||||
|
||||
if g.country == "lan" {
|
||||
return ip.IsPrivate() ||
|
||||
ip.IsUnspecified() ||
|
||||
ip.IsLoopback() ||
|
||||
ip.IsMulticast() ||
|
||||
ip.IsLinkLocalUnicast() ||
|
||||
resolver.IsFakeBroadcastIP(ip), g.adapter
|
||||
return g.isLan(ip), g.adapter
|
||||
}
|
||||
|
||||
for _, code := range metadata.DstGeoIP {
|
||||
if g.country == code {
|
||||
return true, g.adapter
|
||||
}
|
||||
}
|
||||
|
||||
if !C.GeodataMode {
|
||||
if C.GeodataMode {
|
||||
if g.isSourceIP {
|
||||
codes := mmdb.IPInstance().LookupCode(ip.AsSlice())
|
||||
for _, code := range codes {
|
||||
if g.country == code {
|
||||
return true, g.adapter
|
||||
}
|
||||
if slices.Contains(metadata.SrcGeoIP, g.country) {
|
||||
return true, g.adapter
|
||||
}
|
||||
return false, g.adapter
|
||||
}
|
||||
|
||||
if metadata.DstGeoIP != nil {
|
||||
return false, g.adapter
|
||||
}
|
||||
metadata.DstGeoIP = mmdb.IPInstance().LookupCode(ip.AsSlice())
|
||||
for _, code := range metadata.DstGeoIP {
|
||||
if g.country == code {
|
||||
} else {
|
||||
if slices.Contains(metadata.DstGeoIP, g.country) {
|
||||
return true, g.adapter
|
||||
}
|
||||
}
|
||||
return false, g.adapter
|
||||
matcher, err := g.getIPMatcher()
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
match := matcher.Match(ip)
|
||||
if match {
|
||||
if g.isSourceIP {
|
||||
metadata.SrcGeoIP = append(metadata.SrcGeoIP, g.country)
|
||||
} else {
|
||||
metadata.DstGeoIP = append(metadata.DstGeoIP, g.country)
|
||||
}
|
||||
}
|
||||
return match, g.adapter
|
||||
}
|
||||
|
||||
matcher, err := g.GetIPMatcher()
|
||||
if err != nil {
|
||||
return false, ""
|
||||
if g.isSourceIP {
|
||||
if metadata.SrcGeoIP != nil {
|
||||
return slices.Contains(metadata.SrcGeoIP, g.country), g.adapter
|
||||
}
|
||||
} else {
|
||||
if metadata.DstGeoIP != nil {
|
||||
return slices.Contains(metadata.DstGeoIP, g.country), g.adapter
|
||||
}
|
||||
}
|
||||
match := matcher.Match(ip)
|
||||
if match && !g.isSourceIP {
|
||||
metadata.DstGeoIP = append(metadata.DstGeoIP, g.country)
|
||||
codes := mmdb.IPInstance().LookupCode(ip.AsSlice())
|
||||
if g.isSourceIP {
|
||||
metadata.SrcGeoIP = codes
|
||||
} else {
|
||||
metadata.DstGeoIP = codes
|
||||
}
|
||||
return match, g.adapter
|
||||
if slices.Contains(codes, g.country) {
|
||||
return true, g.adapter
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// MatchIp implements C.IpMatcher
|
||||
func (g *GEOIP) MatchIp(ip netip.Addr) bool {
|
||||
if !ip.IsValid() {
|
||||
return false
|
||||
}
|
||||
|
||||
if g.country == "lan" {
|
||||
return g.isLan(ip)
|
||||
}
|
||||
|
||||
if C.GeodataMode {
|
||||
matcher, err := g.getIPMatcher()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return matcher.Match(ip)
|
||||
}
|
||||
|
||||
codes := mmdb.IPInstance().LookupCode(ip.AsSlice())
|
||||
return slices.Contains(codes, g.country)
|
||||
}
|
||||
|
||||
func (g *GEOIP) isLan(ip netip.Addr) bool {
|
||||
return ip.IsPrivate() ||
|
||||
ip.IsUnspecified() ||
|
||||
ip.IsLoopback() ||
|
||||
ip.IsMulticast() ||
|
||||
ip.IsLinkLocalUnicast() ||
|
||||
resolver.IsFakeBroadcastIP(ip)
|
||||
}
|
||||
|
||||
func (g *GEOIP) Adapter() string {
|
||||
@@ -106,14 +141,19 @@ func (g *GEOIP) GetCountry() string {
|
||||
}
|
||||
|
||||
func (g *GEOIP) GetIPMatcher() (router.IPMatcher, error) {
|
||||
if g.geodata {
|
||||
geoIPMatcher, err := geodata.LoadGeoIPMatcher(g.country)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[GeoIP] %w", err)
|
||||
}
|
||||
return geoIPMatcher, nil
|
||||
if C.GeodataMode {
|
||||
return g.getIPMatcher()
|
||||
}
|
||||
return nil, errors.New("geoip country not set")
|
||||
return nil, errors.New("not geodata mode")
|
||||
}
|
||||
|
||||
func (g *GEOIP) getIPMatcher() (router.IPMatcher, error) {
|
||||
geoIPMatcher, err := geodata.LoadGeoIPMatcher(g.country)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[GeoIP] %w", err)
|
||||
}
|
||||
return geoIPMatcher, nil
|
||||
|
||||
}
|
||||
|
||||
func (g *GEOIP) GetRecodeSize() int {
|
||||
@@ -141,12 +181,13 @@ func NewGEOIP(country string, adapter string, isSrc, noResolveIP bool) (*GEOIP,
|
||||
return geoip, nil
|
||||
}
|
||||
|
||||
geoip.geodata = true
|
||||
geoIPMatcher, err := geoip.GetIPMatcher() // test load
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if C.GeodataMode {
|
||||
geoIPMatcher, err := geoip.getIPMatcher() // test load
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Infoln("Finished initial GeoIP rule %s => %s, records: %d", country, adapter, geoIPMatcher.Count())
|
||||
}
|
||||
|
||||
log.Infoln("Finished initial GeoIP rule %s => %s, records: %d", country, adapter, geoIPMatcher.Count())
|
||||
return geoip, nil
|
||||
}
|
||||
|
@@ -23,15 +23,19 @@ func (gs *GEOSITE) RuleType() C.RuleType {
|
||||
}
|
||||
|
||||
func (gs *GEOSITE) Match(metadata *C.Metadata) (bool, string) {
|
||||
domain := metadata.RuleHost()
|
||||
return gs.MatchDomain(metadata.RuleHost()), gs.adapter
|
||||
}
|
||||
|
||||
// MatchDomain implements C.DomainMatcher
|
||||
func (gs *GEOSITE) MatchDomain(domain string) bool {
|
||||
if len(domain) == 0 {
|
||||
return false, ""
|
||||
return false
|
||||
}
|
||||
matcher, err := gs.GetDomainMatcher()
|
||||
if err != nil {
|
||||
return false, ""
|
||||
return false
|
||||
}
|
||||
return matcher.ApplyDomain(domain), gs.adapter
|
||||
return matcher.ApplyDomain(domain)
|
||||
}
|
||||
|
||||
func (gs *GEOSITE) Adapter() string {
|
||||
|
@@ -28,8 +28,11 @@ func (a *ASN) Match(metadata *C.Metadata) (bool, string) {
|
||||
|
||||
result := mmdb.ASNInstance().LookupASN(ip.AsSlice())
|
||||
asnNumber := strconv.FormatUint(uint64(result.AutonomousSystemNumber), 10)
|
||||
if !a.isSourceIP {
|
||||
metadata.DstIPASN = asnNumber + " " + result.AutonomousSystemOrganization
|
||||
ipASN := asnNumber + " " + result.AutonomousSystemOrganization
|
||||
if a.isSourceIP {
|
||||
metadata.SrcIPASN = ipASN
|
||||
} else {
|
||||
metadata.DstIPASN = ipASN
|
||||
}
|
||||
|
||||
match := a.asn == asnNumber
|
||||
|
@@ -1,40 +0,0 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"github.com/metacubex/mihomo/component/trie"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
)
|
||||
|
||||
type DomainSet struct {
|
||||
*domainStrategy
|
||||
adapter string
|
||||
}
|
||||
|
||||
func (d *DomainSet) ProviderNames() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DomainSet) RuleType() C.RuleType {
|
||||
return C.DomainSet
|
||||
}
|
||||
|
||||
func (d *DomainSet) Match(metadata *C.Metadata) (bool, string) {
|
||||
return d.domainStrategy.Match(metadata), d.adapter
|
||||
}
|
||||
|
||||
func (d *DomainSet) Adapter() string {
|
||||
return d.adapter
|
||||
}
|
||||
|
||||
func (d *DomainSet) Payload() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func NewDomainSet(domainSet *trie.DomainSet, adapter string) *DomainSet {
|
||||
return &DomainSet{
|
||||
domainStrategy: &domainStrategy{domainSet: domainSet},
|
||||
adapter: adapter,
|
||||
}
|
||||
}
|
||||
|
||||
var _ C.Rule = (*DomainSet)(nil)
|
@@ -1,40 +0,0 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"github.com/metacubex/mihomo/component/cidr"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
)
|
||||
|
||||
type IpCidrSet struct {
|
||||
*ipcidrStrategy
|
||||
adapter string
|
||||
}
|
||||
|
||||
func (d *IpCidrSet) ProviderNames() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *IpCidrSet) RuleType() C.RuleType {
|
||||
return C.IpCidrSet
|
||||
}
|
||||
|
||||
func (d *IpCidrSet) Match(metadata *C.Metadata) (bool, string) {
|
||||
return d.ipcidrStrategy.Match(metadata), d.adapter
|
||||
}
|
||||
|
||||
func (d *IpCidrSet) Adapter() string {
|
||||
return d.adapter
|
||||
}
|
||||
|
||||
func (d *IpCidrSet) Payload() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func NewIpCidrSet(cidrSet *cidr.IpCidrSet, adapter string) *IpCidrSet {
|
||||
return &IpCidrSet{
|
||||
ipcidrStrategy: &ipcidrStrategy{cidrSet: cidrSet},
|
||||
adapter: adapter,
|
||||
}
|
||||
}
|
||||
|
||||
var _ C.Rule = (*IpCidrSet)(nil)
|
@@ -1,6 +1,8 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"net/netip"
|
||||
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
P "github.com/metacubex/mihomo/constant/provider"
|
||||
"github.com/metacubex/mihomo/rules/common"
|
||||
@@ -35,6 +37,18 @@ func (rs *RuleSet) Match(metadata *C.Metadata) (bool, string) {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// MatchDomain implements C.DomainMatcher
|
||||
func (rs *RuleSet) MatchDomain(domain string) bool {
|
||||
ok, _ := rs.Match(&C.Metadata{Host: domain})
|
||||
return ok
|
||||
}
|
||||
|
||||
// MatchIp implements C.IpMatcher
|
||||
func (rs *RuleSet) MatchIp(ip netip.Addr) bool {
|
||||
ok, _ := rs.Match(&C.Metadata{DstIP: ip})
|
||||
return ok
|
||||
}
|
||||
|
||||
func (rs *RuleSet) Adapter() string {
|
||||
return rs.adapter
|
||||
}
|
||||
|
@@ -1,12 +1,17 @@
|
||||
version: 2
|
||||
version: 2.1
|
||||
|
||||
orbs:
|
||||
android: circleci/android@2.3.0
|
||||
|
||||
jobs:
|
||||
build:
|
||||
working_directory: ~/code
|
||||
docker:
|
||||
- image: cimg/android:2022.12.1-ndk
|
||||
executor:
|
||||
name: android/android-docker
|
||||
tag: 2024.08.1-ndk
|
||||
resource-class: large
|
||||
environment:
|
||||
GRADLE_OPTS: -Dorg.gradle.workers.max=1 -Dorg.gradle.daemon=false -Dkotlin.compiler.execution.strategy="in-process"
|
||||
RUST_VERSION: 1.67.0
|
||||
RUST_VERSION: 1.80.0
|
||||
steps:
|
||||
- checkout
|
||||
- run: git submodule update --init --recursive
|
||||
@@ -16,16 +21,11 @@ jobs:
|
||||
command: |
|
||||
echo 'export PATH="$HOME"/.cargo/bin:"$PATH"' >> "$BASH_ENV"
|
||||
- run: rustup target add armv7-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android
|
||||
- restore_cache:
|
||||
key: jars-{{ checksum "build.gradle.kts" }}
|
||||
- android/restore-gradle-cache
|
||||
- run:
|
||||
name: Run Build and Tests
|
||||
command: ./gradlew assembleDebug check -PCARGO_PROFILE=debug
|
||||
- save_cache:
|
||||
paths:
|
||||
- ~/.gradle
|
||||
- ~/.android/build-cache
|
||||
key: jars-{{ checksum "build.gradle.kts" }}
|
||||
- android/save-gradle-cache
|
||||
- store_artifacts:
|
||||
path: mobile/build/outputs/apk
|
||||
destination: apk/mobile
|
||||
@@ -44,3 +44,8 @@ jobs:
|
||||
- store_artifacts:
|
||||
path: tv/build/reports
|
||||
destination: reports/tv
|
||||
|
||||
workflows:
|
||||
test:
|
||||
jobs:
|
||||
- build
|
||||
|
@@ -1,7 +1,8 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
plugins {
|
||||
id("com.github.ben-manes.versions") version "0.45.0"
|
||||
id("com.github.ben-manes.versions") version "0.51.0"
|
||||
id("com.google.devtools.ksp") version "2.0.20-1.0.24" apply false
|
||||
}
|
||||
|
||||
buildscript {
|
||||
@@ -18,11 +19,11 @@ buildscript {
|
||||
classpath(rootProject.extra["androidPlugin"].toString())
|
||||
classpath(kotlin("gradle-plugin", kotlinVersion))
|
||||
classpath("com.google.android.gms:oss-licenses-plugin:0.10.6")
|
||||
classpath("com.google.firebase:firebase-crashlytics-gradle:2.9.2")
|
||||
classpath("com.google.gms:google-services:4.3.15")
|
||||
classpath("com.vanniktech:gradle-maven-publish-plugin:0.24.0")
|
||||
classpath("org.jetbrains.dokka:dokka-gradle-plugin:1.7.20")
|
||||
classpath("org.mozilla.rust-android-gradle:plugin:0.9.3")
|
||||
classpath("com.google.firebase:firebase-crashlytics-gradle:3.0.2")
|
||||
classpath("com.google.gms:google-services:4.4.2")
|
||||
classpath("com.vanniktech:gradle-maven-publish-plugin:0.29.0")
|
||||
classpath("org.jetbrains.dokka:dokka-gradle-plugin:1.9.20")
|
||||
classpath("org.mozilla.rust-android-gradle:plugin:0.9.4")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,10 +31,6 @@ allprojects {
|
||||
apply(from = "${rootProject.projectDir}/repositories.gradle.kts")
|
||||
}
|
||||
|
||||
tasks.register<Delete>("clean") {
|
||||
delete(rootProject.buildDir)
|
||||
}
|
||||
|
||||
// skip uploading the mapping to Crashlytics
|
||||
subprojects {
|
||||
tasks.whenTaskAdded {
|
||||
|
@@ -1,39 +1,34 @@
|
||||
|
||||
import com.android.build.VariantOutput
|
||||
import com.android.build.api.dsl.CommonExtension
|
||||
import com.android.build.gradle.AbstractAppExtension
|
||||
import com.android.build.gradle.BaseExtension
|
||||
import com.android.build.gradle.internal.api.ApkVariantOutputImpl
|
||||
import org.gradle.api.JavaVersion
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.ExtensionAware
|
||||
import org.gradle.kotlin.dsl.dependencies
|
||||
import org.gradle.kotlin.dsl.getByName
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
|
||||
import java.util.*
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
|
||||
import java.util.Locale
|
||||
|
||||
const val lifecycleVersion = "2.5.1"
|
||||
const val lifecycleVersion = "2.8.4"
|
||||
|
||||
private val Project.android get() = extensions.getByName<BaseExtension>("android")
|
||||
private val BaseExtension.lint get() = (this as CommonExtension<*, *, *, *>).lint
|
||||
private val BaseExtension.lint get() = (this as CommonExtension<*, *, *, *, *, *>).lint
|
||||
|
||||
private val flavorRegex = "(assemble|generate)\\w*(Release|Debug)".toRegex()
|
||||
val Project.currentFlavor get() = gradle.startParameter.taskRequests.toString().let { task ->
|
||||
flavorRegex.find(task)?.groupValues?.get(2)?.toLowerCase(Locale.ROOT) ?: "debug".also {
|
||||
flavorRegex.find(task)?.groupValues?.get(2)?.lowercase(Locale.ROOT) ?: "debug".also {
|
||||
println("Warning: No match found for $task")
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.setupCommon() {
|
||||
val javaVersion = JavaVersion.VERSION_11
|
||||
android.apply {
|
||||
buildToolsVersion("33.0.1")
|
||||
compileSdkVersion(33)
|
||||
compileSdkVersion(34)
|
||||
defaultConfig {
|
||||
minSdk = 23
|
||||
targetSdk = 33
|
||||
targetSdk = 34
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
val javaVersion = JavaVersion.VERSION_11
|
||||
compileOptions {
|
||||
sourceCompatibility = javaVersion
|
||||
targetCompatibility = javaVersion
|
||||
@@ -44,14 +39,14 @@ fun Project.setupCommon() {
|
||||
informational += "MissingQuantity"
|
||||
informational += "MissingTranslation"
|
||||
}
|
||||
(this as ExtensionAware).extensions.getByName<KotlinJvmOptions>("kotlinOptions").jvmTarget =
|
||||
javaVersion.toString()
|
||||
}
|
||||
extensions.getByName<KotlinAndroidProjectExtension>("kotlin").compilerOptions.jvmTarget
|
||||
.set(JvmTarget.fromTarget(javaVersion.toString()))
|
||||
|
||||
dependencies {
|
||||
add("testImplementation", "junit:junit:4.13.2")
|
||||
add("androidTestImplementation", "androidx.test:runner:1.5.2")
|
||||
add("androidTestImplementation", "androidx.test.espresso:espresso-core:3.5.1")
|
||||
add("androidTestImplementation", "androidx.test:runner:1.6.2")
|
||||
add("androidTestImplementation", "androidx.test.espresso:espresso-core:3.6.1")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,11 +64,11 @@ fun Project.setupCore() {
|
||||
disable += "UseAppTint"
|
||||
}
|
||||
ndkVersion = "27.0.12077973"
|
||||
buildFeatures.buildConfig = true
|
||||
}
|
||||
dependencies.add("coreLibraryDesugaring", "com.android.tools:desugar_jdk_libs:2.0.2")
|
||||
dependencies.add("coreLibraryDesugaring", "com.android.tools:desugar_jdk_libs:2.1.0")
|
||||
}
|
||||
|
||||
private val abiCodes = mapOf("armeabi-v7a" to 1, "arm64-v8a" to 2, "x86" to 3, "x86_64" to 4)
|
||||
fun Project.setupApp() {
|
||||
setupCore()
|
||||
|
||||
@@ -111,12 +106,4 @@ fun Project.setupApp() {
|
||||
}
|
||||
|
||||
dependencies.add("implementation", project(":core"))
|
||||
|
||||
if (currentFlavor == "release") (android as AbstractAppExtension).applicationVariants.all {
|
||||
for (output in outputs) {
|
||||
abiCodes[(output as ApkVariantOutputImpl).getFilter(VariantOutput.ABI)]?.let { offset ->
|
||||
output.versionCodeOverride = versionCode + offset
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,9 +2,9 @@ import com.android.build.gradle.internal.tasks.factory.dependsOn
|
||||
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("com.google.devtools.ksp")
|
||||
id("org.mozilla.rust-android-gradle.rust-android")
|
||||
kotlin("android")
|
||||
kotlin("kapt")
|
||||
id("kotlin-parcelize")
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ android {
|
||||
arguments("-j${Runtime.getRuntime().availableProcessors()}")
|
||||
}
|
||||
|
||||
kapt.arguments {
|
||||
arg("room.incremental", true)
|
||||
ksp {
|
||||
arg("room.incremental", "true")
|
||||
arg("room.schemaLocation", "$projectDir/schemas")
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,8 @@ android {
|
||||
sourceSets.getByName("androidTest") {
|
||||
assets.setSrcDirs(assets.srcDirs + files("$projectDir/schemas"))
|
||||
}
|
||||
|
||||
buildFeatures.aidl = true
|
||||
}
|
||||
|
||||
cargo {
|
||||
@@ -51,13 +53,13 @@ cargo {
|
||||
exec = { spec, toolchain ->
|
||||
run {
|
||||
try {
|
||||
Runtime.getRuntime().exec("python3 -V >/dev/null 2>&1")
|
||||
Runtime.getRuntime().exec(arrayOf("python3", "-V"))
|
||||
spec.environment("RUST_ANDROID_GRADLE_PYTHON_COMMAND", "python3")
|
||||
project.logger.lifecycle("Python 3 detected.")
|
||||
} catch (e: java.io.IOException) {
|
||||
project.logger.lifecycle("No python 3 detected.")
|
||||
try {
|
||||
Runtime.getRuntime().exec("python -V >/dev/null 2>&1")
|
||||
Runtime.getRuntime().exec(arrayOf("python", "-V"))
|
||||
spec.environment("RUST_ANDROID_GRADLE_PYTHON_COMMAND", "python")
|
||||
project.logger.lifecycle("Python detected.")
|
||||
} catch (e: java.io.IOException) {
|
||||
@@ -84,28 +86,28 @@ tasks.register<Exec>("cargoClean") {
|
||||
tasks.clean.dependsOn("cargoClean")
|
||||
|
||||
dependencies {
|
||||
val coroutinesVersion = "1.6.4"
|
||||
val roomVersion = "2.5.0"
|
||||
val workVersion = "2.7.1"
|
||||
val coroutinesVersion = "1.8.1"
|
||||
val roomVersion = "2.6.1"
|
||||
val workVersion = "2.9.1"
|
||||
|
||||
api(project(":plugin"))
|
||||
api("androidx.core:core-ktx:1.9.0")
|
||||
api("com.google.android.material:material:1.8.0")
|
||||
api("androidx.core:core-ktx:1.13.1")
|
||||
api("com.google.android.material:material:1.12.0")
|
||||
|
||||
api("androidx.lifecycle:lifecycle-livedata-core-ktx:$lifecycleVersion")
|
||||
api("androidx.preference:preference:1.2.0")
|
||||
api("androidx.preference:preference:1.2.1")
|
||||
api("androidx.room:room-runtime:$roomVersion")
|
||||
api("androidx.work:work-multiprocess:$workVersion")
|
||||
api("androidx.work:work-runtime-ktx:$workVersion")
|
||||
api("com.google.android.gms:play-services-oss-licenses:17.0.0")
|
||||
api("com.google.code.gson:gson:2.10.1")
|
||||
api("com.google.firebase:firebase-analytics-ktx:21.2.0")
|
||||
api("com.google.firebase:firebase-crashlytics:18.3.3")
|
||||
api("com.google.android.gms:play-services-oss-licenses:17.1.0")
|
||||
api("com.google.code.gson:gson:2.11.0")
|
||||
api("com.google.firebase:firebase-analytics-ktx:22.1.0")
|
||||
api("com.google.firebase:firebase-crashlytics:19.0.3")
|
||||
api("com.jakewharton.timber:timber:5.0.1")
|
||||
api("dnsjava:dnsjava:3.5.2")
|
||||
api("dnsjava:dnsjava:3.6.1")
|
||||
api("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion")
|
||||
api("org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutinesVersion")
|
||||
kapt("androidx.room:room-compiler:$roomVersion")
|
||||
ksp("androidx.room:room-compiler:$roomVersion")
|
||||
androidTestImplementation("androidx.room:room-testing:$roomVersion")
|
||||
androidTestImplementation("androidx.test.ext:junit-ktx:1.1.5")
|
||||
androidTestImplementation("androidx.test.ext:junit-ktx:1.2.1")
|
||||
}
|
||||
|
5
shadowsocks-android/core/proguard-rules.pro
vendored
5
shadowsocks-android/core/proguard-rules.pro
vendored
@@ -17,6 +17,11 @@
|
||||
-keepattributes SourceFile,LineNumberTable
|
||||
-dontobfuscate
|
||||
|
||||
-dontwarn lombok.Generated
|
||||
-dontwarn org.slf4j.impl.StaticLoggerBinder
|
||||
-dontwarn org.xbill.DNS.spi.DnsjavaInetAddressResolverProvider
|
||||
-dontwarn sun.net.spi.nameservice.NameServiceDescriptor
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
@@ -5,6 +5,8 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
@@ -27,7 +29,6 @@
|
||||
android:fullBackupOnly="true"
|
||||
android:hasFragileUserData="true"
|
||||
android:label="@string/app_name"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
android:supportsRtl="true"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:banner="@mipmap/banner">
|
||||
@@ -43,7 +44,9 @@
|
||||
android:directBootAware="true"
|
||||
android:label="@string/app_name"
|
||||
android:permission="android.permission.BIND_VPN_SERVICE"
|
||||
android:exported="false">
|
||||
android:foregroundServiceType="systemExempted"
|
||||
android:exported="false"
|
||||
tools:ignore="ForegroundServicePermission">
|
||||
<intent-filter>
|
||||
<action android:name="android.net.VpnService"/>
|
||||
</intent-filter>
|
||||
@@ -53,14 +56,22 @@
|
||||
android:name="com.github.shadowsocks.bg.TransproxyService"
|
||||
android:process=":bg"
|
||||
android:directBootAware="true"
|
||||
android:foregroundServiceType="specialUse"
|
||||
android:exported="false">
|
||||
<property
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||
android:value="Proxy service that handles incoming SOCKS5 and Transproxy traffic" />
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name="com.github.shadowsocks.bg.ProxyService"
|
||||
android:process=":bg"
|
||||
android:directBootAware="true"
|
||||
android:foregroundServiceType="specialUse"
|
||||
android:exported="false">
|
||||
<property
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||
android:value="Proxy service that handles incoming SOCKS5 traffic" />
|
||||
</service>
|
||||
|
||||
<service
|
||||
|
@@ -20,9 +20,17 @@
|
||||
|
||||
package com.github.shadowsocks
|
||||
|
||||
import android.app.*
|
||||
import android.app.ActivityManager
|
||||
import android.app.Application
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.admin.DevicePolicyManager
|
||||
import android.content.*
|
||||
import android.content.ClipData
|
||||
import android.content.ClipDescription
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.ConnectivityManager
|
||||
@@ -34,7 +42,6 @@ import androidx.annotation.VisibleForTesting
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.os.persistableBundleOf
|
||||
import androidx.work.Configuration
|
||||
import com.github.shadowsocks.acl.Acl
|
||||
import com.github.shadowsocks.aidl.ShadowsocksConnection
|
||||
import com.github.shadowsocks.core.BuildConfig
|
||||
@@ -47,19 +54,16 @@ import com.github.shadowsocks.utils.Action
|
||||
import com.github.shadowsocks.utils.DeviceStorageApp
|
||||
import com.github.shadowsocks.utils.DirectBoot
|
||||
import com.github.shadowsocks.utils.Key
|
||||
import com.google.firebase.FirebaseApp
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.google.firebase.ktx.Firebase
|
||||
import com.google.firebase.ktx.initialize
|
||||
import kotlinx.coroutines.DEBUG_PROPERTY_NAME
|
||||
import kotlinx.coroutines.DEBUG_PROPERTY_VALUE_ON
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
object Core : Configuration.Provider {
|
||||
object Core {
|
||||
lateinit var app: Application
|
||||
@VisibleForTesting set
|
||||
lateinit var configureIntent: (Context) -> PendingIntent
|
||||
@@ -111,7 +115,7 @@ object Core : Configuration.Provider {
|
||||
|
||||
// overhead of debug mode is minimal: https://github.com/Kotlin/kotlinx.coroutines/blob/f528898/docs/debugging.md#debug-mode
|
||||
System.setProperty(DEBUG_PROPERTY_NAME, DEBUG_PROPERTY_VALUE_ON)
|
||||
Firebase.initialize(deviceStorage) // multiple processes needs manual set-up
|
||||
FirebaseApp.initializeApp(deviceStorage) // multiple processes needs manual set-up
|
||||
Timber.plant(object : Timber.DebugTree() {
|
||||
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
||||
if (t == null) {
|
||||
@@ -142,13 +146,6 @@ object Core : Configuration.Provider {
|
||||
updateNotificationChannels()
|
||||
}
|
||||
|
||||
override fun getWorkManagerConfiguration() = Configuration.Builder().apply {
|
||||
setDefaultProcessName(app.packageName + ":bg")
|
||||
setMinimumLoggingLevel(if (BuildConfig.DEBUG) Log.VERBOSE else Log.INFO)
|
||||
setExecutor { GlobalScope.launch { it.run() } }
|
||||
setTaskExecutor { GlobalScope.launch { it.run() } }
|
||||
}.build()
|
||||
|
||||
fun updateNotificationChannels() {
|
||||
if (Build.VERSION.SDK_INT >= 26) @RequiresApi(26) {
|
||||
notification.createNotificationChannels(listOf(
|
||||
|
@@ -51,6 +51,7 @@ class UrlImportActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
super.onDismiss(dialog)
|
||||
requireActivity().finish()
|
||||
}
|
||||
}
|
||||
|
@@ -22,10 +22,22 @@ package com.github.shadowsocks.acl
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.work.*
|
||||
import android.util.Log
|
||||
import androidx.work.Configuration
|
||||
import androidx.work.Constraints
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.Data
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.NetworkType
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.WorkerParameters
|
||||
import com.github.shadowsocks.Core
|
||||
import com.github.shadowsocks.Core.app
|
||||
import com.github.shadowsocks.core.BuildConfig
|
||||
import com.github.shadowsocks.utils.useCancellable
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import java.io.IOException
|
||||
import java.net.HttpURLConnection
|
||||
@@ -38,16 +50,21 @@ class AclSyncer(context: Context, workerParams: WorkerParameters) : CoroutineWor
|
||||
|
||||
fun schedule(route: String) {
|
||||
if (Build.VERSION.SDK_INT >= 24 && !Core.user.isUserUnlocked) return // work does not support this
|
||||
if (!WorkManager.isInitialized()) WorkManager.initialize(app, Configuration.Builder().apply {
|
||||
setDefaultProcessName(app.packageName + ":bg")
|
||||
setMinimumLoggingLevel(if (BuildConfig.DEBUG) Log.VERBOSE else Log.INFO)
|
||||
setExecutor { GlobalScope.launch { it.run() } }
|
||||
setTaskExecutor { GlobalScope.launch { it.run() } }
|
||||
}.build())
|
||||
WorkManager.getInstance(app).enqueueUniqueWork(
|
||||
route, ExistingWorkPolicy.REPLACE, OneTimeWorkRequestBuilder<AclSyncer>().run {
|
||||
route, ExistingWorkPolicy.REPLACE, OneTimeWorkRequestBuilder<AclSyncer>().apply {
|
||||
setInputData(Data.Builder().putString(KEY_ROUTE, route).build())
|
||||
setConstraints(Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.UNMETERED)
|
||||
.setRequiresCharging(true)
|
||||
.build())
|
||||
setConstraints(Constraints.Builder().apply {
|
||||
setRequiredNetworkType(NetworkType.UNMETERED)
|
||||
setRequiresCharging(true)
|
||||
}.build())
|
||||
setInitialDelay(10, TimeUnit.SECONDS)
|
||||
build()
|
||||
})
|
||||
}.build())
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -70,7 +70,7 @@ class ShadowsocksConnection(private var listenForDeath: Boolean = false) : Servi
|
||||
override fun stateChanged(state: Int, profileName: String?, msg: String?) {
|
||||
val callback = callback ?: return
|
||||
GlobalScope.launch(Dispatchers.Main.immediate) {
|
||||
callback.stateChanged(BaseService.State.values()[state], profileName, msg)
|
||||
callback.stateChanged(BaseService.State.entries[state], profileName, msg)
|
||||
}
|
||||
}
|
||||
override fun trafficUpdated(profileId: Long, stats: TrafficStats) {
|
||||
|
@@ -44,7 +44,7 @@ import com.github.shadowsocks.utils.broadcastReceiver
|
||||
import com.github.shadowsocks.utils.readableMessage
|
||||
import com.google.firebase.analytics.FirebaseAnalytics
|
||||
import com.google.firebase.analytics.ktx.analytics
|
||||
import com.google.firebase.analytics.ktx.logEvent
|
||||
import com.google.firebase.analytics.logEvent
|
||||
import com.google.firebase.ktx.Firebase
|
||||
import kotlinx.coroutines.*
|
||||
import timber.log.Timber
|
||||
|
@@ -85,6 +85,7 @@ class ProxyInstance(val profile: Profile, private val route: String = profile.ro
|
||||
config.put("plugin", path).put("plugin_opts", opts.toString())
|
||||
}
|
||||
config.put("dns", "system")
|
||||
config.put("mode", mode)
|
||||
config.put("locals", JSONArray().apply {
|
||||
// local SOCKS5 proxy
|
||||
put(JSONObject().apply {
|
||||
|
@@ -20,6 +20,7 @@
|
||||
|
||||
package com.github.shadowsocks.bg
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
@@ -79,6 +80,7 @@ class VpnService : BaseVpnService(), BaseService.Interface {
|
||||
network.bindSocket(fd)
|
||||
return@let true
|
||||
} catch (e: IOException) {
|
||||
@SuppressLint("NewApi")
|
||||
when ((e.cause as? ErrnoException)?.errno) {
|
||||
OsConstants.EPERM, OsConstants.EACCES, OsConstants.ENONET -> Timber.d(e)
|
||||
else -> Timber.w(e)
|
||||
@@ -159,7 +161,7 @@ class VpnService : BaseVpnService(), BaseService.Interface {
|
||||
|
||||
override val isVpnService get() = true
|
||||
|
||||
private suspend fun startVpn(): FileDescriptor {
|
||||
private fun startVpn(): FileDescriptor {
|
||||
val profile = data.proxy!!.profile
|
||||
val builder = Builder()
|
||||
.setConfigureIntent(Core.configureIntent(this))
|
||||
|
@@ -92,7 +92,7 @@ data class Profile(
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@TypeConverter
|
||||
fun of(value: Int) = values().single { it.persistedValue == value }
|
||||
fun of(value: Int) = entries.single { it.persistedValue == value }
|
||||
@JvmStatic
|
||||
@TypeConverter
|
||||
fun toInt(status: SubscriptionStatus) = status.persistedValue
|
||||
@@ -199,10 +199,10 @@ data class Profile(
|
||||
remoteDns = json["remote_dns"].optString ?: remoteDns
|
||||
ipv6 = json["ipv6"].optBoolean ?: ipv6
|
||||
metered = json["metered"].optBoolean ?: metered
|
||||
(json["proxy_apps"] as? JsonObject)?.also {
|
||||
proxyApps = it["enabled"].optBoolean ?: proxyApps
|
||||
bypass = it["bypass"].optBoolean ?: bypass
|
||||
individual = (it["android_list"] as? JsonArray)?.asIterable()?.mapNotNull { it.optString }
|
||||
(json["proxy_apps"] as? JsonObject)?.also { obj ->
|
||||
proxyApps = obj["enabled"].optBoolean ?: proxyApps
|
||||
bypass = obj["bypass"].optBoolean ?: bypass
|
||||
individual = (obj["android_list"] as? JsonArray)?.asIterable()?.mapNotNull { it.optString }
|
||||
?.joinToString("\n") ?: individual
|
||||
}
|
||||
udpdns = json["udpdns"].optBoolean ?: udpdns
|
||||
|
@@ -83,7 +83,7 @@ object DefaultNetworkListener {
|
||||
}
|
||||
|
||||
suspend fun start(key: Any, listener: (Network?) -> Unit) = networkActor.send(NetworkMessage.Start(key, listener))
|
||||
suspend fun get() = if (fallback) @TargetApi(23) {
|
||||
suspend fun get() = if (fallback) {
|
||||
Core.connectivity.activeNetwork ?: throw UnknownHostException() // failed to listen, return current if available
|
||||
} else NetworkMessage.Get().run {
|
||||
networkActor.send(this)
|
||||
|
@@ -26,14 +26,26 @@ import android.net.Network
|
||||
import android.os.Build
|
||||
import android.os.CancellationSignal
|
||||
import com.github.shadowsocks.Core
|
||||
import kotlinx.coroutines.*
|
||||
import org.xbill.DNS.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Runnable
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.xbill.DNS.AAAARecord
|
||||
import org.xbill.DNS.ARecord
|
||||
import org.xbill.DNS.DClass
|
||||
import org.xbill.DNS.Flags
|
||||
import org.xbill.DNS.Message
|
||||
import org.xbill.DNS.Name
|
||||
import org.xbill.DNS.Opcode
|
||||
import org.xbill.DNS.PTRRecord
|
||||
import org.xbill.DNS.ReverseMap
|
||||
import org.xbill.DNS.Section
|
||||
import org.xbill.DNS.Type
|
||||
import java.io.IOException
|
||||
import java.net.Inet4Address
|
||||
import java.net.Inet6Address
|
||||
import java.net.InetAddress
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
|
||||
@@ -73,15 +85,14 @@ sealed class DnsResolverCompat {
|
||||
abstract suspend fun resolveRaw(network: Network, query: ByteArray): ByteArray
|
||||
abstract suspend fun resolveRawOnActiveNetwork(query: ByteArray): ByteArray
|
||||
|
||||
private object DnsResolverCompat23 : DnsResolverCompat() {
|
||||
private data object DnsResolverCompat23 : DnsResolverCompat() {
|
||||
/**
|
||||
* This dispatcher is used for noncancellable possibly-forever-blocking operations in network IO.
|
||||
*
|
||||
* See also: https://issuetracker.google.com/issues/133874590
|
||||
*/
|
||||
private val unboundedIO by lazy {
|
||||
if (Core.activity.isLowRamDevice) Dispatchers.IO
|
||||
else Executors.newCachedThreadPool().asCoroutineDispatcher()
|
||||
if (Core.activity.isLowRamDevice) Dispatchers.IO else Dispatchers.IO.limitedParallelism(Int.MAX_VALUE)
|
||||
}
|
||||
|
||||
override suspend fun resolve(network: Network, host: String) =
|
||||
|
@@ -47,10 +47,10 @@ class HttpsTest : ViewModel() {
|
||||
protected abstract val status: CharSequence
|
||||
open fun retrieve(setStatus: (CharSequence) -> Unit, errorCallback: (String) -> Unit) = setStatus(status)
|
||||
|
||||
object Idle : Status() {
|
||||
data object Idle : Status() {
|
||||
override val status get() = app.getText(R.string.vpn_connected)
|
||||
}
|
||||
object Testing : Status() {
|
||||
data object Testing : Status() {
|
||||
override val status get() = app.getText(R.string.connection_test_testing)
|
||||
}
|
||||
class Success(private val elapsed: Long) : Status() {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user