pk.Option improvement
This commit is contained in:
29
bot/mcbot.go
29
bot/mcbot.go
@ -6,10 +6,7 @@ package bot
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
|
||||||
"encoding/pem"
|
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@ -79,12 +76,12 @@ func (c *Client) join(ctx context.Context, d *mcnet.Dialer, addr string) error {
|
|||||||
}
|
}
|
||||||
// Login Start
|
// Login Start
|
||||||
c.KeyPair, err = user.GetOrFetchKeyPair(c.Auth.AsTk)
|
c.KeyPair, err = user.GetOrFetchKeyPair(c.Auth.AsTk)
|
||||||
KeyPair := pk.Option[keyPair]{
|
KeyPair := pk.OptionEncoder[user.KeyPairResp]{
|
||||||
Has: err == nil,
|
Has: err == nil,
|
||||||
Val: keyPair(c.KeyPair),
|
Val: c.KeyPair,
|
||||||
}
|
}
|
||||||
c.UUID, err = uuid.Parse(c.Auth.UUID)
|
c.UUID, err = uuid.Parse(c.Auth.UUID)
|
||||||
PlayerUUID := pk.Option[pk.UUID]{
|
PlayerUUID := pk.Option[pk.UUID, *pk.UUID]{
|
||||||
Has: err == nil,
|
Has: err == nil,
|
||||||
Val: pk.UUID(c.UUID),
|
Val: pk.UUID(c.UUID),
|
||||||
}
|
}
|
||||||
@ -146,7 +143,7 @@ func (c *Client) join(ctx context.Context, d *mcnet.Dialer, addr string) error {
|
|||||||
return LoginErr{"Login Plugin", err}
|
return LoginErr{"Login Plugin", err}
|
||||||
}
|
}
|
||||||
|
|
||||||
var PluginMessageData pk.Option[pk.PluginMessageData]
|
var PluginMessageData pk.Option[pk.PluginMessageData, *pk.PluginMessageData]
|
||||||
if handler, ok := c.LoginPlugin[string(channel)]; ok {
|
if handler, ok := c.LoginPlugin[string(channel)]; ok {
|
||||||
PluginMessageData.Has = true
|
PluginMessageData.Has = true
|
||||||
PluginMessageData.Val, err = handler(data)
|
PluginMessageData.Val, err = handler(data)
|
||||||
@ -165,24 +162,6 @@ func (c *Client) join(ctx context.Context, d *mcnet.Dialer, addr string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type keyPair user.KeyPairResp
|
|
||||||
|
|
||||||
func (k keyPair) WriteTo(w io.Writer) (int64, error) {
|
|
||||||
block, _ := pem.Decode([]byte(k.KeyPair.PublicKey))
|
|
||||||
if block == nil {
|
|
||||||
return 0, errors.New("pem decode error: no data is found")
|
|
||||||
}
|
|
||||||
signature, err := base64.StdEncoding.DecodeString(k.PublicKeySignature)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return pk.Tuple{
|
|
||||||
pk.Long(k.ExpiresAt.UnixMilli()),
|
|
||||||
pk.ByteArray(block.Bytes),
|
|
||||||
pk.ByteArray(signature),
|
|
||||||
}.WriteTo(w)
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoginErr struct {
|
type LoginErr struct {
|
||||||
Stage string
|
Stage string
|
||||||
Err error
|
Err error
|
||||||
|
@ -479,8 +479,8 @@ func (u *UUID) ReadFrom(r io.Reader) (n int64, err error) {
|
|||||||
return int64(nn), err
|
return int64(nn), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PluginMessageData) WriteTo(w io.Writer) (n int64, err error) {
|
func (p PluginMessageData) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
nn, err := w.Write(*p)
|
nn, err := w.Write(p)
|
||||||
return int64(nn), err
|
return int64(nn), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ Field = (*Option[Field])(nil)
|
_ Field = (*Option[VarInt, *VarInt])(nil)
|
||||||
_ Field = (*Ary[VarInt])(nil)
|
_ Field = (*Ary[VarInt])(nil)
|
||||||
_ Field = Tuple(nil)
|
_ Field = Tuple(nil)
|
||||||
)
|
)
|
||||||
@ -139,29 +139,65 @@ func (o Opt) ReadFrom(r io.Reader) (int64, error) {
|
|||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Option[T any] struct {
|
type fieldPointer[T any] interface {
|
||||||
|
*T
|
||||||
|
FieldDecoder
|
||||||
|
}
|
||||||
|
|
||||||
|
// Currently we have to repeat T in the type arguments.
|
||||||
|
//
|
||||||
|
// var opt Option[String, *String]
|
||||||
|
//
|
||||||
|
// Constraint type will inference makes it less awkward in the future.
|
||||||
|
// See: https://github.com/golang/go/issues/54469
|
||||||
|
type Option[T FieldEncoder, P fieldPointer[T]] struct {
|
||||||
Has Boolean
|
Has Boolean
|
||||||
Val T
|
Val T
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o Option[T]) WriteTo(w io.Writer) (n int64, err error) {
|
func (o Option[T, P]) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
n1, err := o.Has.WriteTo(w)
|
n1, err := o.Has.WriteTo(w)
|
||||||
if err != nil || !o.Has {
|
if err != nil || !o.Has {
|
||||||
return n1, err
|
return n1, err
|
||||||
}
|
}
|
||||||
n2, err := any(&o.Val).(FieldEncoder).WriteTo(w)
|
n2, err := o.Val.WriteTo(w)
|
||||||
return n1 + n2, err
|
return n1 + n2, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Option[T]) ReadFrom(r io.Reader) (n int64, err error) {
|
func (o *Option[T, P]) ReadFrom(r io.Reader) (n int64, err error) {
|
||||||
n1, err := o.Has.ReadFrom(r)
|
n1, err := o.Has.ReadFrom(r)
|
||||||
if err != nil || !o.Has {
|
if err != nil || !o.Has {
|
||||||
return n1, err
|
return n1, err
|
||||||
}
|
}
|
||||||
// This lose performance, but current Golang doesn't provide any better solution.
|
n2, err := P(&o.Val).ReadFrom(r)
|
||||||
// I hope Go support we declare type constraint like `Option[*T Field]` in the future
|
return n1 + n2, err
|
||||||
// and then we can prevent using any dynamic dispatch.
|
}
|
||||||
n2, err := any(&o.Val).(FieldDecoder).ReadFrom(r)
|
|
||||||
|
type OptionDecoder[T any, P fieldPointer[T]] struct {
|
||||||
|
Has Boolean
|
||||||
|
Val T
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OptionDecoder[T, P]) ReadFrom(r io.Reader) (n int64, err error) {
|
||||||
|
n1, err := o.Has.ReadFrom(r)
|
||||||
|
if err != nil || !o.Has {
|
||||||
|
return n1, err
|
||||||
|
}
|
||||||
|
n2, err := P(&o.Val).ReadFrom(r)
|
||||||
|
return n1 + n2, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type OptionEncoder[T FieldEncoder] struct {
|
||||||
|
Has Boolean
|
||||||
|
Val T
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OptionEncoder[T]) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
|
n1, err := o.Has.WriteTo(w)
|
||||||
|
if err != nil || !o.Has {
|
||||||
|
return n1, err
|
||||||
|
}
|
||||||
|
n2, err := o.Val.WriteTo(w)
|
||||||
return n1 + n2, err
|
return n1 + n2, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ func ExampleOption_ReadFrom_func() {
|
|||||||
// empty
|
// empty
|
||||||
}}
|
}}
|
||||||
|
|
||||||
var User1, User2 pk.Option[pk.String]
|
var User1, User2 pk.Option[pk.String, *pk.String]
|
||||||
if err := p1.Scan(&User1); err != nil {
|
if err := p1.Scan(&User1); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ type PublicKey struct {
|
|||||||
Signature []byte
|
Signature []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PublicKey) WriteTo(w io.Writer) (n int64, err error) {
|
func (p PublicKey) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
pubKeyEncoded, err := x509.MarshalPKIXPublicKey(p.PubKey)
|
pubKeyEncoded, err := x509.MarshalPKIXPublicKey(p.PubKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
@ -64,8 +64,8 @@ func (d *MojangLoginHandler) AcceptLogin(conn *net.Conn, protocol int32) (name s
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
pubKey pk.Option[auth.PublicKey]
|
pubKey pk.Option[auth.PublicKey, *auth.PublicKey]
|
||||||
profileUUID pk.Option[pk.UUID] // ignored
|
profileUUID pk.Option[pk.UUID, *pk.UUID] // ignored
|
||||||
)
|
)
|
||||||
err = p.Scan(
|
err = p.Scan(
|
||||||
(*pk.String)(&name), // decode username as pk.String
|
(*pk.String)(&name), // decode username as pk.String
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
pk "github.com/Tnze/go-mc/net/packet"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ServicesURL = "https://api.minecraftservices.com"
|
var ServicesURL = "https://api.minecraftservices.com"
|
||||||
@ -21,6 +27,22 @@ type KeyPairResp struct {
|
|||||||
RefreshedAfter time.Time `json:"refreshedAfter"`
|
RefreshedAfter time.Time `json:"refreshedAfter"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (k KeyPairResp) WriteTo(w io.Writer) (int64, error) {
|
||||||
|
block, _ := pem.Decode([]byte(k.KeyPair.PublicKey))
|
||||||
|
if block == nil {
|
||||||
|
return 0, errors.New("pem decode error: no data is found")
|
||||||
|
}
|
||||||
|
signature, err := base64.StdEncoding.DecodeString(k.PublicKeySignature)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return pk.Tuple{
|
||||||
|
pk.Long(k.ExpiresAt.UnixMilli()),
|
||||||
|
pk.ByteArray(block.Bytes),
|
||||||
|
pk.ByteArray(signature),
|
||||||
|
}.WriteTo(w)
|
||||||
|
}
|
||||||
|
|
||||||
func GetOrFetchKeyPair(accessToken string) (KeyPairResp, error) {
|
func GetOrFetchKeyPair(accessToken string) (KeyPairResp, error) {
|
||||||
return fetchKeyPair(accessToken) // TODO: cache
|
return fetchKeyPair(accessToken) // TODO: cache
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user