97 lines
1.9 KiB
Go
97 lines
1.9 KiB
Go
package rpc
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"git.lastassault.de/speatzle/morffix/constants"
|
|
"github.com/google/uuid"
|
|
"nhooyr.io/websocket"
|
|
)
|
|
|
|
func (s *server) Call(ctx context.Context, c *websocket.Conn, method string, params, result any) (*Response, error) {
|
|
id := uuid.New().String()
|
|
resp := make(chan *Response, 1)
|
|
|
|
var dataParams []byte
|
|
var err error
|
|
if params != nil {
|
|
dataParams, err = json.Marshal(params)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Error Marshalling Params: %w", err)
|
|
}
|
|
}
|
|
|
|
rawParams := json.RawMessage(dataParams)
|
|
|
|
req := Request{
|
|
ID: id,
|
|
Method: method,
|
|
Params: &rawParams,
|
|
}
|
|
|
|
reqData, err := json.Marshal(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Error Marshalling Request: %w", err)
|
|
}
|
|
|
|
// Add Call to Request Map
|
|
func() {
|
|
s.requestMutex.Lock()
|
|
defer s.requestMutex.Unlock()
|
|
|
|
s.requests[id] = resp
|
|
}()
|
|
|
|
// Remove Call from Request map
|
|
defer func() {
|
|
s.requestMutex.Lock()
|
|
defer s.requestMutex.Unlock()
|
|
|
|
delete(s.requests, id)
|
|
}()
|
|
|
|
// Write Request
|
|
err = c.Write(ctx, websocket.MessageText, reqData)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Error Writing Request: %w", err)
|
|
}
|
|
|
|
timeout := time.NewTimer(time.Second * 10)
|
|
|
|
select {
|
|
case response := <-resp:
|
|
// Cleanup timeout
|
|
if !timeout.Stop() {
|
|
<-timeout.C
|
|
}
|
|
if response.Error != nil {
|
|
return response, fmt.Errorf("Call Error (%v): %v", response.Error.Code, response.Error.Message)
|
|
}
|
|
|
|
if result == nil {
|
|
return response, nil
|
|
}
|
|
|
|
if response.Result == nil {
|
|
return response, fmt.Errorf("Got Empty Result")
|
|
}
|
|
|
|
err = json.Unmarshal(*response.Result, &result)
|
|
if err != nil {
|
|
return response, fmt.Errorf("Error Parsing Result: %w", err)
|
|
}
|
|
return response, nil
|
|
case <-timeout.C:
|
|
s.requestMutex.Lock()
|
|
defer s.requestMutex.Unlock()
|
|
|
|
// remove request from map
|
|
delete(s.requests, id)
|
|
return nil, constants.ErrRPCRequestTimeout
|
|
}
|
|
}
|
|
|
|
// TODO Call with Multiple Response (Chunked file upload)
|