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 <bradfitz@tailscale.com>
pull/1696/head
Brad Fitzpatrick 3 years ago
parent 1b9d8771dc
commit db5e269463

@ -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
}

@ -19,11 +19,11 @@ import (
"strconv" "strconv"
"strings" "strings"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/paths" "tailscale.com/paths"
"tailscale.com/safesocket" "tailscale.com/safesocket"
"tailscale.com/tailcfg"
) )
// TailscaledSocket is the tailscaled Unix socket. // 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. // 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)) body, err := get200(ctx, "/localapi/v0/whois?addr="+url.QueryEscape(remoteAddr))
if err != nil { if err != nil {
return nil, err return nil, err
} }
r := new(tailcfg.WhoIsResponse) r := new(apitype.WhoIsResponse)
if err := json.Unmarshal(body, r); err != nil { if err := json.Unmarshal(body, r); err != nil {
if max := 200; len(body) > max { if max := 200; len(body) > max {
body = append(body[:max], "..."...) body = append(body[:max], "..."...)
@ -142,17 +142,12 @@ func status(ctx context.Context, queryString string) (*ipnstate.Status, error) {
return st, nil return st, nil
} }
type WaitingFile struct { func WaitingFiles(ctx context.Context) ([]apitype.WaitingFile, error) {
Name string
Size int64
}
func WaitingFiles(ctx context.Context) ([]WaitingFile, error) {
body, err := get200(ctx, "/localapi/v0/files/") body, err := get200(ctx, "/localapi/v0/files/")
if err != nil { if err != nil {
return nil, err return nil, err
} }
var wfs []WaitingFile var wfs []apitype.WaitingFile
if err := json.Unmarshal(body, &wfs); err != nil { if err := json.Unmarshal(body, &wfs); err != nil {
return nil, err return nil, err
} }
@ -185,6 +180,18 @@ func GetWaitingFile(ctx context.Context, baseName string) (rc io.ReadCloser, siz
return res.Body, res.ContentLength, nil 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 { func CheckIPForwarding(ctx context.Context) error {
body, err := get200(ctx, "/localapi/v0/check-ip-forwarding") body, err := get200(ctx, "/localapi/v0/check-ip-forwarding")
if err != nil { if err != nil {

@ -18,7 +18,7 @@ import (
"strings" "strings"
"tailscale.com/client/tailscale" "tailscale.com/client/tailscale"
"tailscale.com/tailcfg" "tailscale.com/client/tailscale/apitype"
) )
var ( var (
@ -107,7 +107,7 @@ type tmplData struct {
IP string // "100.2.3.4" IP string // "100.2.3.4"
} }
func tailscaleIP(who *tailcfg.WhoIsResponse) string { func tailscaleIP(who *apitype.WhoIsResponse) string {
if who == nil { if who == nil {
return "" return ""
} }

@ -15,6 +15,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
rsc.io/goversion/version from tailscale.com/version rsc.io/goversion/version from tailscale.com/version
tailscale.com/atomicfile from tailscale.com/ipn tailscale.com/atomicfile from tailscale.com/ipn
tailscale.com/client/tailscale from tailscale.com/cmd/tailscale/cli 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/cmd/tailscale/cli from tailscale.com/cmd/tailscale
tailscale.com/derp from tailscale.com/derp/derphttp tailscale.com/derp from tailscale.com/derp/derphttp
tailscale.com/derp/derphttp from tailscale.com/net/netcheck tailscale.com/derp/derphttp from tailscale.com/net/netcheck

@ -71,6 +71,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
inet.af/peercred from tailscale.com/ipn/ipnserver inet.af/peercred from tailscale.com/ipn/ipnserver
rsc.io/goversion/version from tailscale.com/version rsc.io/goversion/version from tailscale.com/version
tailscale.com/atomicfile from tailscale.com/ipn+ 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/control/controlclient from tailscale.com/ipn/ipnlocal+
tailscale.com/derp from tailscale.com/derp/derphttp+ tailscale.com/derp from tailscale.com/derp/derphttp+
tailscale.com/derp/derphttp from tailscale.com/net/netcheck+ tailscale.com/derp/derphttp from tailscale.com/net/netcheck+

@ -25,6 +25,7 @@ import (
"time" "time"
"inet.af/netaddr" "inet.af/netaddr"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/control/controlclient" "tailscale.com/control/controlclient"
"tailscale.com/health" "tailscale.com/health"
"tailscale.com/internal/deepprint" "tailscale.com/internal/deepprint"
@ -2173,7 +2174,7 @@ func (b *LocalBackend) TestOnlyPublicKeys() (machineKey tailcfg.MachineKey, node
return tailcfg.MachineKey(mk), tailcfg.NodeKey(nk) return tailcfg.MachineKey(mk), tailcfg.NodeKey(nk)
} }
func (b *LocalBackend) WaitingFiles() ([]WaitingFile, error) { func (b *LocalBackend) WaitingFiles() ([]apitype.WaitingFile, error) {
b.mu.Lock() b.mu.Lock()
apiSrv := b.peerAPIServer apiSrv := b.peerAPIServer
b.mu.Unlock() b.mu.Unlock()
@ -2203,19 +2204,9 @@ func (b *LocalBackend) OpenFile(name string) (rc io.ReadCloser, size int64, err
return apiSrv.OpenFile(name) 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. // FileTargets lists nodes that the current node can send files to.
func (b *LocalBackend) FileTargets() ([]*FileTarget, error) { func (b *LocalBackend) FileTargets() ([]*apitype.FileTarget, error) {
var ret []*FileTarget var ret []*apitype.FileTarget
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock() defer b.mu.Unlock()
@ -2232,7 +2223,7 @@ func (b *LocalBackend) FileTargets() ([]*FileTarget, error) {
continue continue
} }
ret = append(ret, &FileTarget{ ret = append(ret, &apitype.FileTarget{
Node: p, Node: p,
PeerAPIURL: peerAPI, PeerAPIURL: peerAPI,
}) })

@ -24,6 +24,7 @@ import (
"time" "time"
"inet.af/netaddr" "inet.af/netaddr"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/net/interfaces" "tailscale.com/net/interfaces"
"tailscale.com/syncs" "tailscale.com/syncs"
@ -99,14 +100,7 @@ func (s *peerAPIServer) hasFilesWaiting() bool {
return false return false
} }
// WaitingFile is a JSON-marshaled struct sent by the localapi to pick func (s *peerAPIServer) WaitingFiles() (ret []apitype.WaitingFile, err error) {
// up queued files.
type WaitingFile struct {
Name string
Size int64
}
func (s *peerAPIServer) WaitingFiles() (ret []WaitingFile, err error) {
if s.rootDir == "" { if s.rootDir == "" {
return nil, errors.New("peerapi disabled; no storage configured") return nil, errors.New("peerapi disabled; no storage configured")
} }
@ -130,7 +124,7 @@ func (s *peerAPIServer) WaitingFiles() (ret []WaitingFile, err error) {
if err != nil { if err != nil {
continue continue
} }
ret = append(ret, WaitingFile{ ret = append(ret, apitype.WaitingFile{
Name: filepath.Base(name), Name: filepath.Base(name),
Size: fi.Size(), Size: fi.Size(),
}) })

@ -23,6 +23,7 @@ import (
"time" "time"
"inet.af/netaddr" "inet.af/netaddr"
"tailscale.com/client/tailscale/apitype"
"tailscale.com/ipn" "tailscale.com/ipn"
"tailscale.com/ipn/ipnlocal" "tailscale.com/ipn/ipnlocal"
"tailscale.com/ipn/ipnstate" "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) http.Error(w, "no match for IP:port", 404)
return return
} }
res := &tailcfg.WhoIsResponse{ res := &apitype.WhoIsResponse{
Node: n, Node: n,
UserProfile: &u, 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:] stableID, filenameEscaped := tailcfg.StableNodeID(upath[:slash]), upath[slash+1:]
var ft *ipnlocal.FileTarget var ft *apitype.FileTarget
for _, x := range fts { for _, x := range fts {
if x.Node.StableID == stableID { if x.Node.StableID == stableID {
ft = x ft = x

@ -1050,12 +1050,6 @@ func eqTimePtr(a, b *time.Time) bool {
return ((a == nil) == (b == nil)) && (a == nil || a.Equal(*b)) 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 // 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. // go.mod dependency on App Engine and grpc, which was causing problems.
// All we actually needed was this struct on the client side. // All we actually needed was this struct on the client side.

Loading…
Cancel
Save