mirror of
https://github.com/anyproto/anytype-heart.git
synced 2025-06-08 05:47:07 +09:00
GO-3886 Merge branch 'release-6' of ssh://github.com/anyproto/anytype-heart into go-3886-add-p2p-restricted-status
# Conflicts: # go.mod # go.sum # pb/commands.pb.go # pb/events.pb.go
This commit is contained in:
commit
2f5ecbb156
13 changed files with 1518 additions and 1141 deletions
|
@ -5,6 +5,7 @@ import (
|
|||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
trace2 "runtime/trace"
|
||||
"strings"
|
||||
|
||||
|
@ -40,9 +41,10 @@ func (s *Service) AccountSelect(ctx context.Context, req *pb.RpcAccountSelectReq
|
|||
return nil, ErrEmptyAccountID
|
||||
}
|
||||
|
||||
s.traceRecorder.start()
|
||||
defer s.traceRecorder.stop()
|
||||
|
||||
if runtime.GOOS != "android" && runtime.GOOS != "ios" {
|
||||
s.traceRecorder.start()
|
||||
defer s.traceRecorder.stop()
|
||||
}
|
||||
s.cancelStartIfInProcess()
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/klauspost/compress/flate"
|
||||
exptrace "golang.org/x/exp/trace"
|
||||
|
||||
"github.com/anyproto/anytype-heart/util/debug"
|
||||
|
@ -91,6 +92,9 @@ type zipFile struct {
|
|||
|
||||
func createZipArchive(w io.Writer, files []zipFile) error {
|
||||
zipw := zip.NewWriter(w)
|
||||
zipw.RegisterCompressor(zip.Deflate, func(w io.Writer) (io.WriteCloser, error) {
|
||||
return flate.NewWriter(w, flate.BestSpeed)
|
||||
})
|
||||
err := func() error {
|
||||
for _, file := range files {
|
||||
f, err := zipw.Create(file.name)
|
||||
|
@ -107,8 +111,8 @@ func createZipArchive(w io.Writer, files []zipFile) error {
|
|||
return errors.Join(err, zipw.Close())
|
||||
}
|
||||
|
||||
func (s *Service) SaveLoginTrace() (string, error) {
|
||||
return s.traceRecorder.save()
|
||||
func (s *Service) SaveLoginTrace(dir string) (string, error) {
|
||||
return s.traceRecorder.save(dir)
|
||||
}
|
||||
|
||||
// traceRecorder is a helper to start and stop flight trace recorder
|
||||
|
@ -118,7 +122,8 @@ type traceRecorder struct {
|
|||
lastRecordedBuf *bytes.Buffer // contains zip archive of trace
|
||||
}
|
||||
|
||||
func (r *traceRecorder) save() (string, error) {
|
||||
// empty dir means use system temp dir
|
||||
func (r *traceRecorder) save(dir string) (string, error) {
|
||||
r.lock.Lock()
|
||||
defer r.lock.Unlock()
|
||||
|
||||
|
@ -138,7 +143,7 @@ func (r *traceRecorder) save() (string, error) {
|
|||
traceReader = buf
|
||||
}
|
||||
|
||||
f, err := os.CreateTemp("", "account-select-trace-*.zip")
|
||||
f, err := os.CreateTemp(dir, "account-select-trace-*.zip")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("create temp file: %w", err)
|
||||
}
|
||||
|
|
|
@ -224,7 +224,7 @@ func (mw *Middleware) DebugRunProfiler(cctx context.Context, req *pb.RpcDebugRun
|
|||
}
|
||||
|
||||
func (mw *Middleware) DebugAccountSelectTrace(cctx context.Context, req *pb.RpcDebugAccountSelectTraceRequest) *pb.RpcDebugAccountSelectTraceResponse {
|
||||
path, err := mw.applicationService.SaveLoginTrace()
|
||||
path, err := mw.applicationService.SaveLoginTrace(req.Dir)
|
||||
if err != nil {
|
||||
return &pb.RpcDebugAccountSelectTraceResponse{
|
||||
Error: &pb.RpcDebugAccountSelectTraceResponseError{
|
||||
|
|
|
@ -9741,6 +9741,11 @@ Get marks list in the selected range in text block.
|
|||
|
||||
|
||||
|
||||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| dir | [string](#string) | | empty means using OS-provided temp dir |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
package addrs
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"github.com/anyproto/anytype-heart/pkg/lib/logging"
|
||||
"github.com/anyproto/anytype-heart/util/slice"
|
||||
)
|
||||
|
||||
var log = logging.Logger("anytype-net")
|
||||
|
||||
type Interface struct {
|
||||
net.Interface
|
||||
Addrs []InterfaceAddr
|
||||
|
@ -20,9 +27,54 @@ type InterfaceAddr struct {
|
|||
Prefix int
|
||||
}
|
||||
|
||||
type NetInterfaceWithAddrCache struct {
|
||||
net.Interface
|
||||
cachedAddrs []net.Addr // ipv4 addresses
|
||||
cachedErr error
|
||||
}
|
||||
type InterfacesAddrs struct {
|
||||
Interfaces []net.Interface
|
||||
Addrs []net.Addr
|
||||
Interfaces []NetInterfaceWithAddrCache
|
||||
Addrs []net.Addr // addrs without attachment to specific interface. Used as a fallback mechanism
|
||||
}
|
||||
|
||||
func WrapInterface(iface net.Interface) NetInterfaceWithAddrCache {
|
||||
return NetInterfaceWithAddrCache{
|
||||
Interface: iface,
|
||||
}
|
||||
}
|
||||
|
||||
func WrapInterfaces(ifaces []net.Interface) []NetInterfaceWithAddrCache {
|
||||
var m = make([]NetInterfaceWithAddrCache, 0, len(ifaces))
|
||||
for i := range ifaces {
|
||||
m = append(m, NetInterfaceWithAddrCache{
|
||||
Interface: ifaces[i],
|
||||
})
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// GetAddr returns ipv4 only addresses for interface or cached one if set
|
||||
func (i NetInterfaceWithAddrCache) GetAddr() []net.Addr {
|
||||
if i.cachedAddrs != nil {
|
||||
return i.cachedAddrs
|
||||
}
|
||||
if i.cachedErr != nil {
|
||||
return nil
|
||||
}
|
||||
i.cachedAddrs, i.cachedErr = i.Interface.Addrs()
|
||||
if i.cachedErr != nil {
|
||||
log.Warn("interface GetAddr error: %v", i.cachedErr)
|
||||
}
|
||||
// filter-out ipv6
|
||||
i.cachedAddrs = slice.Filter(i.cachedAddrs, func(addr net.Addr) bool {
|
||||
if ip, ok := addr.(*net.IPNet); ok {
|
||||
if ip.IP.To4() == nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
return i.cachedAddrs
|
||||
}
|
||||
|
||||
func (i InterfacesAddrs) Equal(other InterfacesAddrs) bool {
|
||||
|
@ -34,35 +86,110 @@ func (i InterfacesAddrs) Equal(other InterfacesAddrs) bool {
|
|||
}
|
||||
myStr := getStrings(i)
|
||||
otherStr := getStrings(other)
|
||||
return slices.Equal(myStr, otherStr)
|
||||
// compare slices without order
|
||||
if !slices.Equal(myStr, otherStr) {
|
||||
log.Debug(fmt.Sprintf("addrs compare: strings mismatch: %v != %v", myStr, otherStr))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var (
|
||||
ifaceRe = regexp.MustCompile(`^([a-z]*?)([0-9]+)$`)
|
||||
ifaceRe = regexp.MustCompile(`^([a-z]*?)([0-9]+)$`)
|
||||
ifaceWindowsRe = regexp.MustCompile(`^(.*?)([0-9]*)$`)
|
||||
|
||||
// ifaceReBusSlot used for prefixBusSlot naming schema used in newer linux distros https://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-net_id.c#n20
|
||||
ifaceReBusSlot = regexp.MustCompile(`^([a-z]*?)p([0-9]+)s([0-9a-f]+)$`)
|
||||
ifaceReBusSlot = regexp.MustCompile(`^(?P<type>enp|eno|ens|enx|wlp|wlx)(?P<bus>[0-9a-fA-F]*)s?(?P<slot>[0-9a-fA-F]*)?$`)
|
||||
)
|
||||
|
||||
func parseInterfaceName(name string) (prefix string, bus int, num int64) {
|
||||
func cleanInterfaceName(name string) (clean string, namingType NamingType) {
|
||||
if strings.HasPrefix(name, "en") ||
|
||||
strings.HasPrefix(name, "wl") ||
|
||||
strings.HasPrefix(name, "eth") {
|
||||
|
||||
lastSymbol := name[len(name)-1]
|
||||
switch NamingType(lastSymbol) {
|
||||
case NamingTypeBusSlot, NamingTypeHotplug, NamingTypeMac, NamingTypeOnboard:
|
||||
return name[0 : len(name)-1], NamingType(lastSymbol)
|
||||
}
|
||||
}
|
||||
|
||||
return name, NamingTypeOld
|
||||
}
|
||||
|
||||
type NamingType string
|
||||
|
||||
const (
|
||||
NamingTypeOld NamingType = ""
|
||||
NamingTypeOnboard NamingType = "o"
|
||||
NamingTypeBusSlot NamingType = "p"
|
||||
NamingTypeMac NamingType = "x"
|
||||
NamingTypeHotplug NamingType = "s"
|
||||
)
|
||||
|
||||
func (n NamingType) Priority() int {
|
||||
switch n {
|
||||
case NamingTypeOld:
|
||||
return 0
|
||||
case NamingTypeOnboard:
|
||||
return 1
|
||||
case NamingTypeBusSlot:
|
||||
return 2
|
||||
case NamingTypeMac:
|
||||
return 3
|
||||
case NamingTypeHotplug:
|
||||
return 4
|
||||
default:
|
||||
return 5
|
||||
}
|
||||
}
|
||||
|
||||
// parseInterfaceName parses interface name and returns prefix, naming type, bus number and slot number
|
||||
// e.g. enp0s3 -> en, NamingTypeBusSlot, 0, 3
|
||||
// bus and slot are interpreted as hex numbers
|
||||
// bus is also used for mac address
|
||||
// in case of enx001122334455 -> en, NamingTypeMac, 0x001122334455, 0
|
||||
func parseInterfaceName(name string) (iface string, namingType NamingType, busNum int64, num int64) {
|
||||
if runtime.GOOS == "windows" {
|
||||
name, num = parseInterfaceWindowsName(name)
|
||||
return
|
||||
}
|
||||
// try new-style naming schema first (enp0s3, wlp2s0, ...)
|
||||
res := ifaceReBusSlot.FindStringSubmatch(name)
|
||||
if len(res) > 0 {
|
||||
if len(res) > 1 {
|
||||
prefix = res[1]
|
||||
}
|
||||
if len(res) > 2 {
|
||||
bus, _ = strconv.Atoi(res[2])
|
||||
}
|
||||
if len(res) > 3 {
|
||||
numHex := res[3]
|
||||
num, _ = strconv.ParseInt(numHex, 16, 32)
|
||||
|
||||
for i, subName := range ifaceReBusSlot.SubexpNames() {
|
||||
if i > 0 && res[i] != "" {
|
||||
switch subName {
|
||||
case "type":
|
||||
iface, namingType = cleanInterfaceName(res[i])
|
||||
case "bus":
|
||||
busNum, _ = strconv.ParseInt(res[i], 16, 64)
|
||||
case "slot": // or mac
|
||||
num, _ = strconv.ParseInt(res[i], 16, 64)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
// try old-style naming schema (eth0, wlan0, ...)
|
||||
res = ifaceRe.FindStringSubmatch(name)
|
||||
if len(res) > 1 {
|
||||
prefix = res[1]
|
||||
iface = res[1]
|
||||
}
|
||||
if len(res) > 2 {
|
||||
num, _ = strconv.ParseInt(res[2], 10, 32)
|
||||
}
|
||||
if iface == "" {
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func parseInterfaceWindowsName(name string) (iface string, num int64) {
|
||||
res := ifaceWindowsRe.FindStringSubmatch(name)
|
||||
if len(res) > 1 {
|
||||
iface = res[1]
|
||||
}
|
||||
if len(res) > 2 {
|
||||
num, _ = strconv.ParseInt(res[2], 10, 32)
|
||||
|
@ -70,42 +197,62 @@ func parseInterfaceName(name string) (prefix string, bus int, num int64) {
|
|||
return
|
||||
}
|
||||
|
||||
func (i InterfacesAddrs) SortWithPriority(priority []string) {
|
||||
less := func(a, b net.Interface) bool {
|
||||
aPrefix, aBus, aNum := parseInterfaceName(a.Name)
|
||||
bPrefix, bBus, bNum := parseInterfaceName(b.Name)
|
||||
type interfaceComparer struct {
|
||||
priority []string
|
||||
}
|
||||
|
||||
aPrioirity := slice.FindPos(priority, aPrefix)
|
||||
bPrioirity := slice.FindPos(priority, bPrefix)
|
||||
func (i interfaceComparer) Compare(a, b string) int {
|
||||
aPrefix, aType, aBus, aNum := parseInterfaceName(a)
|
||||
bPrefix, bType, bBus, bNum := parseInterfaceName(b)
|
||||
|
||||
if aPrefix == bPrefix {
|
||||
return aNum < bNum
|
||||
} else if aPrioirity == -1 && bPrioirity == -1 {
|
||||
// sort alphabetically
|
||||
return aPrefix < bPrefix
|
||||
} else if aPrioirity != -1 && bPrioirity != -1 {
|
||||
// in case we have [eth, wlan]
|
||||
if aPrioirity == bPrioirity {
|
||||
// prioritize eth0 over wlan0
|
||||
return aPrioirity < bPrioirity
|
||||
aPrioirity := slice.FindPos(i.priority, aPrefix)
|
||||
bPrioirity := slice.FindPos(i.priority, bPrefix)
|
||||
|
||||
if aPrioirity != -1 && bPrioirity != -1 || aPrioirity == -1 && bPrioirity == -1 {
|
||||
if aPrefix != bPrefix {
|
||||
if aPrioirity != -1 && bPrioirity != -1 {
|
||||
// prioritize by priority
|
||||
return cmp.Compare(aPrioirity, bPrioirity)
|
||||
} else {
|
||||
// prioritize by prefix
|
||||
return cmp.Compare(aPrefix, bPrefix)
|
||||
}
|
||||
// prioritise wlan1 over eth8
|
||||
if aBus != bBus {
|
||||
return aBus < bBus
|
||||
}
|
||||
return aNum < bNum
|
||||
} else if aPrioirity != -1 {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
if aType != bType {
|
||||
return cmp.Compare(aType.Priority(), bType.Priority())
|
||||
}
|
||||
if aBus != bBus {
|
||||
return cmp.Compare(aBus, bBus)
|
||||
}
|
||||
if aNum != bNum {
|
||||
return cmp.Compare(aNum, bNum)
|
||||
}
|
||||
// shouldn't be a case
|
||||
return cmp.Compare(a, b)
|
||||
}
|
||||
slices.SortFunc(i.Interfaces, func(a, b net.Interface) int {
|
||||
if less(a, b) {
|
||||
return -1
|
||||
}
|
||||
|
||||
if aPrioirity == -1 {
|
||||
return 1
|
||||
})
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
func (i InterfacesAddrs) SortInterfacesWithPriority(priority []string) {
|
||||
sorter := interfaceComparer{priority: priority}
|
||||
|
||||
compare := func(a, b NetInterfaceWithAddrCache) int {
|
||||
return sorter.Compare(a.Name, b.Name)
|
||||
}
|
||||
slices.SortFunc(i.Interfaces, compare)
|
||||
}
|
||||
|
||||
func (i InterfacesAddrs) NetInterfaces() []net.Interface {
|
||||
var s = make([]net.Interface, 0, len(i.Interfaces))
|
||||
for _, iface := range i.Interfaces {
|
||||
s = append(s, iface.Interface)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func getStrings(i InterfacesAddrs) (allStrings []string) {
|
||||
|
@ -118,3 +265,65 @@ func getStrings(i InterfacesAddrs) (allStrings []string) {
|
|||
slices.Sort(allStrings)
|
||||
return
|
||||
}
|
||||
|
||||
func (i InterfacesAddrs) GetInterfaceByAddr(addr net.Addr) (net.Interface, bool) {
|
||||
for _, iface := range i.Interfaces {
|
||||
for _, addrInIface := range iface.GetAddr() {
|
||||
if addr.String() == addrInIface.String() {
|
||||
return iface.Interface, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return net.Interface{}, false
|
||||
}
|
||||
|
||||
// SortIPsLikeInterfaces sort IPs in a way they match sorted interface addresses(via mask matching)
|
||||
// e.g. we have interfaces
|
||||
// - en0: 192.168.1.10/24
|
||||
// - lo0: 127.0.0.1/8
|
||||
// we pass IPs: 10.124.22.1, 127.0.0.1, 192.168.1.25
|
||||
// we will get: 192.168.1.25, 127.0.0.1, 10.124.22.1
|
||||
// 10.124.22.1 does not match any interface, so it will be at the end
|
||||
func (i InterfacesAddrs) SortIPsLikeInterfaces(ips []net.IP) {
|
||||
slices.SortFunc(ips, func(a, b net.IP) int {
|
||||
posA, _ := i.findInterfacePosByIP(a)
|
||||
posB, _ := i.findInterfacePosByIP(b)
|
||||
|
||||
if posA == -1 && posB != -1 {
|
||||
return 1
|
||||
}
|
||||
if posA != -1 && posB == -1 {
|
||||
return -1
|
||||
}
|
||||
if posA < posB {
|
||||
return -1
|
||||
} else if posA > posB {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
})
|
||||
}
|
||||
|
||||
func (i InterfacesAddrs) findInterfacePosByIP(ip net.IP) (pos int, equal bool) {
|
||||
for position, iface := range i.Interfaces {
|
||||
for _, addr := range iface.GetAddr() {
|
||||
if ni, ok := addr.(*net.IPNet); ok {
|
||||
if ni.Contains(ip) {
|
||||
return position, ni.IP.Equal(ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1, false
|
||||
}
|
||||
|
||||
func filterInterfaces(ifaces []NetInterfaceWithAddrCache) []NetInterfaceWithAddrCache {
|
||||
return slice.Filter(ifaces, func(iface NetInterfaceWithAddrCache) bool {
|
||||
if iface.Flags&net.FlagUp != 0 && iface.Flags&net.FlagMulticast != 0 && iface.Flags&net.FlagLoopback == 0 {
|
||||
if len(iface.GetAddr()) > 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
package addrs
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_parseInterfaceName(t *testing.T) {
|
||||
type args struct {
|
||||
|
@ -10,18 +15,27 @@ func Test_parseInterfaceName(t *testing.T) {
|
|||
name string
|
||||
args args
|
||||
wantPrefix string
|
||||
wantBus int
|
||||
wantType NamingType
|
||||
wantBus int64
|
||||
wantNum int64
|
||||
}{
|
||||
{"eth0", args{"eth0"}, "eth", 0, 0},
|
||||
{"eth1", args{"eth1"}, "eth", 0, 1},
|
||||
{"eth10", args{"eth10"}, "eth", 0, 10},
|
||||
{"enp0s10", args{"enp0s10"}, "en", 0, 16},
|
||||
{"wlp0s20f3", args{"wlp0s20f3"}, "wl", 0, 8435},
|
||||
{"eth0", args{"eth0"}, "eth", NamingTypeOld, 0, 0},
|
||||
{"eth1", args{"eth1"}, "eth", NamingTypeOld, 0, 1},
|
||||
{"eth10", args{"eth10"}, "eth", NamingTypeOld, 0, 10},
|
||||
{"enp0s10", args{"enp0s10"}, "en", NamingTypeBusSlot, 0, 0x10},
|
||||
{"wlp0s20f3", args{"wlp0s20f3"}, "wl", NamingTypeBusSlot, 0, 0x20f3},
|
||||
{"tun0", args{"tun0"}, "tun", NamingTypeOld, 0, 0},
|
||||
{"tap0", args{"tap0"}, "tap", NamingTypeOld, 0, 0},
|
||||
{"lo0", args{"lo0"}, "lo", NamingTypeOld, 0, 0},
|
||||
{"lo1", args{"lo1"}, "lo", NamingTypeOld, 0, 1},
|
||||
{"lo10", args{"lo10"}, "lo", NamingTypeOld, 0, 10},
|
||||
{"wlx001122334455", args{"wlx001122334455"}, "wl", NamingTypeMac, 0x001122334455, 0},
|
||||
{"wlxffffffffffff", args{"wlxffffffffffff"}, "wl", NamingTypeMac, 0xffffffffffff, 0},
|
||||
{"eno16777736", args{"eno16777736"}, "en", NamingTypeOnboard, 0x16777736, 0},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotPrefix, gotBus, gotNum := parseInterfaceName(tt.args.name)
|
||||
gotPrefix, gotType, gotBus, gotNum := parseInterfaceName(tt.args.name)
|
||||
if gotPrefix != tt.wantPrefix {
|
||||
t.Errorf("parseInterfaceName() gotPrefix = %v, want %v", gotPrefix, tt.wantPrefix)
|
||||
}
|
||||
|
@ -31,6 +45,54 @@ func Test_parseInterfaceName(t *testing.T) {
|
|||
if gotNum != tt.wantNum {
|
||||
t.Errorf("parseInterfaceName() gotNum = %v, want %v", gotNum, tt.wantNum)
|
||||
}
|
||||
if gotType != tt.wantType {
|
||||
t.Errorf("parseInterfaceName() gotType = %v, want %v", gotType, tt.wantType)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestInterfaceSorterSorting tests sorting a list of interface names using the Compare method.
|
||||
func TestInterfaceSorterSorting(t *testing.T) {
|
||||
sorter := interfaceComparer{
|
||||
priority: []string{"wl", "wlan", "en", "eth", "tun", "tap", "utun"},
|
||||
}
|
||||
|
||||
// List of interfaces to sort
|
||||
interfaces := []string{
|
||||
"tap0",
|
||||
"awdl0",
|
||||
"eth0",
|
||||
"eno1",
|
||||
"wlp2s0",
|
||||
"ens2",
|
||||
"enp0s3",
|
||||
"tun0",
|
||||
"wlan0",
|
||||
"enx001122334455",
|
||||
"wlx001122334455",
|
||||
}
|
||||
|
||||
// Expected order after sorting
|
||||
expected := []string{
|
||||
"wlp2s0", // Wireless LAN on PCI bus
|
||||
"wlx001122334455", // Wireless LAN with MAC address
|
||||
"wlan0", // Old-style Wireless LAN
|
||||
"eno1", // Highest priority (onboard Ethernet)
|
||||
"enp0s3", // PCI bus Ethernet
|
||||
"enx001122334455", // Ethernet with MAC address
|
||||
"ens2", // Hotplug Ethernet
|
||||
"eth0", // Old-style Ethernet
|
||||
"tun0", // VPN TUN interface
|
||||
"tap0", // VPN TAP interface
|
||||
"awdl0",
|
||||
}
|
||||
|
||||
// Sorting the interfaces using the Compare method
|
||||
sort.Slice(interfaces, func(i, j int) bool {
|
||||
return sorter.Compare(interfaces[i], interfaces[j]) < 0
|
||||
})
|
||||
|
||||
// Assert the sorted order matches the expected order
|
||||
assert.Equal(t, expected, interfaces, "The interfaces should be sorted correctly according to priority.")
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@ package addrs
|
|||
import (
|
||||
"net"
|
||||
"slices"
|
||||
|
||||
"github.com/anyproto/anytype-heart/util/slice"
|
||||
)
|
||||
|
||||
func SetInterfaceAddrsGetter(getter InterfaceAddrsGetter) {}
|
||||
|
@ -32,11 +30,7 @@ func GetInterfacesAddrs() (iAddrs InterfacesAddrs, err error) {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
iAddrs.Interfaces = ifaces
|
||||
|
||||
iAddrs.Interfaces = slice.Filter(iAddrs.Interfaces, func(iface net.Interface) bool {
|
||||
return iface.Flags&net.FlagUp != 0 && iface.Flags&net.FlagMulticast != 0
|
||||
})
|
||||
iAddrs.Interfaces = filterInterfaces(WrapInterfaces(ifaces))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -57,8 +57,9 @@ func GetInterfacesAddrs() (addrs InterfacesAddrs, err error) {
|
|||
}
|
||||
lock.Unlock()
|
||||
for _, iface := range interfaceGetter.Interfaces() {
|
||||
addrs.Interfaces = append(addrs.Interfaces, iface.Interface)
|
||||
ifaceWrapped := WrapInterface(iface.Interface)
|
||||
unmaskedAddrs := iface.Addrs
|
||||
ifaceAddrs := make([]net.Addr, 0, len(unmaskedAddrs))
|
||||
for _, addr := range unmaskedAddrs {
|
||||
var mask []byte
|
||||
if len(addr.Ip) == 4 {
|
||||
|
@ -66,11 +67,17 @@ func GetInterfacesAddrs() (addrs InterfacesAddrs, err error) {
|
|||
} else {
|
||||
mask = ipV6MaskFromPrefix(addr.Prefix)
|
||||
}
|
||||
addrs.Addrs = append(addrs.Addrs, &net.IPNet{
|
||||
ifaceAddrs = append(ifaceAddrs, &net.IPNet{
|
||||
IP: addr.Ip,
|
||||
Mask: mask,
|
||||
})
|
||||
}
|
||||
// inject cached addresses, because we can't get them from net.Interface's Addrs() on android
|
||||
ifaceWrapped.cachedAddrs = ifaceAddrs
|
||||
addrs.Addrs = append(addrs.Addrs, ifaceAddrs...)
|
||||
addrs.Interfaces = append(addrs.Interfaces, ifaceWrapped)
|
||||
}
|
||||
|
||||
addrs.Interfaces = filterInterfaces(addrs.Interfaces)
|
||||
return
|
||||
}
|
||||
|
|
2152
pb/commands.pb.go
2152
pb/commands.pb.go
File diff suppressed because it is too large
Load diff
|
@ -6405,6 +6405,7 @@ message Rpc {
|
|||
message AccountSelectTrace {
|
||||
message Request {
|
||||
option (no_auth) = true;
|
||||
string dir = 1; // empty means using OS-provided temp dir
|
||||
}
|
||||
|
||||
message Response {
|
||||
|
|
|
@ -23,10 +23,10 @@ import (
|
|||
"github.com/anyproto/anytype-heart/space/spacecore/clientserver"
|
||||
)
|
||||
|
||||
var interfacesSortPriority = []string{"en", "wlan", "wl", "eth", "lo"}
|
||||
|
||||
type Hook int
|
||||
|
||||
var interfacesSortPriority = []string{"wlan", "wl", "en", "eth", "tun", "tap", "utun", "lo"}
|
||||
|
||||
const (
|
||||
PeerToPeerImpossible Hook = 0
|
||||
PeerToPeerPossible Hook = 1
|
||||
|
@ -70,7 +70,7 @@ func (l *localDiscovery) Init(a *app.App) (err error) {
|
|||
l.manualStart = a.MustComponent(config.CName).(*config.Config).DontStartLocalNetworkSyncAutomatically
|
||||
l.nodeConf = a.MustComponent(config.CName).(*config.Config).GetNodeConf()
|
||||
l.peerId = a.MustComponent(accountservice.CName).(accountservice.Service).Account().PeerId
|
||||
l.periodicCheck = periodicsync.NewPeriodicSync(10, 0, l.checkAddrs, log)
|
||||
l.periodicCheck = periodicsync.NewPeriodicSync(5, 0, l.checkAddrs, log)
|
||||
l.drpcServer = app.MustComponent[clientserver.ClientServer](a)
|
||||
return
|
||||
}
|
||||
|
@ -158,10 +158,11 @@ func (l *localDiscovery) checkAddrs(ctx context.Context) (err error) {
|
|||
newAddrs, err := addrs.GetInterfacesAddrs()
|
||||
l.notifyPeerToPeerStatus(newAddrs)
|
||||
if err != nil {
|
||||
return
|
||||
return fmt.Errorf("getting iface addresses: %w", err)
|
||||
}
|
||||
|
||||
newAddrs.SortWithPriority(interfacesSortPriority)
|
||||
newAddrs.SortInterfacesWithPriority(interfacesSortPriority)
|
||||
|
||||
if newAddrs.Equal(l.interfacesAddrs) && l.server != nil {
|
||||
return
|
||||
}
|
||||
|
@ -174,22 +175,45 @@ func (l *localDiscovery) checkAddrs(ctx context.Context) (err error) {
|
|||
}
|
||||
l.ctx, l.cancel = context.WithCancel(ctx)
|
||||
if err = l.startServer(); err != nil {
|
||||
return
|
||||
return fmt.Errorf("starting mdns server: %w", err)
|
||||
}
|
||||
l.startQuerying(l.ctx)
|
||||
return
|
||||
}
|
||||
|
||||
func (l *localDiscovery) getAddresses() (ipv4, ipv6 []gonet.IP) {
|
||||
for _, iface := range l.interfacesAddrs.Interfaces {
|
||||
for _, addr := range iface.GetAddr() {
|
||||
ip := addr.(*gonet.IPNet).IP
|
||||
if ip.To4() != nil {
|
||||
ipv4 = append(ipv4, ip)
|
||||
} else {
|
||||
ipv6 = append(ipv6, ip)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(ipv4) == 0 {
|
||||
// fallback in case we have no ipv4 addresses from interfaces
|
||||
for _, addr := range l.interfacesAddrs.Addrs {
|
||||
ip := strings.Split(addr.String(), "/")[0]
|
||||
ipVal := gonet.ParseIP(ip)
|
||||
if ipVal.To4() != nil {
|
||||
ipv4 = append(ipv4, ipVal)
|
||||
} else {
|
||||
ipv6 = append(ipv6, ipVal)
|
||||
}
|
||||
}
|
||||
l.interfacesAddrs.SortIPsLikeInterfaces(ipv4)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (l *localDiscovery) startServer() (err error) {
|
||||
l.ipv4 = l.ipv4[:0]
|
||||
l.ipv6 = l.ipv6[:0]
|
||||
for _, addr := range l.interfacesAddrs.Addrs {
|
||||
ip := strings.Split(addr.String(), "/")[0]
|
||||
if gonet.ParseIP(ip).To4() != nil {
|
||||
l.ipv4 = append(l.ipv4, ip)
|
||||
} else {
|
||||
l.ipv6 = append(l.ipv6, ip)
|
||||
}
|
||||
ipv4, _ := l.getAddresses() // ignore ipv6 for now
|
||||
for _, ip := range ipv4 {
|
||||
l.ipv4 = append(l.ipv4, ip.String())
|
||||
}
|
||||
log.Debug("starting mdns server", zap.Strings("ips", l.ipv4), zap.Int("port", l.port), zap.String("peerId", l.peerId))
|
||||
l.server, err = zeroconf.RegisterProxy(
|
||||
|
@ -200,7 +224,7 @@ func (l *localDiscovery) startServer() (err error) {
|
|||
l.peerId,
|
||||
l.ipv4, // do not include ipv6 addresses, because they are disabled
|
||||
nil,
|
||||
l.interfacesAddrs.Interfaces,
|
||||
l.interfacesAddrs.NetInterfaces(),
|
||||
zeroconf.TTL(60),
|
||||
zeroconf.ServerSelectIPTraffic(zeroconf.IPv4), // disable ipv6 for now
|
||||
zeroconf.WriteTimeout(time.Second*1),
|
||||
|
@ -223,6 +247,7 @@ func (l *localDiscovery) readAnswers(ch chan *zeroconf.ServiceEntry) {
|
|||
continue
|
||||
}
|
||||
var portAddrs []string
|
||||
l.interfacesAddrs.SortIPsLikeInterfaces(entry.AddrIPv4)
|
||||
for _, a := range entry.AddrIPv4 {
|
||||
portAddrs = append(portAddrs, fmt.Sprintf("%s:%d", a.String(), entry.Port))
|
||||
}
|
||||
|
@ -248,10 +273,10 @@ func (l *localDiscovery) browse(ctx context.Context, ch chan *zeroconf.ServiceEn
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
newAddrs.SortWithPriority(interfacesSortPriority)
|
||||
newAddrs.SortInterfacesWithPriority(interfacesSortPriority)
|
||||
if err := zeroconf.Browse(ctx, serviceName, mdnsDomain, ch,
|
||||
zeroconf.ClientWriteTimeout(time.Second*1),
|
||||
zeroconf.SelectIfaces(newAddrs.Interfaces),
|
||||
zeroconf.SelectIfaces(newAddrs.NetInterfaces()),
|
||||
zeroconf.SelectIPTraffic(zeroconf.IPv4)); err != nil {
|
||||
log.Error("browsing failed", zap.Error(err))
|
||||
}
|
||||
|
@ -266,7 +291,7 @@ func (l *localDiscovery) notifyPeerToPeerStatus(newAddrs addrs.InterfacesAddrs)
|
|||
}
|
||||
|
||||
func (l *localDiscovery) notifyP2PNotPossible(newAddrs addrs.InterfacesAddrs) bool {
|
||||
return len(newAddrs.Interfaces) == 0 || addrs.IsLoopBack(newAddrs.Interfaces)
|
||||
return len(newAddrs.Interfaces) == 0 || addrs.IsLoopBack(newAddrs.NetInterfaces())
|
||||
}
|
||||
|
||||
func (l *localDiscovery) executeHook(hook Hook) {
|
||||
|
|
|
@ -160,7 +160,7 @@ func (l *localDiscovery) notifyPeerToPeerStatus(newAddrs addrs.InterfacesAddrs)
|
|||
}
|
||||
|
||||
func (l *localDiscovery) notifyP2PNotPossible(newAddrs addrs.InterfacesAddrs) bool {
|
||||
return len(newAddrs.Interfaces) == 0 || IsLoopBack(newAddrs.Interfaces)
|
||||
return len(newAddrs.Interfaces) == 0 || IsLoopBack(newAddrs.NetInterfaces())
|
||||
}
|
||||
|
||||
func IsLoopBack(interfaces []net.Interface) bool {
|
||||
|
|
|
@ -3,11 +3,13 @@ package spacecore
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/anyproto/any-sync/commonspace"
|
||||
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
|
||||
"github.com/anyproto/any-sync/net/peer"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"github.com/anyproto/anytype-heart/space/spacecore/clientspaceproto"
|
||||
)
|
||||
|
@ -49,8 +51,21 @@ func (r *rpcHandler) SpaceExchange(ctx context.Context, request *clientspaceprot
|
|||
return nil, err
|
||||
}
|
||||
var portAddrs []string
|
||||
peerAddr := peer.CtxPeerAddr(ctx)
|
||||
|
||||
if peerAddr != "" {
|
||||
// prioritize address remote peer connected us from
|
||||
if u, errParse := url.Parse(peerAddr); errParse == nil {
|
||||
portAddrs = append(portAddrs, u.Host)
|
||||
}
|
||||
}
|
||||
|
||||
for _, ip := range request.LocalServer.Ips {
|
||||
portAddrs = append(portAddrs, fmt.Sprintf("%s:%d", ip, request.LocalServer.Port))
|
||||
addr := fmt.Sprintf("%s:%d", ip, request.LocalServer.Port)
|
||||
if slices.Contains(portAddrs, addr) {
|
||||
continue
|
||||
}
|
||||
portAddrs = append(portAddrs, addr)
|
||||
}
|
||||
r.s.peerService.SetPeerAddrs(peerId, portAddrs)
|
||||
r.s.peerStore.UpdateLocalPeer(peerId, request.SpaceIds)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue