From db5e269463c6e9794efa871ee3246223feee20d8 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 13 Apr 2021 08:13:46 -0700 Subject: [PATCH] client/tailscale/apitype: move local API types to new apitype package They were scattered/duplicated in misc places before. It can't be in the client package itself for circular dep reasons. This new package is basically tailcfg but for localhost communications, instead of to control. Signed-off-by: Brad Fitzpatrick --- client/tailscale/apitype/apitype.go | 29 +++++++++++++++++++++++++++++ client/tailscale/tailscale.go | 27 +++++++++++++++++---------- cmd/hello/hello.go | 4 ++-- cmd/tailscale/depaware.txt | 1 + cmd/tailscaled/depaware.txt | 1 + ipn/ipnlocal/local.go | 19 +++++-------------- ipn/ipnlocal/peerapi.go | 12 +++--------- ipn/localapi/localapi.go | 5 +++-- tailcfg/tailcfg.go | 6 ------ 9 files changed, 61 insertions(+), 43 deletions(-) create mode 100644 client/tailscale/apitype/apitype.go diff --git a/client/tailscale/apitype/apitype.go b/client/tailscale/apitype/apitype.go new file mode 100644 index 000000000..cae573a4e --- /dev/null +++ b/client/tailscale/apitype/apitype.go @@ -0,0 +1,29 @@ +// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package apitype contains types for the Tailscale local API. +package apitype + +import "tailscale.com/tailcfg" + +// WhoIsResponse is the JSON type returned by tailscaled debug server's /whois?ip=$IP handler. +type WhoIsResponse struct { + Node *tailcfg.Node + UserProfile *tailcfg.UserProfile +} + +// FileTarget is a node to which files can be sent, and the PeerAPI +// URL base to do so via. +type FileTarget struct { + Node *tailcfg.Node + + // PeerAPI is the http://ip:port URL base of the node's peer API, + // without any path (not even a single slash). + PeerAPIURL string +} + +type WaitingFile struct { + Name string + Size int64 +} diff --git a/client/tailscale/tailscale.go b/client/tailscale/tailscale.go index e386d7695..ba59a060c 100644 --- a/client/tailscale/tailscale.go +++ b/client/tailscale/tailscale.go @@ -19,11 +19,11 @@ import ( "strconv" "strings" + "tailscale.com/client/tailscale/apitype" "tailscale.com/ipn" "tailscale.com/ipn/ipnstate" "tailscale.com/paths" "tailscale.com/safesocket" - "tailscale.com/tailcfg" ) // TailscaledSocket is the tailscaled Unix socket. @@ -91,12 +91,12 @@ func get200(ctx context.Context, path string) ([]byte, error) { } // WhoIs returns the owner of the remoteAddr, which must be an IP or IP:port. -func WhoIs(ctx context.Context, remoteAddr string) (*tailcfg.WhoIsResponse, error) { +func WhoIs(ctx context.Context, remoteAddr string) (*apitype.WhoIsResponse, error) { body, err := get200(ctx, "/localapi/v0/whois?addr="+url.QueryEscape(remoteAddr)) if err != nil { return nil, err } - r := new(tailcfg.WhoIsResponse) + r := new(apitype.WhoIsResponse) if err := json.Unmarshal(body, r); err != nil { if max := 200; len(body) > max { body = append(body[:max], "..."...) @@ -142,17 +142,12 @@ func status(ctx context.Context, queryString string) (*ipnstate.Status, error) { return st, nil } -type WaitingFile struct { - Name string - Size int64 -} - -func WaitingFiles(ctx context.Context) ([]WaitingFile, error) { +func WaitingFiles(ctx context.Context) ([]apitype.WaitingFile, error) { body, err := get200(ctx, "/localapi/v0/files/") if err != nil { return nil, err } - var wfs []WaitingFile + var wfs []apitype.WaitingFile if err := json.Unmarshal(body, &wfs); err != nil { return nil, err } @@ -185,6 +180,18 @@ func GetWaitingFile(ctx context.Context, baseName string) (rc io.ReadCloser, siz return res.Body, res.ContentLength, nil } +func FileTargets(ctx context.Context) ([]apitype.FileTarget, error) { + body, err := get200(ctx, "/localapi/v0/file-targets") + if err != nil { + return nil, err + } + var fts []apitype.FileTarget + if err := json.Unmarshal(body, &fts); err != nil { + return nil, fmt.Errorf("invalid JSON: %w", err) + } + return fts, nil +} + func CheckIPForwarding(ctx context.Context) error { body, err := get200(ctx, "/localapi/v0/check-ip-forwarding") if err != nil { diff --git a/cmd/hello/hello.go b/cmd/hello/hello.go index 1c14fb71b..0e7b64890 100644 --- a/cmd/hello/hello.go +++ b/cmd/hello/hello.go @@ -18,7 +18,7 @@ import ( "strings" "tailscale.com/client/tailscale" - "tailscale.com/tailcfg" + "tailscale.com/client/tailscale/apitype" ) var ( @@ -107,7 +107,7 @@ type tmplData struct { IP string // "100.2.3.4" } -func tailscaleIP(who *tailcfg.WhoIsResponse) string { +func tailscaleIP(who *apitype.WhoIsResponse) string { if who == nil { return "" } diff --git a/cmd/tailscale/depaware.txt b/cmd/tailscale/depaware.txt index be3a096b8..2b2fa40ee 100644 --- a/cmd/tailscale/depaware.txt +++ b/cmd/tailscale/depaware.txt @@ -15,6 +15,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep rsc.io/goversion/version from tailscale.com/version tailscale.com/atomicfile from tailscale.com/ipn tailscale.com/client/tailscale from tailscale.com/cmd/tailscale/cli + tailscale.com/client/tailscale/apitype from tailscale.com/client/tailscale tailscale.com/cmd/tailscale/cli from tailscale.com/cmd/tailscale tailscale.com/derp from tailscale.com/derp/derphttp tailscale.com/derp/derphttp from tailscale.com/net/netcheck diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index e300e9af9..c4689dac8 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -71,6 +71,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de inet.af/peercred from tailscale.com/ipn/ipnserver rsc.io/goversion/version from tailscale.com/version tailscale.com/atomicfile from tailscale.com/ipn+ + tailscale.com/client/tailscale/apitype from tailscale.com/ipn/ipnlocal+ tailscale.com/control/controlclient from tailscale.com/ipn/ipnlocal+ tailscale.com/derp from tailscale.com/derp/derphttp+ tailscale.com/derp/derphttp from tailscale.com/net/netcheck+ diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index abb3aa866..e42065ac9 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -25,6 +25,7 @@ import ( "time" "inet.af/netaddr" + "tailscale.com/client/tailscale/apitype" "tailscale.com/control/controlclient" "tailscale.com/health" "tailscale.com/internal/deepprint" @@ -2173,7 +2174,7 @@ func (b *LocalBackend) TestOnlyPublicKeys() (machineKey tailcfg.MachineKey, node return tailcfg.MachineKey(mk), tailcfg.NodeKey(nk) } -func (b *LocalBackend) WaitingFiles() ([]WaitingFile, error) { +func (b *LocalBackend) WaitingFiles() ([]apitype.WaitingFile, error) { b.mu.Lock() apiSrv := b.peerAPIServer b.mu.Unlock() @@ -2203,19 +2204,9 @@ func (b *LocalBackend) OpenFile(name string) (rc io.ReadCloser, size int64, err return apiSrv.OpenFile(name) } -// FileTarget is a node to which files can be sent, and the PeerAPI -// URL base to do so via. -type FileTarget struct { - Node *tailcfg.Node - - // PeerAPI is the http://ip:port URL base of the node's peer API, - // without any path (not even a single slash). - PeerAPIURL string -} - // FileTargets lists nodes that the current node can send files to. -func (b *LocalBackend) FileTargets() ([]*FileTarget, error) { - var ret []*FileTarget +func (b *LocalBackend) FileTargets() ([]*apitype.FileTarget, error) { + var ret []*apitype.FileTarget b.mu.Lock() defer b.mu.Unlock() @@ -2232,7 +2223,7 @@ func (b *LocalBackend) FileTargets() ([]*FileTarget, error) { continue } - ret = append(ret, &FileTarget{ + ret = append(ret, &apitype.FileTarget{ Node: p, PeerAPIURL: peerAPI, }) diff --git a/ipn/ipnlocal/peerapi.go b/ipn/ipnlocal/peerapi.go index 33ec9df0b..0834481e5 100644 --- a/ipn/ipnlocal/peerapi.go +++ b/ipn/ipnlocal/peerapi.go @@ -24,6 +24,7 @@ import ( "time" "inet.af/netaddr" + "tailscale.com/client/tailscale/apitype" "tailscale.com/ipn" "tailscale.com/net/interfaces" "tailscale.com/syncs" @@ -99,14 +100,7 @@ func (s *peerAPIServer) hasFilesWaiting() bool { return false } -// WaitingFile is a JSON-marshaled struct sent by the localapi to pick -// up queued files. -type WaitingFile struct { - Name string - Size int64 -} - -func (s *peerAPIServer) WaitingFiles() (ret []WaitingFile, err error) { +func (s *peerAPIServer) WaitingFiles() (ret []apitype.WaitingFile, err error) { if s.rootDir == "" { return nil, errors.New("peerapi disabled; no storage configured") } @@ -130,7 +124,7 @@ func (s *peerAPIServer) WaitingFiles() (ret []WaitingFile, err error) { if err != nil { continue } - ret = append(ret, WaitingFile{ + ret = append(ret, apitype.WaitingFile{ Name: filepath.Base(name), Size: fi.Size(), }) diff --git a/ipn/localapi/localapi.go b/ipn/localapi/localapi.go index d4f89f51f..8bd82c501 100644 --- a/ipn/localapi/localapi.go +++ b/ipn/localapi/localapi.go @@ -23,6 +23,7 @@ import ( "time" "inet.af/netaddr" + "tailscale.com/client/tailscale/apitype" "tailscale.com/ipn" "tailscale.com/ipn/ipnlocal" "tailscale.com/ipn/ipnstate" @@ -143,7 +144,7 @@ func (h *Handler) serveWhoIs(w http.ResponseWriter, r *http.Request) { http.Error(w, "no match for IP:port", 404) return } - res := &tailcfg.WhoIsResponse{ + res := &apitype.WhoIsResponse{ Node: n, UserProfile: &u, } @@ -340,7 +341,7 @@ func (h *Handler) serveFilePut(w http.ResponseWriter, r *http.Request) { } stableID, filenameEscaped := tailcfg.StableNodeID(upath[:slash]), upath[slash+1:] - var ft *ipnlocal.FileTarget + var ft *apitype.FileTarget for _, x := range fts { if x.Node.StableID == stableID { ft = x diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go index 52c3911f9..c255de54b 100644 --- a/tailcfg/tailcfg.go +++ b/tailcfg/tailcfg.go @@ -1050,12 +1050,6 @@ func eqTimePtr(a, b *time.Time) bool { return ((a == nil) == (b == nil)) && (a == nil || a.Equal(*b)) } -// WhoIsResponse is the JSON type returned by tailscaled debug server's /whois?ip=$IP handler. -type WhoIsResponse struct { - Node *Node - UserProfile *UserProfile -} - // Oauth2Token is a copy of golang.org/x/oauth2.Token, to avoid the // go.mod dependency on App Engine and grpc, which was causing problems. // All we actually needed was this struct on the client side.