2023-07-21 15:16:35 -06:00
|
|
|
package graphvent
|
|
|
|
import (
|
2023-07-29 16:34:21 -06:00
|
|
|
"reflect"
|
2023-09-18 11:15:58 -06:00
|
|
|
"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
|
|
|
)
|
|
|
|
|
2023-09-18 11:15:58 -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))
|
|
|
|
}
|
|
|
|
|
2023-09-18 12:02:30 -06:00
|
|
|
return node.NodeID, nil
|
2023-09-18 11:15:58 -06:00
|
|
|
}
|
|
|
|
|
2024-03-09 22:09:40 -07:00
|
|
|
func ResolveNodeType(p graphql.ResolveParams) (interface{}, error) {
|
2023-09-18 11:15:58 -06:00
|
|
|
node, ok := p.Source.(NodeResult)
|
|
|
|
if ok == false {
|
|
|
|
return nil, fmt.Errorf("Can't get TypeHash from %+v", reflect.TypeOf(p.Source))
|
|
|
|
}
|
|
|
|
|
2023-09-18 12:02:30 -06:00
|
|
|
return uint64(node.NodeType), nil
|
2023-09-18 11:15:58 -06:00
|
|
|
}
|
|
|
|
|
2024-03-17 14:25:34 -06:00
|
|
|
type FieldIndex struct {
|
|
|
|
Extension ExtType
|
|
|
|
Tag string
|
|
|
|
}
|
|
|
|
|
2024-03-28 20:28:07 -06:00
|
|
|
func GetFields(selection_set *ast.SelectionSet) []string {
|
|
|
|
names := []string{}
|
2023-07-29 16:34:21 -06:00
|
|
|
if selection_set == nil {
|
|
|
|
return names
|
|
|
|
}
|
2023-07-29 11:03:41 -06:00
|
|
|
|
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
|
|
|
|
}
|
2024-03-28 20:28:07 -06:00
|
|
|
names = append(names, field.Name.Value)
|
2023-07-29 16:34:21 -06:00
|
|
|
case *ast.InlineFragment:
|
2024-03-28 20:28:07 -06:00
|
|
|
names = append(names, GetFields(field.SelectionSet)...)
|
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
|
2024-03-28 20:28:07 -06:00
|
|
|
func GetResolveFields(p graphql.ResolveParams) []string {
|
|
|
|
fields := []string{}
|
2023-07-29 16:34:21 -06:00
|
|
|
for _, field := range(p.Info.FieldASTs) {
|
2024-03-28 20:28:07 -06:00
|
|
|
fields = append(fields, GetFields(field.SelectionSet)...)
|
2023-07-29 16:34:21 -06:00
|
|
|
}
|
|
|
|
|
2024-03-25 18:49:52 -06:00
|
|
|
return fields
|
|
|
|
}
|
|
|
|
|
|
|
|
func ResolveNode(id NodeID, p graphql.ResolveParams) (NodeResult, error) {
|
|
|
|
ctx, err := PrepResolve(p)
|
|
|
|
if err != nil {
|
|
|
|
return NodeResult{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch source := p.Source.(type) {
|
|
|
|
case *StatusSignal:
|
|
|
|
cached_node, cached := ctx.NodeCache[source.Source]
|
|
|
|
if cached {
|
2024-03-28 20:28:07 -06:00
|
|
|
for _, field_name := range(source.Fields) {
|
|
|
|
_, cached := cached_node.Data[field_name]
|
2024-03-25 18:49:52 -06:00
|
|
|
if cached {
|
2024-03-28 20:28:07 -06:00
|
|
|
delete(cached_node.Data, field_name)
|
2024-03-25 18:49:52 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ctx.NodeCache[source.Source] = cached_node
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-09 22:09:40 -07:00
|
|
|
cache, node_cached := ctx.NodeCache[id]
|
2024-03-28 20:28:07 -06:00
|
|
|
fields := GetResolveFields(p)
|
|
|
|
var not_cached []string
|
|
|
|
if node_cached {
|
|
|
|
not_cached = []string{}
|
|
|
|
for _, field := range(fields) {
|
|
|
|
if node_cached {
|
|
|
|
_, field_cached := cache.Data[field]
|
2024-03-09 22:09:40 -07:00
|
|
|
if field_cached {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-28 20:28:07 -06:00
|
|
|
not_cached = append(not_cached, field)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
not_cached = fields
|
2024-03-09 22:09:40 -07:00
|
|
|
}
|
|
|
|
|
2024-03-25 18:49:52 -06:00
|
|
|
if (len(not_cached) == 0) && (node_cached == true) {
|
|
|
|
ctx.Context.Log.Logf("gql", "No new fields to resolve for %s", id)
|
|
|
|
return cache, nil
|
|
|
|
} else {
|
|
|
|
ctx.Context.Log.Logf("gql", "Resolving fields %+v on node %s", not_cached, id)
|
|
|
|
|
|
|
|
signal := NewReadSignal(not_cached)
|
|
|
|
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
|
|
|
|
2024-03-25 18:49:52 -06:00
|
|
|
response, _, err := WaitForResponse(response_chan, 100*time.Millisecond, signal.ID())
|
2024-03-09 22:09:40 -07:00
|
|
|
ctx.Ext.FreeResponseChannel(signal.ID())
|
2024-03-25 18:49:52 -06:00
|
|
|
if err != nil {
|
|
|
|
return NodeResult{}, err
|
|
|
|
}
|
2024-03-09 22:09:40 -07:00
|
|
|
|
2024-03-25 18:49:52 -06:00
|
|
|
switch response := response.(type) {
|
|
|
|
case *ReadResultSignal:
|
|
|
|
if node_cached == false {
|
|
|
|
cache = NodeResult{
|
|
|
|
NodeID: id,
|
|
|
|
NodeType: response.NodeType,
|
2024-03-28 20:28:07 -06:00
|
|
|
Data: response.Fields,
|
2024-03-09 22:09:40 -07:00
|
|
|
}
|
2024-03-25 18:49:52 -06:00
|
|
|
} else {
|
2024-03-28 20:28:07 -06:00
|
|
|
for field_name, field_value := range(response.Fields) {
|
|
|
|
cache.Data[field_name] = field_value
|
2024-03-25 18:49:52 -06:00
|
|
|
}
|
2024-03-09 22:09:40 -07:00
|
|
|
}
|
|
|
|
|
2024-03-25 18:49:52 -06:00
|
|
|
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
|
|
|
}
|