mirror of
https://github.com/wisplite/tether.git
synced 2026-05-01 06:22:41 -05:00
fix the bugs that were causing mutation response errors, and add duplicate subscription checks
MUTATIONS WORK BTW!!!
This commit is contained in:
@@ -176,8 +176,15 @@ func (e *Engine) ExecuteQuery(query string, params map[string]interface{}, clien
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Engine) ExecuteMutation(mutation string, params map[string]interface{}, clientID string) (interface{}, error) {
|
func (e *Engine) ExecuteMutation(mutation string, params map[string]interface{}, clientID string, mutationID string) (interface{}, error) {
|
||||||
result := e.mutations[mutation](&MutationCtx{DB: e.db, AuthCtx: &AuthCtx{UserID: "", IsLoggedIn: true}, Params: params})
|
result := e.mutations[mutation](&MutationCtx{DB: e.db, AuthCtx: &AuthCtx{UserID: "", IsLoggedIn: true}, Params: params})
|
||||||
|
slog.Debug("Executing mutation", "mutation", mutation, "params", params, "result", result)
|
||||||
|
responseJSON, err := json.Marshal(map[string]interface{}{"type": "mutation", "location": mutation, "data": result, "mutation_id": mutationID})
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to encode mutation result", "mutation", mutation, "error", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
e.tracker.SendMessage(clientID, responseJSON)
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +199,7 @@ func (e *Engine) OnReceiveMessage(clientID string, msg map[string]interface{}) e
|
|||||||
e.tracker.SubscribeToQuery(clientID, msg["location"].(string), string(paramsJSON))
|
e.tracker.SubscribeToQuery(clientID, msg["location"].(string), string(paramsJSON))
|
||||||
e.ExecuteQuery(msg["location"].(string), msg["params"].(map[string]interface{}), clientID, true)
|
e.ExecuteQuery(msg["location"].(string), msg["params"].(map[string]interface{}), clientID, true)
|
||||||
case "mutation":
|
case "mutation":
|
||||||
e.ExecuteMutation(msg["location"].(string), msg["params"].(map[string]interface{}), clientID)
|
e.ExecuteMutation(msg["location"].(string), msg["params"].(map[string]interface{}), clientID, msg["mutation_id"].(string))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ const rl = createInterface({
|
|||||||
while (true) {
|
while (true) {
|
||||||
const message = await rl.question("Enter a message");
|
const message = await rl.question("Enter a message");
|
||||||
if (message) {
|
if (message) {
|
||||||
client.sendMutation("createMessage", { room: "1", message: message });
|
const result = await client.sendMutation("createMessage", { room: "1", message: message });
|
||||||
|
console.log("Mutation result", result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Generated
+1
-1
@@ -28,7 +28,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/tether-ts": {
|
"node_modules/tether-ts": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "git+ssh://git@github.com/wisplite/tether-ts.git#8945de00ece92ce1e939a3ff70c5312f80e56dda",
|
"resolved": "git+ssh://git@github.com/wisplite/tether-ts.git#82a462ee116789dd6832fe5ff079a63fcb91afc4",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
|
|||||||
+5
-2
@@ -42,8 +42,11 @@ func main() {
|
|||||||
}, []string{"messages"})
|
}, []string{"messages"})
|
||||||
|
|
||||||
engine.RegisterMutation("createMessage", func(ctx *tether.MutationCtx) interface{} {
|
engine.RegisterMutation("createMessage", func(ctx *tether.MutationCtx) interface{} {
|
||||||
ctx.DB.Create(&Messages{ID: uuid.NewString(), Message: ctx.Params["message"].(string), SenderID: ctx.AuthCtx.UserID, RoomID: ctx.Params["room"].(string)})
|
msg := &Messages{ID: uuid.NewString(), Message: ctx.Params["message"].(string), SenderID: ctx.AuthCtx.UserID, RoomID: ctx.Params["room"].(string)}
|
||||||
return nil
|
if err := ctx.DB.Create(msg).Error; err != nil {
|
||||||
|
return map[string]interface{}{"error": err.Error()}
|
||||||
|
}
|
||||||
|
return msg
|
||||||
})
|
})
|
||||||
|
|
||||||
http.HandleFunc("/tether", engine.Handle)
|
http.HandleFunc("/tether", engine.Handle)
|
||||||
|
|||||||
+33
-2
@@ -2,6 +2,7 @@ package reactivity
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"slices"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -13,11 +14,16 @@ type Tracker struct {
|
|||||||
clients map[string]*Client
|
clients map[string]*Client
|
||||||
|
|
||||||
// Maps a Query Hash (e.g. "getUser?id=1") to a Set of Client IDs
|
// Maps a Query Hash (e.g. "getUser?id=1") to a Set of Client IDs
|
||||||
subscriptions map[string][]map[string]string
|
subscriptions map[string][]map[string]string
|
||||||
|
clientSubscriptions map[string][]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTracker() *Tracker {
|
func NewTracker() *Tracker {
|
||||||
return &Tracker{clients: make(map[string]*Client), subscriptions: make(map[string][]map[string]string)}
|
return &Tracker{
|
||||||
|
clients: make(map[string]*Client),
|
||||||
|
subscriptions: make(map[string][]map[string]string),
|
||||||
|
clientSubscriptions: make(map[string][]string),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracker) Track(c *Client) {
|
func (t *Tracker) Track(c *Client) {
|
||||||
@@ -30,6 +36,20 @@ func (t *Tracker) Untrack(c *Client) {
|
|||||||
t.mu.Lock()
|
t.mu.Lock()
|
||||||
defer t.mu.Unlock()
|
defer t.mu.Unlock()
|
||||||
delete(t.clients, c.ID)
|
delete(t.clients, c.ID)
|
||||||
|
delete(t.clientSubscriptions, c.ID)
|
||||||
|
for query, subs := range t.subscriptions {
|
||||||
|
kept := subs[:0]
|
||||||
|
for _, sub := range subs {
|
||||||
|
if sub["clientID"] != c.ID {
|
||||||
|
kept = append(kept, sub)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(kept) == 0 {
|
||||||
|
delete(t.subscriptions, query)
|
||||||
|
} else {
|
||||||
|
t.subscriptions[query] = kept
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracker) SetAuthID(clientID string, authID string) {
|
func (t *Tracker) SetAuthID(clientID string, authID string) {
|
||||||
@@ -39,6 +59,10 @@ func (t *Tracker) SetAuthID(clientID string, authID string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracker) GetAuthID(clientID string) string {
|
func (t *Tracker) GetAuthID(clientID string) string {
|
||||||
|
if _, ok := t.clients[clientID]; !ok {
|
||||||
|
slog.Error("Tracker: Client not found", "clientID", clientID)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
return t.clients[clientID].GetAuthID()
|
return t.clients[clientID].GetAuthID()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,6 +72,13 @@ func (t *Tracker) SubscribeToQuery(clientID string, query string, params string)
|
|||||||
if t.subscriptions[query] == nil {
|
if t.subscriptions[query] == nil {
|
||||||
t.subscriptions[query] = make([]map[string]string, 0)
|
t.subscriptions[query] = make([]map[string]string, 0)
|
||||||
}
|
}
|
||||||
|
if t.clientSubscriptions[clientID] == nil {
|
||||||
|
t.clientSubscriptions[clientID] = make([]string, 0)
|
||||||
|
}
|
||||||
|
if slices.Contains(t.clientSubscriptions[clientID], query) {
|
||||||
|
return // avoid duplicate subscriptions
|
||||||
|
}
|
||||||
|
t.clientSubscriptions[clientID] = append(t.clientSubscriptions[clientID], query)
|
||||||
// set t.subscriptions[query] to a map of client IDs and their params
|
// set t.subscriptions[query] to a map of client IDs and their params
|
||||||
t.subscriptions[query] = append(t.subscriptions[query], map[string]string{"clientID": clientID, "params": params})
|
t.subscriptions[query] = append(t.subscriptions[query], map[string]string{"clientID": clientID, "params": params})
|
||||||
slog.Debug("Tracker: Subscribed to query", "query", query, "clientID", clientID, "params", params)
|
slog.Debug("Tracker: Subscribed to query", "query", query, "clientID", clientID, "params", params)
|
||||||
|
|||||||
Reference in New Issue
Block a user