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"
"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 {

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

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

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

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

@ -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(),
})

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

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

Loading…
Cancel
Save