Skip to content

Commit 6967a17

Browse files
committed
tools: Tailscale status
1 parent 24a732e commit 6967a17

10 files changed

Lines changed: 524 additions & 174 deletions

File tree

adapter/tailscale.go

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,18 @@ package adapter
22

33
import "context"
44

5-
type TailscaleStatusProvider interface {
5+
type TailscaleEndpoint interface {
66
SubscribeTailscaleStatus(ctx context.Context, fn func(*TailscaleEndpointStatus)) error
7+
StartTailscalePing(ctx context.Context, peerIP string, fn func(*TailscalePingResult)) error
8+
}
9+
10+
type TailscalePingResult struct {
11+
LatencyMs float64
12+
IsDirect bool
13+
Endpoint string
14+
DERPRegionID int32
15+
DERPRegionCode string
16+
Error string
717
}
818

919
type TailscaleEndpointStatus struct {
@@ -12,8 +22,15 @@ type TailscaleEndpointStatus struct {
1222
NetworkName string
1323
MagicDNSSuffix string
1424
Self *TailscalePeer
15-
Users map[int64]*TailscaleUser
16-
Peers []*TailscalePeer
25+
UserGroups []*TailscaleUserGroup
26+
}
27+
28+
type TailscaleUserGroup struct {
29+
UserID int64
30+
LoginName string
31+
DisplayName string
32+
ProfilePicURL string
33+
Peers []*TailscalePeer
1734
}
1835

1936
type TailscalePeer struct {
@@ -31,9 +48,3 @@ type TailscalePeer struct {
3148
KeyExpiry int64
3249
}
3350

34-
type TailscaleUser struct {
35-
ID int64
36-
LoginName string
37-
DisplayName string
38-
ProfilePicURL string
39-
}

daemon/started_service.go

Lines changed: 91 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,31 +1085,6 @@ func (s *StartedService) GetStartedAt(ctx context.Context, empty *emptypb.Empty)
10851085
return &StartedAt{StartedAt: s.startedAt.UnixMilli()}, nil
10861086
}
10871087

1088-
func (s *StartedService) ListOutbounds(ctx context.Context, _ *emptypb.Empty) (*OutboundList, error) {
1089-
s.serviceAccess.RLock()
1090-
if s.serviceStatus.Status != ServiceStatus_STARTED {
1091-
s.serviceAccess.RUnlock()
1092-
return nil, os.ErrInvalid
1093-
}
1094-
boxService := s.instance
1095-
s.serviceAccess.RUnlock()
1096-
historyStorage := boxService.urlTestHistoryStorage
1097-
outbounds := boxService.instance.Outbound().Outbounds()
1098-
var list OutboundList
1099-
for _, ob := range outbounds {
1100-
item := &GroupItem{
1101-
Tag: ob.Tag(),
1102-
Type: ob.Type(),
1103-
}
1104-
if history := historyStorage.LoadURLTestHistory(adapter.OutboundTag(ob)); history != nil {
1105-
item.UrlTestTime = history.Time.Unix()
1106-
item.UrlTestDelay = int32(history.Delay)
1107-
}
1108-
list.Outbounds = append(list.Outbounds, item)
1109-
}
1110-
return &list, nil
1111-
}
1112-
11131088
func (s *StartedService) SubscribeOutbounds(_ *emptypb.Empty, server grpc.ServerStreamingServer[OutboundList]) error {
11141089
err := s.waitForStarted(server.Context())
11151090
if err != nil {
@@ -1129,9 +1104,8 @@ func (s *StartedService) SubscribeOutbounds(_ *emptypb.Empty, server grpc.Server
11291104
boxService := s.instance
11301105
s.serviceAccess.RUnlock()
11311106
historyStorage := boxService.urlTestHistoryStorage
1132-
outbounds := boxService.instance.Outbound().Outbounds()
11331107
var list OutboundList
1134-
for _, ob := range outbounds {
1108+
for _, ob := range boxService.instance.Outbound().Outbounds() {
11351109
item := &GroupItem{
11361110
Tag: ob.Tag(),
11371111
Type: ob.Type(),
@@ -1142,6 +1116,17 @@ func (s *StartedService) SubscribeOutbounds(_ *emptypb.Empty, server grpc.Server
11421116
}
11431117
list.Outbounds = append(list.Outbounds, item)
11441118
}
1119+
for _, ep := range boxService.instance.Endpoint().Endpoints() {
1120+
item := &GroupItem{
1121+
Tag: ep.Tag(),
1122+
Type: ep.Type(),
1123+
}
1124+
if history := historyStorage.LoadURLTestHistory(adapter.OutboundTag(ep)); history != nil {
1125+
item.UrlTestTime = history.Time.Unix()
1126+
item.UrlTestDelay = int32(history.Delay)
1127+
}
1128+
list.Outbounds = append(list.Outbounds, item)
1129+
}
11451130
err = server.Send(&list)
11461131
if err != nil {
11471132
return err
@@ -1308,14 +1293,14 @@ func (s *StartedService) SubscribeTailscaleStatus(
13081293

13091294
type tailscaleEndpoint struct {
13101295
tag string
1311-
provider adapter.TailscaleStatusProvider
1296+
provider adapter.TailscaleEndpoint
13121297
}
13131298
var endpoints []tailscaleEndpoint
13141299
for _, endpoint := range endpointManager.Endpoints() {
13151300
if endpoint.Type() != C.TypeTailscale {
13161301
continue
13171302
}
1318-
provider, loaded := endpoint.(adapter.TailscaleStatusProvider)
1303+
provider, loaded := endpoint.(adapter.TailscaleEndpoint)
13191304
if !loaded {
13201305
continue
13211306
}
@@ -1339,7 +1324,7 @@ func (s *StartedService) SubscribeTailscaleStatus(
13391324
var waitGroup sync.WaitGroup
13401325
for _, endpoint := range endpoints {
13411326
waitGroup.Add(1)
1342-
go func(tag string, provider adapter.TailscaleStatusProvider) {
1327+
go func(tag string, provider adapter.TailscaleEndpoint) {
13431328
defer waitGroup.Done()
13441329
_ = provider.SubscribeTailscaleStatus(ctx, func(endpointStatus *adapter.TailscaleEndpointStatus) {
13451330
select {
@@ -1355,12 +1340,16 @@ func (s *StartedService) SubscribeTailscaleStatus(
13551340
close(updates)
13561341
}()
13571342

1343+
var tags []string
13581344
statuses := make(map[string]*adapter.TailscaleEndpointStatus, len(endpoints))
13591345
for update := range updates {
1346+
if _, exists := statuses[update.tag]; !exists {
1347+
tags = append(tags, update.tag)
1348+
}
13601349
statuses[update.tag] = update.status
13611350
protoEndpoints := make([]*TailscaleEndpointStatus, 0, len(statuses))
1362-
for tag, endpointStatus := range statuses {
1363-
protoEndpoints = append(protoEndpoints, tailscaleEndpointStatusToProto(tag, endpointStatus))
1351+
for _, tag := range tags {
1352+
protoEndpoints = append(protoEndpoints, tailscaleEndpointStatusToProto(tag, statuses[tag]))
13641353
}
13651354
sendErr := server.Send(&TailscaleStatusUpdate{
13661355
Endpoints: protoEndpoints,
@@ -1373,27 +1362,19 @@ func (s *StartedService) SubscribeTailscaleStatus(
13731362
}
13741363

13751364
func tailscaleEndpointStatusToProto(tag string, s *adapter.TailscaleEndpointStatus) *TailscaleEndpointStatus {
1376-
userGroupMap := make(map[int64]*TailscaleUserGroup)
1377-
for userID, user := range s.Users {
1378-
userGroupMap[userID] = &TailscaleUserGroup{
1379-
UserID: userID,
1380-
LoginName: user.LoginName,
1381-
DisplayName: user.DisplayName,
1382-
ProfilePicURL: user.ProfilePicURL,
1365+
userGroups := make([]*TailscaleUserGroup, len(s.UserGroups))
1366+
for i, group := range s.UserGroups {
1367+
peers := make([]*TailscalePeer, len(group.Peers))
1368+
for j, peer := range group.Peers {
1369+
peers[j] = tailscalePeerToProto(peer)
13831370
}
1384-
}
1385-
for _, peer := range s.Peers {
1386-
protoPeer := tailscalePeerToProto(peer)
1387-
group, loaded := userGroupMap[peer.UserID]
1388-
if !loaded {
1389-
group = &TailscaleUserGroup{UserID: peer.UserID}
1390-
userGroupMap[peer.UserID] = group
1371+
userGroups[i] = &TailscaleUserGroup{
1372+
UserID: group.UserID,
1373+
LoginName: group.LoginName,
1374+
DisplayName: group.DisplayName,
1375+
ProfilePicURL: group.ProfilePicURL,
1376+
Peers: peers,
13911377
}
1392-
group.Peers = append(group.Peers, protoPeer)
1393-
}
1394-
userGroups := make([]*TailscaleUserGroup, 0, len(userGroupMap))
1395-
for _, group := range userGroupMap {
1396-
userGroups = append(userGroups, group)
13971378
}
13981379
result := &TailscaleEndpointStatus{
13991380
EndpointTag: tag,
@@ -1425,6 +1406,65 @@ func tailscalePeerToProto(peer *adapter.TailscalePeer) *TailscalePeer {
14251406
}
14261407
}
14271408

1409+
func (s *StartedService) StartTailscalePing(
1410+
request *TailscalePingRequest,
1411+
server grpc.ServerStreamingServer[TailscalePingResponse],
1412+
) error {
1413+
err := s.waitForStarted(server.Context())
1414+
if err != nil {
1415+
return err
1416+
}
1417+
s.serviceAccess.RLock()
1418+
boxService := s.instance
1419+
s.serviceAccess.RUnlock()
1420+
1421+
endpointManager := service.FromContext[adapter.EndpointManager](boxService.ctx)
1422+
if endpointManager == nil {
1423+
return status.Error(codes.FailedPrecondition, "endpoint manager not available")
1424+
}
1425+
1426+
var provider adapter.TailscaleEndpoint
1427+
if request.EndpointTag != "" {
1428+
endpoint, loaded := endpointManager.Get(request.EndpointTag)
1429+
if !loaded {
1430+
return status.Error(codes.NotFound, "endpoint not found: "+request.EndpointTag)
1431+
}
1432+
if endpoint.Type() != C.TypeTailscale {
1433+
return status.Error(codes.InvalidArgument, "endpoint is not Tailscale: "+request.EndpointTag)
1434+
}
1435+
pingProvider, loaded := endpoint.(adapter.TailscaleEndpoint)
1436+
if !loaded {
1437+
return status.Error(codes.FailedPrecondition, "endpoint does not support ping")
1438+
}
1439+
provider = pingProvider
1440+
} else {
1441+
for _, endpoint := range endpointManager.Endpoints() {
1442+
if endpoint.Type() != C.TypeTailscale {
1443+
continue
1444+
}
1445+
pingProvider, loaded := endpoint.(adapter.TailscaleEndpoint)
1446+
if loaded {
1447+
provider = pingProvider
1448+
break
1449+
}
1450+
}
1451+
if provider == nil {
1452+
return status.Error(codes.NotFound, "no Tailscale endpoint found")
1453+
}
1454+
}
1455+
1456+
return provider.StartTailscalePing(server.Context(), request.PeerIP, func(result *adapter.TailscalePingResult) {
1457+
_ = server.Send(&TailscalePingResponse{
1458+
LatencyMs: result.LatencyMs,
1459+
IsDirect: result.IsDirect,
1460+
Endpoint: result.Endpoint,
1461+
DerpRegionID: result.DERPRegionID,
1462+
DerpRegionCode: result.DERPRegionCode,
1463+
Error: result.Error,
1464+
})
1465+
})
1466+
}
1467+
14281468
func (s *StartedService) mustEmbedUnimplementedStartedServiceServer() {
14291469
}
14301470

0 commit comments

Comments
 (0)