Compare commits

...

1 Commits

Author SHA1 Message Date
Joe Tsai
8841fd58c9 cmd/viewer: support v2 JSON methods
This links in github.com/go-json-experiment/json into tailscaled.
After this change, the tailscaled binary on GOOS=linux and GOARCH=amd64
increases by ~85KiB.

The v2 marshal/unmarshal methods avoids a O(n^2) behavior
with deeply nested v1 MarshalJSON and UnmarshalJSON calls,
since each call requires the encoding/json package to rescan
the entire JSON value. Our data structures are not so deep
that the O(n^2) behavior becomes notable,
but this does provide about a ~20% performance benefit.

Updates tailscale/corp#14379

Signed-off-by: Joe Tsai <joetsai@digital-static.net>
2023-09-06 13:03:51 -07:00
10 changed files with 502 additions and 19 deletions

View File

@@ -15,6 +15,12 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
L github.com/coreos/go-iptables/iptables from tailscale.com/util/linuxfw
W 💣 github.com/dblohm7/wingoes from tailscale.com/util/winutil
github.com/fxamacker/cbor/v2 from tailscale.com/tka
github.com/go-json-experiment/json from tailscale.com/tailcfg
github.com/go-json-experiment/json/internal from github.com/go-json-experiment/json+
github.com/go-json-experiment/json/internal/jsonflags from github.com/go-json-experiment/json+
github.com/go-json-experiment/json/internal/jsonopts from github.com/go-json-experiment/json+
github.com/go-json-experiment/json/internal/jsonwire from github.com/go-json-experiment/json+
github.com/go-json-experiment/json/jsontext from github.com/go-json-experiment/json+
github.com/golang/groupcache/lru from tailscale.com/net/dnscache
github.com/golang/protobuf/proto from github.com/matttproud/golang_protobuf_extensions/pbutil+
L github.com/google/nftables from tailscale.com/util/linuxfw
@@ -191,7 +197,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
golang.org/x/time/rate from tailscale.com/cmd/derper+
bufio from compress/flate+
bytes from bufio+
cmp from slices
cmp from slices+
compress/flate from compress/gzip+
compress/gzip from internal/profile+
container/list from crypto/tls+
@@ -220,7 +226,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
embed from crypto/internal/nistec+
encoding from encoding/json+
encoding/asn1 from crypto/x509+
encoding/base32 from tailscale.com/tka
encoding/base32 from tailscale.com/tka+
encoding/base64 from encoding/json+
encoding/binary from compress/gzip+
encoding/hex from crypto/x509+

View File

@@ -42,6 +42,7 @@ import (
"github.com/dsnet/try"
jsonv2 "github.com/go-json-experiment/json"
"github.com/go-json-experiment/json/jsontext"
"tailscale.com/types/logid"
"tailscale.com/types/netlogtype"
"tailscale.com/util/cmpx"
@@ -75,13 +76,13 @@ func main() {
func processStream(r io.Reader) (err error) {
defer try.Handle(&err)
dec := jsonv2.NewDecoder(os.Stdin)
dec := jsontext.NewDecoder(os.Stdin)
for {
processValue(dec)
}
}
func processValue(dec *jsonv2.Decoder) {
func processValue(dec *jsontext.Decoder) {
switch dec.PeekKind() {
case '[':
processArray(dec)
@@ -92,7 +93,7 @@ func processValue(dec *jsonv2.Decoder) {
}
}
func processArray(dec *jsonv2.Decoder) {
func processArray(dec *jsontext.Decoder) {
try.E1(dec.ReadToken()) // parse '['
for dec.PeekKind() != ']' {
processValue(dec)
@@ -100,7 +101,7 @@ func processArray(dec *jsonv2.Decoder) {
try.E1(dec.ReadToken()) // parse ']'
}
func processObject(dec *jsonv2.Decoder) {
func processObject(dec *jsontext.Decoder) {
var hasTraffic bool
var rawMsg []byte
try.E1(dec.ReadToken()) // parse '{'

View File

@@ -15,6 +15,12 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
W 💣 github.com/dblohm7/wingoes from tailscale.com/util/winutil/authenticode+
W 💣 github.com/dblohm7/wingoes/pe from tailscale.com/util/winutil/authenticode
github.com/fxamacker/cbor/v2 from tailscale.com/tka
github.com/go-json-experiment/json from tailscale.com/tailcfg
github.com/go-json-experiment/json/internal from github.com/go-json-experiment/json+
github.com/go-json-experiment/json/internal/jsonflags from github.com/go-json-experiment/json+
github.com/go-json-experiment/json/internal/jsonopts from github.com/go-json-experiment/json+
github.com/go-json-experiment/json/internal/jsonwire from github.com/go-json-experiment/json+
github.com/go-json-experiment/json/jsontext from github.com/go-json-experiment/json+
L 💣 github.com/godbus/dbus/v5 from github.com/coreos/go-systemd/v22/dbus
github.com/golang/groupcache/lru from tailscale.com/net/dnscache
L github.com/google/nftables from tailscale.com/util/linuxfw
@@ -205,7 +211,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
archive/tar from tailscale.com/clientupdate
bufio from compress/flate+
bytes from bufio+
cmp from slices
cmp from slices+
compress/flate from compress/gzip+
compress/gzip from net/http+
compress/zlib from image/png+

View File

@@ -84,6 +84,12 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
W github.com/dblohm7/wingoes/internal from github.com/dblohm7/wingoes/com
W 💣 github.com/dblohm7/wingoes/pe from tailscale.com/util/osdiag+
github.com/fxamacker/cbor/v2 from tailscale.com/tka
github.com/go-json-experiment/json from tailscale.com/tailcfg
github.com/go-json-experiment/json/internal from github.com/go-json-experiment/json+
github.com/go-json-experiment/json/internal/jsonflags from github.com/go-json-experiment/json+
github.com/go-json-experiment/json/internal/jsonopts from github.com/go-json-experiment/json+
github.com/go-json-experiment/json/internal/jsonwire from github.com/go-json-experiment/json+
github.com/go-json-experiment/json/jsontext from github.com/go-json-experiment/json+
W 💣 github.com/go-ole/go-ole from github.com/go-ole/go-ole/oleutil+
W 💣 github.com/go-ole/go-ole/oleutil from tailscale.com/wgengine/winnet
L 💣 github.com/godbus/dbus/v5 from tailscale.com/net/dns+
@@ -418,7 +424,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
archive/tar from tailscale.com/clientupdate
bufio from compress/flate+
bytes from bufio+
cmp from slices
cmp from slices+
compress/flate from compress/gzip+
compress/gzip from golang.org/x/net/http2+
W compress/zlib from debug/pe

View File

@@ -64,6 +64,30 @@ func (v *{{.ViewName}}) UnmarshalJSON(b []byte) error {
return nil
}
{{if .SupportJSONV2}}
// Verify that {{.ViewName}} implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*{{.ViewName}})(nil)
_ (jsonv2.UnmarshalerV2) = (*{{.ViewName}})(nil)
)
func (v {{.ViewName}}) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *{{.ViewName}}) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x {{.StructName}}
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
{{end}}
{{end}}
{{define "valueField"}}func (v {{.ViewName}}) {{.FieldName}}() {{.FieldType}} { return v.ж.{{.FieldName}} }
{{end}}
@@ -126,6 +150,10 @@ func genView(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named, thi
}
it.Import("encoding/json")
it.Import("errors")
if *jsonv2Methods {
it.ImportNamed("github.com/go-json-experiment/json", "jsonv2")
it.Import("github.com/go-json-experiment/json/jsontext")
}
args := struct {
StructName string
@@ -138,9 +166,12 @@ func genView(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named, thi
MapValueType string
MapValueView string
MapFn string
SupportJSONV2 bool
}{
StructName: typ.Obj().Name(),
ViewName: typ.Obj().Name() + "View",
StructName: typ.Obj().Name(),
ViewName: typ.Obj().Name() + "View",
SupportJSONV2: *jsonv2Methods,
}
writeTemplate := func(name string) {
@@ -321,6 +352,7 @@ var (
flagTypes = flag.String("type", "", "comma-separated list of types; required")
flagBuildTags = flag.String("tags", "", "compiler build tags to apply")
flagCloneFunc = flag.Bool("clonefunc", false, "add a top-level Clone func")
jsonv2Methods = flag.Bool("jsonv2method", false, "add marshal/unmarshal methods for JSONv2")
flagCloneOnlyTypes = flag.String("clone-only-type", "", "comma-separated list of types (a subset of --type) that should only generate a go:generate clone line and not actual views")
)

2
go.mod
View File

@@ -24,7 +24,7 @@ require (
github.com/evanw/esbuild v0.14.53
github.com/frankban/quicktest v1.14.5
github.com/fxamacker/cbor/v2 v2.4.0
github.com/go-json-experiment/json v0.0.0-20230321051131-ccbac49a6929
github.com/go-json-experiment/json v0.0.0-20230831193458-5df0a50228ea
github.com/go-logr/zapr v1.2.4
github.com/go-ole/go-ole v1.2.6
github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466

4
go.sum
View File

@@ -299,8 +299,8 @@ github.com/go-git/go-git/v5 v5.7.0/go.mod h1:coJHKEOk5kUClpsNlXrUvPrDxY3w3gjHvhc
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-json-experiment/json v0.0.0-20230321051131-ccbac49a6929 h1:GdbUZo0+623j+pKRhwwdf1q28IUgRc7asx3TjF9b7VQ=
github.com/go-json-experiment/json v0.0.0-20230321051131-ccbac49a6929/go.mod h1:AHV+bpNGVGD0DCHMBhhTYtT7yeBYD9Yk92XAjB7vOgo=
github.com/go-json-experiment/json v0.0.0-20230831193458-5df0a50228ea h1:EFOg7Pq/YiznRzn/7udE/cuT1swauYdQ5ljDK93jBNc=
github.com/go-json-experiment/json v0.0.0-20230831193458-5df0a50228ea/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=

View File

@@ -3,7 +3,7 @@
package tailcfg
//go:generate go run tailscale.com/cmd/viewer --type=User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,RegisterResponseAuth,RegisterRequest,DERPHomeParams,DERPRegion,DERPMap,DERPNode,SSHRule,SSHAction,SSHPrincipal,ControlDialPlan,Location,UserProfile --clonefunc
//go:generate go run tailscale.com/cmd/viewer --type=User,Node,Hostinfo,NetInfo,Login,DNSConfig,RegisterResponse,RegisterResponseAuth,RegisterRequest,DERPHomeParams,DERPRegion,DERPMap,DERPNode,SSHRule,SSHAction,SSHPrincipal,ControlDialPlan,Location,UserProfile --clonefunc --jsonv2method
import (
"bytes"

View File

@@ -11,6 +11,8 @@ import (
"net/netip"
"time"
jsonv2 "github.com/go-json-experiment/json"
"github.com/go-json-experiment/json/jsontext"
"tailscale.com/types/dnstype"
"tailscale.com/types/key"
"tailscale.com/types/opt"
@@ -66,6 +68,28 @@ func (v *UserView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that UserView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*UserView)(nil)
_ (jsonv2.UnmarshalerV2) = (*UserView)(nil)
)
func (v UserView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *UserView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x User
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v UserView) ID() UserID { return v.ж.ID }
func (v UserView) LoginName() string { return v.ж.LoginName }
func (v UserView) DisplayName() string { return v.ж.DisplayName }
@@ -128,6 +152,28 @@ func (v *NodeView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that NodeView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*NodeView)(nil)
_ (jsonv2.UnmarshalerV2) = (*NodeView)(nil)
)
func (v NodeView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *NodeView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x Node
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v NodeView) ID() NodeID { return v.ж.ID }
func (v NodeView) StableID() StableNodeID { return v.ж.StableID }
func (v NodeView) Name() string { return v.ж.Name }
@@ -263,6 +309,28 @@ func (v *HostinfoView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that HostinfoView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*HostinfoView)(nil)
_ (jsonv2.UnmarshalerV2) = (*HostinfoView)(nil)
)
func (v HostinfoView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *HostinfoView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x Hostinfo
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v HostinfoView) IPNVersion() string { return v.ж.IPNVersion }
func (v HostinfoView) FrontendLogID() string { return v.ж.FrontendLogID }
func (v HostinfoView) BackendLogID() string { return v.ж.BackendLogID }
@@ -389,6 +457,28 @@ func (v *NetInfoView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that NetInfoView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*NetInfoView)(nil)
_ (jsonv2.UnmarshalerV2) = (*NetInfoView)(nil)
)
func (v NetInfoView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *NetInfoView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x NetInfo
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v NetInfoView) MappingVariesByDestIP() opt.Bool { return v.ж.MappingVariesByDestIP }
func (v NetInfoView) HairPinning() opt.Bool { return v.ж.HairPinning }
func (v NetInfoView) WorkingIPv6() opt.Bool { return v.ж.WorkingIPv6 }
@@ -469,6 +559,28 @@ func (v *LoginView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that LoginView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*LoginView)(nil)
_ (jsonv2.UnmarshalerV2) = (*LoginView)(nil)
)
func (v LoginView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *LoginView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x Login
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v LoginView) ID() LoginID { return v.ж.ID }
func (v LoginView) Provider() string { return v.ж.Provider }
func (v LoginView) LoginName() string { return v.ж.LoginName }
@@ -530,6 +642,28 @@ func (v *DNSConfigView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that DNSConfigView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*DNSConfigView)(nil)
_ (jsonv2.UnmarshalerV2) = (*DNSConfigView)(nil)
)
func (v DNSConfigView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *DNSConfigView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x DNSConfig
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v DNSConfigView) Resolvers() views.SliceView[*dnstype.Resolver, dnstype.ResolverView] {
return views.SliceOfViews[*dnstype.Resolver, dnstype.ResolverView](v.ж.Resolvers)
}
@@ -611,6 +745,28 @@ func (v *RegisterResponseView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that RegisterResponseView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*RegisterResponseView)(nil)
_ (jsonv2.UnmarshalerV2) = (*RegisterResponseView)(nil)
)
func (v RegisterResponseView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *RegisterResponseView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x RegisterResponse
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v RegisterResponseView) User() UserView { return v.ж.User.View() }
func (v RegisterResponseView) Login() Login { return v.ж.Login }
func (v RegisterResponseView) NodeKeyExpired() bool { return v.ж.NodeKeyExpired }
@@ -677,6 +833,28 @@ func (v *RegisterResponseAuthView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that RegisterResponseAuthView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*RegisterResponseAuthView)(nil)
_ (jsonv2.UnmarshalerV2) = (*RegisterResponseAuthView)(nil)
)
func (v RegisterResponseAuthView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *RegisterResponseAuthView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x RegisterResponseAuth
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v RegisterResponseAuthView) Provider() string { return v.ж.Provider }
func (v RegisterResponseAuthView) LoginName() string { return v.ж.LoginName }
func (v RegisterResponseAuthView) Oauth2Token() *Oauth2Token {
@@ -743,6 +921,28 @@ func (v *RegisterRequestView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that RegisterRequestView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*RegisterRequestView)(nil)
_ (jsonv2.UnmarshalerV2) = (*RegisterRequestView)(nil)
)
func (v RegisterRequestView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *RegisterRequestView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x RegisterRequest
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v RegisterRequestView) Version() CapabilityVersion { return v.ж.Version }
func (v RegisterRequestView) NodeKey() key.NodePublic { return v.ж.NodeKey }
func (v RegisterRequestView) OldNodeKey() key.NodePublic { return v.ж.OldNodeKey }
@@ -835,6 +1035,28 @@ func (v *DERPHomeParamsView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that DERPHomeParamsView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*DERPHomeParamsView)(nil)
_ (jsonv2.UnmarshalerV2) = (*DERPHomeParamsView)(nil)
)
func (v DERPHomeParamsView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *DERPHomeParamsView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x DERPHomeParams
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v DERPHomeParamsView) RegionScore() views.Map[int, float64] {
return views.MapOf(v.ж.RegionScore)
}
@@ -889,6 +1111,28 @@ func (v *DERPRegionView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that DERPRegionView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*DERPRegionView)(nil)
_ (jsonv2.UnmarshalerV2) = (*DERPRegionView)(nil)
)
func (v DERPRegionView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *DERPRegionView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x DERPRegion
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v DERPRegionView) RegionID() int { return v.ж.RegionID }
func (v DERPRegionView) RegionCode() string { return v.ж.RegionCode }
func (v DERPRegionView) RegionName() string { return v.ж.RegionName }
@@ -951,6 +1195,28 @@ func (v *DERPMapView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that DERPMapView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*DERPMapView)(nil)
_ (jsonv2.UnmarshalerV2) = (*DERPMapView)(nil)
)
func (v DERPMapView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *DERPMapView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x DERPMap
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v DERPMapView) HomeParams() DERPHomeParamsView { return v.ж.HomeParams.View() }
func (v DERPMapView) Regions() views.MapFn[int, *DERPRegion, DERPRegionView] {
@@ -1012,6 +1278,28 @@ func (v *DERPNodeView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that DERPNodeView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*DERPNodeView)(nil)
_ (jsonv2.UnmarshalerV2) = (*DERPNodeView)(nil)
)
func (v DERPNodeView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *DERPNodeView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x DERPNode
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v DERPNodeView) Name() string { return v.ж.Name }
func (v DERPNodeView) RegionID() int { return v.ж.RegionID }
func (v DERPNodeView) HostName() string { return v.ж.HostName }
@@ -1086,6 +1374,28 @@ func (v *SSHRuleView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that SSHRuleView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*SSHRuleView)(nil)
_ (jsonv2.UnmarshalerV2) = (*SSHRuleView)(nil)
)
func (v SSHRuleView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *SSHRuleView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x SSHRule
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v SSHRuleView) RuleExpires() *time.Time {
if v.ж.RuleExpires == nil {
return nil
@@ -1154,6 +1464,28 @@ func (v *SSHActionView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that SSHActionView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*SSHActionView)(nil)
_ (jsonv2.UnmarshalerV2) = (*SSHActionView)(nil)
)
func (v SSHActionView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *SSHActionView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x SSHAction
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v SSHActionView) Message() string { return v.ж.Message }
func (v SSHActionView) Reject() bool { return v.ж.Reject }
func (v SSHActionView) Accept() bool { return v.ж.Accept }
@@ -1230,6 +1562,28 @@ func (v *SSHPrincipalView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that SSHPrincipalView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*SSHPrincipalView)(nil)
_ (jsonv2.UnmarshalerV2) = (*SSHPrincipalView)(nil)
)
func (v SSHPrincipalView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *SSHPrincipalView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x SSHPrincipal
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v SSHPrincipalView) Node() StableNodeID { return v.ж.Node }
func (v SSHPrincipalView) NodeIP() string { return v.ж.NodeIP }
func (v SSHPrincipalView) UserLogin() string { return v.ж.UserLogin }
@@ -1290,6 +1644,28 @@ func (v *ControlDialPlanView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that ControlDialPlanView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*ControlDialPlanView)(nil)
_ (jsonv2.UnmarshalerV2) = (*ControlDialPlanView)(nil)
)
func (v ControlDialPlanView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *ControlDialPlanView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x ControlDialPlan
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v ControlDialPlanView) Candidates() views.Slice[ControlIPCandidate] {
return views.SliceOf(v.ж.Candidates)
}
@@ -1344,6 +1720,28 @@ func (v *LocationView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that LocationView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*LocationView)(nil)
_ (jsonv2.UnmarshalerV2) = (*LocationView)(nil)
)
func (v LocationView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *LocationView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x Location
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v LocationView) Country() string { return v.ж.Country }
func (v LocationView) CountryCode() string { return v.ж.CountryCode }
func (v LocationView) City() string { return v.ж.City }
@@ -1404,6 +1802,28 @@ func (v *UserProfileView) UnmarshalJSON(b []byte) error {
return nil
}
// Verify that UserProfileView implements jsonv2 interfaces.
var (
_ (jsonv2.MarshalerV2) = (*UserProfileView)(nil)
_ (jsonv2.UnmarshalerV2) = (*UserProfileView)(nil)
)
func (v UserProfileView) MarshalJSONV2(enc *jsontext.Encoder, opts jsonv2.Options) error {
return jsonv2.MarshalEncode(enc, v.ж, opts)
}
func (v *UserProfileView) UnmarshalJSONV2(dec *jsontext.Decoder, opts jsonv2.Options) error {
if v.ж != nil {
return errors.New("already initialized")
}
var x UserProfile
if err := jsonv2.UnmarshalDecode(dec, &x, opts); err != nil {
return err
}
v.ж = &x
return nil
}
func (v UserProfileView) ID() UserID { return v.ж.ID }
func (v UserProfileView) LoginName() string { return v.ж.LoginName }
func (v UserProfileView) DisplayName() string { return v.ж.DisplayName }

View File

@@ -74,12 +74,20 @@ func NewImportTracker(thisPkg *types.Package) *ImportTracker {
// ImportTracker provides a mechanism to track and build import paths.
type ImportTracker struct {
thisPkg *types.Package
packages map[string]bool
packages map[string]string // package paths to package names; empty name to use default
}
func (it *ImportTracker) Import(pkg string) {
if pkg != "" && !it.packages[pkg] {
mak.Set(&it.packages, pkg, true)
_, ok := it.packages[pkg]
if pkg != "" && !ok {
mak.Set(&it.packages, pkg, "")
}
}
func (it *ImportTracker) ImportNamed(pkg, name string) {
_, ok := it.packages[pkg]
if pkg != "" && !ok {
mak.Set(&it.packages, pkg, name)
}
}
@@ -100,8 +108,12 @@ func (it *ImportTracker) QualifiedName(t types.Type) string {
// Write prints all the tracked imports in a single import block to w.
func (it *ImportTracker) Write(w io.Writer) {
fmt.Fprintf(w, "import (\n")
for s := range it.packages {
fmt.Fprintf(w, "\t%q\n", s)
for pkgPath, pkgName := range it.packages {
if pkgName == "" {
fmt.Fprintf(w, "\t%q\n", pkgPath)
} else {
fmt.Fprintf(w, "\t%s %q\n", pkgName, pkgPath)
}
}
fmt.Fprintf(w, ")\n\n")
}