diff --git a/context.go b/context.go index ee61247..0519a77 100644 --- a/context.go +++ b/context.go @@ -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 } diff --git a/gql.go b/gql.go index 9d55df0..4dda9d4 100644 --- a/gql.go +++ b/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 { - } - - 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) +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"}) + } + default: + 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 } diff --git a/gql_interfaces.go b/gql_interfaces.go index 38dffdf..1083e76 100644 --- a/gql_interfaces.go +++ b/gql_interfaces.go @@ -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) }) diff --git a/gql_mutation.go b/gql_mutation.go index f30b010..8d24754 100644 --- a/gql_mutation.go +++ b/gql_mutation.go @@ -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 }) diff --git a/gql_query.go b/gql_query.go index 679c43d..e3b8502 100644 --- a/gql_query.go +++ b/gql_query.go @@ -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 }, } diff --git a/gql_subscribe.go b/gql_subscribe.go index a83c0a3..da09b8a 100644 --- a/gql_subscribe.go +++ b/gql_subscribe.go @@ -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 }) diff --git a/gql_test.go b/gql_test.go index 65256a7..f407fef 100644 --- a/gql_test.go +++ b/gql_test.go @@ -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) { diff --git a/gql_types.go b/gql_types.go index 3b4fc96..5d81d61 100644 --- a/gql_types.go +++ b/gql_types.go @@ -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 { diff --git a/signal.go b/signal.go index f0a5fd1..cbac046 100644 --- a/signal.go +++ b/signal.go @@ -23,8 +23,9 @@ const ( ReadResultSignalType = "READ_RESULT" LinkStartSignalType = "LINK_START" ECDHSignalType = "ECDH" - ECDHStateSignalType = "ECDH_STATE" + ECDHStateSignalType = "ECDH_STATE" ECDHProxySignalType = "ECDH_PROXY" + GQLStateSignalType = "GQL_STATE" Up SignalDirection = iota Down