graphvent/gql_node.go

159 lines
4.1 KiB
Go

2023-07-21 15:16:35 -06:00
package graphvent
import (
2023-07-29 16:34:21 -06:00
"reflect"
"fmt"
2024-03-09 22:09:40 -07:00
"time"
2023-07-21 15:16:35 -06:00
"github.com/graphql-go/graphql"
2023-07-29 11:03:41 -06:00
"github.com/graphql-go/graphql/language/ast"
2023-07-21 15:16:35 -06:00
)
func ResolveNodeID(p graphql.ResolveParams) (interface{}, error) {
node, ok := p.Source.(NodeResult)
if ok == false {
return nil, fmt.Errorf("Can't get NodeID from %+v", reflect.TypeOf(p.Source))
}
return node.NodeID, nil
}
2024-03-09 22:09:40 -07:00
func ResolveNodeType(p graphql.ResolveParams) (interface{}, error) {
node, ok := p.Source.(NodeResult)
if ok == false {
return nil, fmt.Errorf("Can't get TypeHash from %+v", reflect.TypeOf(p.Source))
}
return uint64(node.NodeType), nil
}
2024-03-17 14:25:34 -06:00
type FieldIndex struct {
Extension ExtType
Tag string
}
func GetFields(ctx *Context, node_type string, selection_set *ast.SelectionSet) []FieldIndex {
names := []FieldIndex{}
2023-07-29 16:34:21 -06:00
if selection_set == nil {
return names
}
2023-07-29 11:03:41 -06:00
2024-03-17 14:25:34 -06:00
node_info, mapped := ctx.NodeTypes[node_type]
if mapped == false {
return nil
}
2023-07-29 16:34:21 -06:00
for _, sel := range(selection_set.Selections) {
switch field := sel.(type) {
case *ast.Field:
2024-03-17 14:25:34 -06:00
if field.Name.Value == "ID" || field.Name.Value == "Type" {
continue
}
extension, mapped := node_info.Fields[field.Name.Value]
if mapped == false {
continue
}
names = append(names, FieldIndex{extension, field.Name.Value})
2023-07-29 16:34:21 -06:00
case *ast.InlineFragment:
2024-03-17 14:25:34 -06:00
names = append(names, GetFields(ctx, field.TypeCondition.Name.Value, field.SelectionSet)...)
2023-07-29 16:34:21 -06:00
default:
ctx.Log.Logf("gql", "Unknown selection type: %s", reflect.TypeOf(field))
2023-07-29 11:03:41 -06:00
}
}
return names
}
2024-03-09 22:09:40 -07:00
// Returns the fields that need to be resolved
func GetResolveFields(id NodeID, ctx *ResolveContext, p graphql.ResolveParams) (map[ExtType][]string, error) {
2024-03-17 14:25:34 -06:00
m := map[ExtType][]string{}
fields := []FieldIndex{}
2023-07-29 16:34:21 -06:00
for _, field := range(p.Info.FieldASTs) {
2024-03-17 14:25:34 -06:00
fields = append(fields, GetFields(ctx.Context, p.Info.ReturnType.Name(), field.SelectionSet)...)
2023-07-29 16:34:21 -06:00
}
2024-03-09 22:09:40 -07:00
cache, node_cached := ctx.NodeCache[id]
2024-03-17 14:25:34 -06:00
for _, field := range(fields) {
ext_fields, exists := m[field.Extension]
2024-03-09 22:09:40 -07:00
if exists == false {
ext_fields = []string{}
}
if node_cached {
2024-03-17 14:25:34 -06:00
ext_cache, ext_cached := cache.Data[field.Extension]
2024-03-09 22:09:40 -07:00
if ext_cached {
2024-03-17 14:25:34 -06:00
_, field_cached := ext_cache[field.Tag]
2024-03-09 22:09:40 -07:00
if field_cached {
continue
}
}
}
2024-03-17 14:25:34 -06:00
m[field.Extension] = append(ext_fields, field.Tag)
2024-03-09 22:09:40 -07:00
}
2024-03-17 14:25:34 -06:00
return m, nil
2024-03-09 22:09:40 -07:00
}
// TODO: instead of doing the read right away, check if any new fields need to be read
func ResolveNode(id NodeID, p graphql.ResolveParams) (NodeResult, error) {
2024-03-09 22:09:40 -07:00
ctx, err := PrepResolve(p)
if err != nil {
return NodeResult{}, err
2024-03-09 22:09:40 -07:00
}
fields, err := GetResolveFields(id, ctx, p)
if err != nil {
return NodeResult{}, err
2024-03-09 22:09:40 -07:00
}
ctx.Context.Log.Logf("gql", "Resolving fields %+v on node %s", fields, id)
signal := NewReadSignal(fields)
response_chan := ctx.Ext.GetResponseChannel(signal.ID())
// TODO: TIMEOUT DURATION
err = ctx.Context.Send(ctx.Server, []SendMsg{{
Dest: id,
Signal: signal,
}})
if err != nil {
ctx.Ext.FreeResponseChannel(signal.ID())
return NodeResult{}, err
2024-03-09 22:09:40 -07:00
}
response, _, err := WaitForResponse(response_chan, 100*time.Millisecond, signal.ID())
ctx.Ext.FreeResponseChannel(signal.ID())
if err != nil {
return NodeResult{}, err
2024-03-09 22:09:40 -07:00
}
switch response := response.(type) {
case *ReadResultSignal:
cache, node_cached := ctx.NodeCache[id]
if node_cached == false {
cache = NodeResult{
NodeID: id,
NodeType: response.NodeType,
Data: response.Extensions,
}
} else {
for ext_type, ext_data := range(response.Extensions) {
cached_ext, ext_cached := cache.Data[ext_type]
if ext_cached {
for field_name, field := range(ext_data) {
cache.Data[ext_type][field_name] = field
}
} else {
cache.Data[ext_type] = ext_data
}
cache.Data[ext_type] = cached_ext
}
}
ctx.NodeCache[id] = cache
return ctx.NodeCache[id], nil
default:
return NodeResult{}, fmt.Errorf("Bad read response: %+v", response)
2024-03-09 22:09:40 -07:00
}
2023-07-29 16:34:21 -06:00
}