Add login support for WebSocket API
This commit is contained in:
		
							
								
								
									
										78
									
								
								websocket.go
									
									
									
									
									
								
							
							
						
						
									
										78
									
								
								websocket.go
									
									
									
									
									
								
							@@ -1,18 +1,27 @@
 | 
				
			|||||||
package lemmy
 | 
					package lemmy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/mitchellh/mapstructure"
 | 
					 | 
				
			||||||
	"github.com/recws-org/recws"
 | 
						"github.com/recws-org/recws"
 | 
				
			||||||
	"go.arsenm.dev/go-lemmy/types"
 | 
						"go.arsenm.dev/go-lemmy/types"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type authData struct {
 | 
				
			||||||
 | 
						Auth string `json:"auth"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type WSClient struct {
 | 
					type WSClient struct {
 | 
				
			||||||
	conn    *recws.RecConn
 | 
						conn    *recws.RecConn
 | 
				
			||||||
 | 
						baseURL *url.URL
 | 
				
			||||||
	respCh  chan types.LemmyWebSocketMsg
 | 
						respCh  chan types.LemmyWebSocketMsg
 | 
				
			||||||
	errCh   chan error
 | 
						errCh   chan error
 | 
				
			||||||
 | 
						token   string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewWebSocket(baseURL string) (*WSClient, error) {
 | 
					func NewWebSocket(baseURL string) (*WSClient, error) {
 | 
				
			||||||
@@ -26,10 +35,11 @@ func NewWebSocket(baseURL string) (*WSClient, error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	u = u.JoinPath("/api/v3")
 | 
						u = u.JoinPath("/api/v3")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ws.Dial(u.String(), nil)
 | 
						ws.Dial(u.JoinPath("ws").String(), nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	out := &WSClient{
 | 
						out := &WSClient{
 | 
				
			||||||
		conn:    ws,
 | 
							conn:    ws,
 | 
				
			||||||
 | 
							baseURL: u,
 | 
				
			||||||
		respCh:  make(chan types.LemmyWebSocketMsg, 10),
 | 
							respCh:  make(chan types.LemmyWebSocketMsg, 10),
 | 
				
			||||||
		errCh:   make(chan error, 10),
 | 
							errCh:   make(chan error, 10),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -49,10 +59,40 @@ func NewWebSocket(baseURL string) (*WSClient, error) {
 | 
				
			|||||||
	return out, nil
 | 
						return out, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *WSClient) Login(ctx context.Context, l types.Login) error {
 | 
				
			||||||
 | 
						u := &url.URL{}
 | 
				
			||||||
 | 
						*u = *c.baseURL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if u.Scheme == "ws" {
 | 
				
			||||||
 | 
							u.Scheme = "http"
 | 
				
			||||||
 | 
						} else if u.Scheme == "wss" {
 | 
				
			||||||
 | 
							u.Scheme = "https"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hc := &Client{baseURL: u, client: http.DefaultClient}
 | 
				
			||||||
 | 
						err := hc.Login(ctx, l)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						c.token = hc.token
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *WSClient) Request(op types.UserOperation, data any) error {
 | 
					func (c *WSClient) Request(op types.UserOperation, data any) error {
 | 
				
			||||||
 | 
						if data == nil {
 | 
				
			||||||
 | 
							data = authData{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data = c.setAuth(data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						d, err := json.Marshal(data)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return c.conn.WriteJSON(types.LemmyWebSocketMsg{
 | 
						return c.conn.WriteJSON(types.LemmyWebSocketMsg{
 | 
				
			||||||
		Op:   op,
 | 
							Op:   op,
 | 
				
			||||||
		Data: data,
 | 
							Data: d,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -64,13 +104,29 @@ func (c *WSClient) Errors() <-chan error {
 | 
				
			|||||||
	return c.errCh
 | 
						return c.errCh
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func DecodeResponse(data, out any) error {
 | 
					func (c *WSClient) setAuth(data any) any {
 | 
				
			||||||
	dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
 | 
						val := reflect.New(reflect.TypeOf(data))
 | 
				
			||||||
		TagName: "json",
 | 
						val.Elem().Set(reflect.ValueOf(data))
 | 
				
			||||||
		Result:  out,
 | 
					
 | 
				
			||||||
	})
 | 
						authField := val.Elem().FieldByName("Auth")
 | 
				
			||||||
	if err != nil {
 | 
						if !authField.IsValid() {
 | 
				
			||||||
		return err
 | 
							return data
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return dec.Decode(data)
 | 
					
 | 
				
			||||||
 | 
						switch authField.Type().String() {
 | 
				
			||||||
 | 
						case "string":
 | 
				
			||||||
 | 
							authField.SetString(c.token)
 | 
				
			||||||
 | 
						case "types.Optional[string]":
 | 
				
			||||||
 | 
							setMtd := authField.MethodByName("Set")
 | 
				
			||||||
 | 
							out := setMtd.Call([]reflect.Value{reflect.ValueOf(c.token)})
 | 
				
			||||||
 | 
							authField.Set(out[0])
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return data
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return val.Elem().Interface()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func DecodeResponse(data json.RawMessage, out any) error {
 | 
				
			||||||
 | 
						return json.Unmarshal(data, out)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user