Renamed GQL functions to remove GQL

gql_cataclysm
noah metz 2023-07-29 11:03:41 -06:00
parent c60393d390
commit 2dfa10b1f6
9 changed files with 172 additions and 177 deletions

@ -13,13 +13,13 @@ import (
)
// A Type can be Hashed by Hash
type Type interface {
type TypeName interface {
String() string
Prefix() string
}
// Hashed a Type to a uint64
func Hash(t Type) uint64 {
func Hash(t TypeName) uint64 {
hash := sha512.Sum512([]byte(fmt.Sprintf("%s%s", t.Prefix(), t.String())))
return binary.BigEndian.Uint64(hash[(len(hash)-9):(len(hash)-1)])
}
@ -273,7 +273,7 @@ func NewContext(db * badger.DB, log Logger) (*Context, error) {
return nil, err
}
err = gql_ctx.RegisterNodeType(GQLNodeType, GQLTypeGQLNode.Type)
err = gql_ctx.RegisterNodeType(GQLNodeType, TypeGQLNode.Type)
if err != nil {
return nil, err
}

114
gql.go

@ -420,20 +420,20 @@ func GQLWSHandler(ctx * Context, server *Node, gql_ext *GQLExt) func(http.Respon
}
}
type GQLInterface struct {
type Interface struct {
Interface *graphql.Interface
Default *graphql.Object
List *graphql.List
Extensions []ExtType
}
type GQLType struct {
type Type struct {
Type *graphql.Object
List *graphql.List
}
func NewGQLNodeType(node_type NodeType, interfaces []*graphql.Interface, init func(*GQLType)) *GQLType {
var gql GQLType
func NewGQLNodeType(node_type NodeType, interfaces []*graphql.Interface, init func(*Type)) *Type {
var gql Type
gql.Type = graphql.NewObject(graphql.ObjectConfig{
Name: string(node_type),
Interfaces: interfaces,
@ -452,8 +452,8 @@ func NewGQLNodeType(node_type NodeType, interfaces []*graphql.Interface, init fu
return &gql
}
func NewGQLInterface(if_name string, default_name string, interfaces []*graphql.Interface, extensions []ExtType, init_1 func(*GQLInterface), init_2 func(*GQLInterface)) *GQLInterface {
var gql GQLInterface
func NewInterface(if_name string, default_name string, interfaces []*graphql.Interface, extensions []ExtType, init_1 func(*Interface), init_2 func(*Interface)) *Interface {
var gql Interface
gql.Extensions = extensions
gql.Interface = graphql.NewInterface(graphql.InterfaceConfig{
Name: if_name,
@ -488,7 +488,7 @@ type GQLExtContext struct {
// Custom graphql types, mapped to NodeTypes
NodeTypes map[NodeType]*graphql.Object
Interfaces []*GQLInterface
Interfaces []*Interface
// Schema parameters
Types []graphql.Type
@ -508,7 +508,7 @@ func BuildSchema(ctx *GQLExtContext) (graphql.Schema, error) {
return graphql.NewSchema(schemaConfig)
}
func (ctx *GQLExtContext) AddInterface(i *GQLInterface) error {
func (ctx *GQLExtContext) AddInterface(i *Interface) error {
if i == nil {
return fmt.Errorf("interface is nil")
}
@ -544,24 +544,23 @@ func NewGQLExtContext() *GQLExtContext {
Fields: graphql.Fields{},
})
query.AddFieldConfig("Self", GQLQuerySelf)
query.AddFieldConfig("Node", GQLQueryNode)
query.AddFieldConfig("Self", QuerySelf)
query.AddFieldConfig("Node", QueryNode)
mutation := graphql.NewObject(graphql.ObjectConfig{
Name: "Mutation",
Fields: graphql.Fields{},
})
mutation.AddFieldConfig("stop", GQLMutationStop)
mutation.AddFieldConfig("startChild", GQLMutationStartChild)
mutation.AddFieldConfig("stop", MutationStop)
subscription := graphql.NewObject(graphql.ObjectConfig{
Name: "Subscription",
Fields: graphql.Fields{},
})
subscription.AddFieldConfig("Self", GQLSubscriptionSelf)
subscription.AddFieldConfig("Update", GQLSubscriptionUpdate)
subscription.AddFieldConfig("Self", SubscriptionSelf)
subscription.AddFieldConfig("Self", SubscriptionNode)
context := GQLExtContext{
Schema: graphql.Schema{},
@ -570,15 +569,15 @@ func NewGQLExtContext() *GQLExtContext {
Mutation: mutation,
Subscription: subscription,
NodeTypes: map[NodeType]*graphql.Object{},
Interfaces: []*GQLInterface{},
Interfaces: []*Interface{},
}
var err error
err = context.AddInterface(GQLInterfaceNode)
err = context.AddInterface(InterfaceNode)
if err != nil {
panic(err)
}
err = context.AddInterface(GQLInterfaceLockable)
err = context.AddInterface(InterfaceLockable)
if err != nil {
panic(err)
}
@ -597,12 +596,10 @@ type GQLExt struct {
tcp_listener net.Listener
http_server *http.Server
http_done sync.WaitGroup
tls_key []byte
tls_cert []byte
Listen string
SubscribeLock sync.Mutex
SubscribeListeners []chan Signal
}
func (ext *GQLExt) Field(name string) interface{} {
@ -613,37 +610,24 @@ func (ext *GQLExt) Field(name string) interface{} {
})
}
func (ext *GQLExt) NewSubscriptionChannel(buffer int) chan Signal {
ext.SubscribeLock.Lock()
defer ext.SubscribeLock.Unlock()
new_listener := make(chan Signal, buffer)
ext.SubscribeListeners = append(ext.SubscribeListeners, new_listener)
return new_listener
}
func (ext *GQLExt) Process(context *Context, princ_id NodeID, node *Node, signal Signal) {
if signal.Type() == ReadResultSignalType {
func (ext *GQLExt) Process(ctx *Context, source NodeID, node *Node, signal Signal) {
if signal.Type() == GQLStateSignalType {
sig := signal.(StateSignal)
switch sig.State {
case "start_server":
err := ext.StartGQLServer(ctx, node)
if err == nil {
ctx.Send(node.ID, source, StateSignal{NewDirectSignal(GQLStateSignalType), "server_started"})
}
case "stop_server":
err := ext.StopGQLServer()
if err == nil {
ctx.Send(node.ID, source, StateSignal{NewDirectSignal(GQLStateSignalType), "server_stopped"})
}
ext.SubscribeLock.Lock()
defer ext.SubscribeLock.Unlock()
active_listeners := []chan Signal{}
for _, listener := range(ext.SubscribeListeners) {
select {
case listener <- signal:
active_listeners = append(active_listeners, listener)
default:
go func(listener chan Signal) {
listener <- NewDirectSignal("Channel Closed")
close(listener)
}(listener)
ctx.Log.Logf("gql", "unknown gql state %s", sig.State)
}
}
ext.SubscribeListeners = active_listeners
return
}
func (ext *GQLExt) Type() ExtType {
@ -732,16 +716,18 @@ func NewGQLExt(ctx *Context, listen string, tls_cert []byte, tls_key []byte) (*G
}
return &GQLExt{
Listen: listen,
SubscribeListeners: []chan Signal{},
tls_cert: tls_cert,
tls_key: tls_key,
}, nil
}
func StartGQLServer(ctx *Context, node *Node, gql_ext *GQLExt) error {
func (ext *GQLExt) StartGQLServer(ctx *Context, node *Node) error {
if ext.tcp_listener != nil || ext.http_server != nil {
return fmt.Errorf("listener or server is still running, stop them first")
}
mux := http.NewServeMux()
mux.HandleFunc("/gql", GQLHandler(ctx, node, gql_ext))
mux.HandleFunc("/gqlws", GQLWSHandler(ctx, node, gql_ext))
mux.HandleFunc("/gql", GQLHandler(ctx, node, ext))
mux.HandleFunc("/gqlws", GQLWSHandler(ctx, node, ext))
// Server a graphiql interface(TODO make configurable whether to start this)
mux.HandleFunc("/graphiql", GraphiQLHandler())
@ -751,7 +737,7 @@ func StartGQLServer(ctx *Context, node *Node, gql_ext *GQLExt) error {
mux.Handle("/site/", http.StripPrefix("/site", fs))
http_server := &http.Server{
Addr: gql_ext.Listen,
Addr: ext.Listen,
Handler: mux,
}
@ -760,7 +746,7 @@ func StartGQLServer(ctx *Context, node *Node, gql_ext *GQLExt) error {
return fmt.Errorf("Failed to start listener for server on %s", http_server.Addr)
}
cert, err := tls.X509KeyPair(gql_ext.tls_cert, gql_ext.tls_key)
cert, err := tls.X509KeyPair(ext.tls_cert, ext.tls_key)
if err != nil {
return err
}
@ -772,23 +758,29 @@ func StartGQLServer(ctx *Context, node *Node, gql_ext *GQLExt) error {
listener := tls.NewListener(l, &config)
gql_ext.http_done.Add(1)
ext.http_done.Add(1)
go func(qql_ext *GQLExt) {
defer gql_ext.http_done.Done()
defer ext.http_done.Done()
err := http_server.Serve(listener)
if err != http.ErrServerClosed {
panic(fmt.Sprintf("Failed to start gql server: %s", err))
}
}(gql_ext)
}(ext)
gql_ext.tcp_listener = listener
gql_ext.http_server = http_server
ext.tcp_listener = listener
ext.http_server = http_server
return nil
}
func StopGQLServer(gql_ext *GQLExt) {
gql_ext.http_server.Shutdown(context.TODO())
gql_ext.http_done.Wait()
func (ext *GQLExt) StopGQLServer() error {
if ext.tcp_listener == nil || ext.http_server == nil {
return fmt.Errorf("already shutdown, cannot shut down again" )
}
ext.http_server.Shutdown(context.TODO())
ext.http_done.Wait()
ext.tcp_listener = nil
ext.http_server = nil
return nil
}

@ -25,7 +25,7 @@ func NewSingleton[K graphql.Type](init func() K, post_init func(K, *graphql.List
}
}
func AddNodeInterfaceFields(gql *GQLInterface) {
func AddNodeInterfaceFields(gql *Interface) {
gql.Interface.AddFieldConfig("ID", &graphql.Field{
Type: graphql.String,
})
@ -35,11 +35,11 @@ func AddNodeInterfaceFields(gql *GQLInterface) {
})
}
func AddLockableInterfaceFields(gql *GQLInterface) {
addLockableInterfaceFields(gql, GQLInterfaceLockable)
func AddLockableInterfaceFields(gql *Interface) {
addLockableInterfaceFields(gql, InterfaceLockable)
}
func addLockableInterfaceFields(gql *GQLInterface, gql_lockable *GQLInterface) {
func addLockableInterfaceFields(gql *Interface, gql_lockable *Interface) {
AddNodeInterfaceFields(gql)
gql.Interface.AddFieldConfig("Requirements", &graphql.Field{
@ -108,15 +108,15 @@ func NodeResolver(required_extensions []ExtType, default_type **graphql.Object)f
}
}
var GQLInterfaceNode = NewGQLInterface("Node", "DefaultNode", []*graphql.Interface{}, []ExtType{}, func(gql *GQLInterface) {
var InterfaceNode = NewInterface("Node", "DefaultNode", []*graphql.Interface{}, []ExtType{}, func(gql *Interface) {
AddNodeInterfaceFields(gql)
}, func(gql *GQLInterface) {
}, func(gql *Interface) {
AddNodeFields(gql.Default)
})
var GQLInterfaceLockable = NewGQLInterface("Lockable", "DefaultLockable", []*graphql.Interface{GQLInterfaceNode.Interface}, []ExtType{LockableExtType}, func(gql *GQLInterface) {
var InterfaceLockable = NewInterface("Lockable", "DefaultLockable", []*graphql.Interface{InterfaceNode.Interface}, []ExtType{LockableExtType}, func(gql *Interface) {
addLockableInterfaceFields(gql, gql)
}, func(gql *GQLInterface) {
}, func(gql *Interface) {
addLockableFields(gql.Default, gql.Interface, gql.List)
})

@ -3,9 +3,9 @@ import (
"github.com/graphql-go/graphql"
)
var GQLMutationStop = NewField(func()*graphql.Field {
gql_mutation_stop := &graphql.Field{
Type: GQLTypeSignal.Type,
var MutationStop = NewField(func()*graphql.Field {
mutation_stop := &graphql.Field{
Type: TypeSignal.Type,
Args: graphql.FieldConfigArgument{
"id": &graphql.ArgumentConfig{
Type: graphql.String,
@ -16,70 +16,6 @@ var GQLMutationStop = NewField(func()*graphql.Field {
},
}
return gql_mutation_stop
})
var GQLMutationStartChild = NewField(func()*graphql.Field{
gql_mutation_start_child := &graphql.Field{
Type: GQLTypeSignal.Type,
Args: graphql.FieldConfigArgument{
"parent_id": &graphql.ArgumentConfig{
Type: graphql.String,
},
"child_id": &graphql.ArgumentConfig{
Type: graphql.String,
},
"action": &graphql.ArgumentConfig{
Type: graphql.String,
DefaultValue: "start",
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
/*_, ctx, err := PrepResolve(p)
if err != nil {
return nil, err
}
parent_id, err := ExtractID(p, "parent_id")
if err != nil {
return nil, err
}
child_id, err := ExtractID(p, "child_id")
if err != nil {
return nil, err
}
action, err := ExtractParam[string](p, "action")
if err != nil {
return nil, err
}
var signal Signal
context := NewWriteContext(ctx.Context)
err = UseStates(context, ctx.User, NewACLMap(
NewACLInfo(ctx.Server, []string{"children"}),
), func(context *StateContext) error {
parent, err := FindChild(context, ctx.User, ctx.Server, parent_id)
if err != nil {
return err
}
if parent == nil {
return fmt.Errorf("%s is not a child of %s", parent_id, ctx.Server.ID)
}
signal = NewStartChildSignal(child_id, action)
return parent.Process(context, ctx.User.ID, signal)
})
if err != nil {
return nil, err
}*/
// TODO: wait for the result of the signal to send back instead of just the signal
return nil, nil
},
}
return gql_mutation_start_child
return mutation_stop
})

@ -1,16 +1,34 @@
package graphvent
import (
"github.com/graphql-go/graphql"
"github.com/graphql-go/graphql/language/ast"
)
var GQLQueryNode = &graphql.Field{
Type: GQLInterfaceNode.Interface,
func GetFieldNames(p graphql.ResolveParams) []string {
names := []string{}
for _, node := range(p.Info.FieldASTs) {
for _, sel := range(node.SelectionSet.Selections) {
names = append(names, sel.(*ast.Field).Name.Value)
}
}
return names
}
var QueryNode = &graphql.Field{
Type: InterfaceNode.Interface,
Args: graphql.FieldConfigArgument{
"id": &graphql.ArgumentConfig{
Type: graphql.String,
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
ctx, err := PrepResolve(p)
if err != nil {
return nil, err
}
ctx.Context.Log.Logf("gql", "FieldASTs: %+v", p.Info.FieldASTs)
ctx.Context.Log.Logf("gql", "FIELDS: %+v", GetFieldNames(p))
// Get a list of fields that will be written
// Send the read signal
// Wait for the response, returning an error on timeout
@ -19,14 +37,16 @@ var GQLQueryNode = &graphql.Field{
},
}
var GQLQuerySelf = &graphql.Field{
Type: GQLInterfaceNode.Default,
var QuerySelf = &graphql.Field{
Type: InterfaceNode.Default,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
_, err := PrepResolve(p)
ctx, err := PrepResolve(p)
if err != nil {
return nil, err
}
ctx.Context.Log.Logf("gql", "FIELDS: %+v", GetFieldNames(p))
return nil, nil
},
}

@ -3,19 +3,19 @@ import (
"github.com/graphql-go/graphql"
)
func GQLSubscribeSignal(p graphql.ResolveParams) (interface{}, error) {
return GQLSubscribeFn(p, false, func(ctx *Context, server *Node, ext *GQLExt, signal Signal, p graphql.ResolveParams)(interface{}, error) {
return signal, nil
func SubscribeNode(p graphql.ResolveParams) (interface{}, error) {
return SubscribeFn(p, false, func(ctx *Context, server *Node, ext *GQLExt, signal Signal, p graphql.ResolveParams)(interface{}, error) {
return nil, nil
})
}
func GQLSubscribeSelf(p graphql.ResolveParams) (interface{}, error) {
return GQLSubscribeFn(p, true, func(ctx *Context, server *Node, ext *GQLExt, signal Signal, p graphql.ResolveParams)(interface{}, error) {
func SubscribeSelf(p graphql.ResolveParams) (interface{}, error) {
return SubscribeFn(p, true, func(ctx *Context, server *Node, ext *GQLExt, signal Signal, p graphql.ResolveParams)(interface{}, error) {
return server, nil
})
}
func GQLSubscribeFn(p graphql.ResolveParams, send_nil bool, fn func(*Context, *Node, *GQLExt, Signal, graphql.ResolveParams)(interface{}, error))(interface{}, error) {
func SubscribeFn(p graphql.ResolveParams, send_nil bool, fn func(*Context, *Node, *GQLExt, Signal, graphql.ResolveParams)(interface{}, error))(interface{}, error) {
ctx, err := PrepResolve(p)
if err != nil {
return nil, err
@ -24,7 +24,7 @@ func GQLSubscribeFn(p graphql.ResolveParams, send_nil bool, fn func(*Context, *N
c := make(chan interface{})
go func(c chan interface{}, ext *GQLExt, server *Node) {
ctx.Context.Log.Logf("gqlws", "GQL_SUBSCRIBE_THREAD_START")
sig_c := ext.NewSubscriptionChannel(1)
sig_c := make(chan Signal, 1)
if send_nil == true {
sig_c <- nil
}
@ -44,26 +44,32 @@ func GQLSubscribeFn(p graphql.ResolveParams, send_nil bool, fn func(*Context, *N
return c, nil
}
var GQLSubscriptionSelf = NewField(func()*graphql.Field{
gql_subscription_self := &graphql.Field{
Type: GQLInterfaceNode.Default,
var SubscriptionSelf = NewField(func()*graphql.Field{
subscription_self := &graphql.Field{
Type: InterfaceNode.Default,
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return p.Source, nil
},
Subscribe: GQLSubscribeSelf,
Subscribe: SubscribeSelf,
}
return gql_subscription_self
return subscription_self
})
var GQLSubscriptionUpdate = NewField(func()*graphql.Field{
gql_subscription_update := &graphql.Field{
Type: GQLTypeSignal.Type,
var SubscriptionNode = NewField(func()*graphql.Field{
subscription_node := &graphql.Field{
Type: InterfaceNode.Default,
Args: graphql.FieldConfigArgument{
"id": &graphql.ArgumentConfig{
Type: graphql.String,
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return p.Source, nil
},
Subscribe: GQLSubscribeSignal,
Subscribe: SubscribeNode,
}
return gql_subscription_update
return subscription_node
})

@ -3,10 +3,17 @@ package graphvent
import (
"testing"
"time"
"fmt"
"encoding/json"
"io"
"net/http"
"net"
"crypto/tls"
"bytes"
)
func TestGQL(t *testing.T) {
ctx := logTestContext(t, []string{})
ctx := logTestContext(t, []string{"test", "gql", "policy"})
TestNodeType := NodeType("TEST")
err := ctx.RegisterNodeType(TestNodeType, []ExtType{LockableExtType, ACLExtType})
@ -16,14 +23,47 @@ func TestGQL(t *testing.T) {
fatalErr(t, err)
listener_ext := NewListenerExt(10)
policy := NewAllNodesPolicy(Actions{MakeAction("+")})
gql := NewNode(ctx, nil, TestNodeType, 10, nil, NewLockableExt(), NewACLExt(policy), gql_ext, listener_ext)
n1 := NewNode(ctx, nil, TestNodeType, 10, nil, NewLockableExt(), NewACLExt(policy))
gql := NewNode(ctx, nil, TestNodeType, 10, nil, NewLockableExt(), NewACLExt(policy), gql_ext)
n1 := NewNode(ctx, nil, TestNodeType, 10, nil, NewLockableExt(), NewACLExt(policy), listener_ext)
LinkRequirement(ctx, gql.ID, n1.ID)
_, err = WaitForSignal(ctx, listener_ext, time.Millisecond*10, LinkSignalType, func(sig StateSignal) bool {
return sig.State == "linked_as_req"
ctx.Send(n1.ID, gql.ID, StateSignal{NewDirectSignal(GQLStateSignalType), "start_server"})
_, err = WaitForSignal(ctx, listener_ext, 100*time.Millisecond, GQLStateSignalType, func(sig StateSignal) bool {
return sig.State == "server_started"
})
fatalErr(t, err)
skipVerifyTransport := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: skipVerifyTransport}
port := gql_ext.tcp_listener.Addr().(*net.TCPAddr).Port
url := fmt.Sprintf("https://localhost:%d/gql", port)
ser, err := json.MarshalIndent(&GQLPayload{
Query: "query { Self { ID } }",
}, "", " ")
fatalErr(t, err)
req_data := bytes.NewBuffer(ser)
req, err := http.NewRequest("GET", url, req_data)
req.SetBasicAuth(n1.ID.String(), "BAD_PASSWORD")
fatalErr(t, err)
resp, err := client.Do(req)
fatalErr(t, err)
body, err := io.ReadAll(resp.Body)
fatalErr(t, err)
resp.Body.Close()
ctx.Log.Logf("test", "TEST_RESP: %s", body)
ctx.Send(n1.ID, gql.ID, StateSignal{NewDirectSignal(GQLStateSignalType), "stop_server"})
_, err = WaitForSignal(ctx, listener_ext, 100*time.Millisecond, GQLStateSignalType, func(sig StateSignal) bool {
return sig.State == "server_stopped"
})
}
func TestGQLDB(t *testing.T) {

@ -17,7 +17,7 @@ func AddNodeFields(object *graphql.Object) {
}
func AddLockableFields(object *graphql.Object) {
addLockableFields(object, GQLInterfaceLockable.Interface, GQLInterfaceLockable.List)
addLockableFields(object, InterfaceLockable.Interface, InterfaceLockable.List)
}
func addLockableFields(object *graphql.Object, lockable_interface *graphql.Interface, lockable_list *graphql.List) {
@ -38,10 +38,10 @@ func addLockableFields(object *graphql.Object, lockable_interface *graphql.Inter
})
}
var GQLNodeInterfaces = []*graphql.Interface{GQLInterfaceNode.Interface}
var GQLLockableInterfaces = append(GQLNodeInterfaces, GQLInterfaceLockable.Interface)
var GQLNodeInterfaces = []*graphql.Interface{InterfaceNode.Interface}
var GQLLockableInterfaces = append(GQLNodeInterfaces, InterfaceLockable.Interface)
var GQLTypeGQLNode = NewGQLNodeType(GQLNodeType, GQLNodeInterfaces, func(gql *GQLType) {
var TypeGQLNode = NewGQLNodeType(GQLNodeType, GQLNodeInterfaces, func(gql *Type) {
AddNodeFields(gql.Type)
gql.Type.AddFieldConfig("Listen", &graphql.Field{
@ -50,7 +50,7 @@ var GQLTypeGQLNode = NewGQLNodeType(GQLNodeType, GQLNodeInterfaces, func(gql *GQ
})
})
var GQLTypeSignal = NewSingleton(func() *graphql.Object {
var TypeSignal = NewSingleton(func() *graphql.Object {
gql_type_signal := graphql.NewObject(graphql.ObjectConfig{
Name: "Signal",
IsTypeOf: func(p graphql.IsTypeOfParams) bool {

@ -25,6 +25,7 @@ const (
ECDHSignalType = "ECDH"
ECDHStateSignalType = "ECDH_STATE"
ECDHProxySignalType = "ECDH_PROXY"
GQLStateSignalType = "GQL_STATE"
Up SignalDirection = iota
Down