diff --git a/gql.go b/gql.go
new file mode 100644
index 0000000..4051dd9
--- /dev/null
+++ b/gql.go
@@ -0,0 +1,375 @@
+package main
+
+import (
+ "net/http"
+ "github.com/graphql-go/graphql"
+ "context"
+ "encoding/json"
+ "io"
+ "reflect"
+ "errors"
+ "fmt"
+ "sync"
+)
+
+func GraphiQLHandler() func(http.ResponseWriter, *http.Request) {
+ graphiql_string := `
+
+
+
+
+ GraphiQL
+
+
+
+
+
+
+
+
+
+
+
+ Loading...
+
+
+
+
+`
+
+ return func(w http.ResponseWriter, r * http.Request) {
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ w.WriteHeader(http.StatusOK)
+ io.WriteString(w, graphiql_string)
+ }
+
+}
+
+type GQLQuery struct {
+ Query string `json:"query"`
+}
+
+func GQLHandler(schema graphql.Schema, ctx context.Context) func(http.ResponseWriter, *http.Request) {
+ return func(w http.ResponseWriter, r * http.Request) {
+ str, err := io.ReadAll(r.Body)
+ if err != nil {
+ log.Logf("gql", "failed to read request body: %s", err)
+ return
+ }
+ res := GQLQuery{}
+ json.Unmarshal(str, &res)
+ result := graphql.Do(graphql.Params{
+ Schema: schema,
+ Context: ctx,
+ RequestString: res.Query,
+ })
+ if len(result.Errors) > 0 {
+ log.Logf("gql", "wrong result, unexpected errors: %v", result.Errors)
+ }
+ json.NewEncoder(w).Encode(result)
+ }
+}
+
+func GQLEventFn(p graphql.ResolveParams, fn func(Event, graphql.ResolveParams)(interface{}, error))(interface{}, error) {
+ if event, ok := p.Source.(Event); ok {
+ return fn(event, p)
+ }
+ return nil, errors.New("Failed to cast source to event")
+}
+
+func GQLEventID(p graphql.ResolveParams) (interface{}, error) {
+ return GQLEventFn(p, func(event Event, p graphql.ResolveParams)(interface{}, error) {
+ return event.ID(), nil
+ })
+}
+
+func GQLEventName(p graphql.ResolveParams) (interface{}, error) {
+ return GQLEventFn(p, func(event Event, p graphql.ResolveParams)(interface{}, error) {
+ return event.Name(), nil
+ })
+}
+
+func GQLEventDescription(p graphql.ResolveParams) (interface{}, error) {
+ return GQLEventFn(p, func(event Event, p graphql.ResolveParams)(interface{}, error) {
+ return event.Description(), nil
+ })
+}
+
+func GQLEventChildren(p graphql.ResolveParams) (interface{}, error) {
+ return GQLEventFn(p, func(event Event, p graphql.ResolveParams)(interface{}, error) {
+ return event.Children(), nil
+ })
+}
+
+
+var gql_list_event * graphql.List = nil
+func GQLListEvent() * graphql.List {
+ if gql_list_event == nil {
+ gql_list_event = graphql.NewList(GQLInterfaceEvent())
+ }
+ return gql_list_event
+}
+
+var gql_interface_event * graphql.Interface = nil
+func GQLInterfaceEvent() * graphql.Interface {
+ if gql_interface_event == nil {
+ gql_interface_event = graphql.NewInterface(graphql.InterfaceConfig{
+ Name: "Event",
+ ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object {
+ valid_events, ok := p.Context.Value("valid_events").(map[reflect.Type]*graphql.Object)
+ if ok == false {
+ return nil
+ }
+ for key, value := range(valid_events) {
+ if reflect.TypeOf(p.Value) == key {
+ return value
+ }
+ }
+ return nil
+ },
+ Fields: graphql.Fields{},
+ })
+
+ if gql_list_event == nil {
+ gql_list_event = graphql.NewList(gql_interface_event)
+ }
+
+ gql_interface_event.AddFieldConfig("ID", &graphql.Field{
+ Type: graphql.String,
+ })
+
+ gql_interface_event.AddFieldConfig("Name", &graphql.Field{
+ Type: graphql.String,
+ })
+
+ gql_interface_event.AddFieldConfig("Description", &graphql.Field{
+ Type: graphql.String,
+ })
+
+ gql_interface_event.AddFieldConfig("Children", &graphql.Field{
+ Type: gql_list_event,
+ })
+ }
+
+ return gql_interface_event
+}
+
+var gql_type_base_event * graphql.Object = nil
+func GQLTypeBaseEvent() * graphql.Object {
+ if gql_type_base_event == nil {
+ gql_type_base_event = graphql.NewObject(graphql.ObjectConfig{
+ Name: "BaseEvent",
+ Interfaces: []*graphql.Interface{
+ GQLInterfaceEvent(),
+ },
+ IsTypeOf: func(p graphql.IsTypeOfParams) bool {
+ _, ok := p.Value.(*BaseEvent)
+ return ok
+ },
+ Fields: graphql.Fields{},
+ })
+ gql_type_base_event.AddFieldConfig("ID", &graphql.Field{
+ Type: graphql.String,
+ Resolve: GQLEventID,
+ })
+
+ gql_type_base_event.AddFieldConfig("Name", &graphql.Field{
+ Type: graphql.String,
+ Resolve: GQLEventName,
+ })
+
+ gql_type_base_event.AddFieldConfig("Description", &graphql.Field{
+ Type: graphql.String,
+ Resolve: GQLEventDescription,
+ })
+
+ gql_type_base_event.AddFieldConfig("Children", &graphql.Field{
+ Type: GQLListEvent(),
+ Resolve: GQLEventChildren,
+ })
+ }
+
+ return gql_type_base_event
+}
+
+var gql_type_event_queue * graphql.Object = nil
+func GQLTypeEventQueue() * graphql.Object {
+ if gql_type_event_queue == nil {
+ gql_type_event_queue = graphql.NewObject(graphql.ObjectConfig{
+ Name: "EventQueue",
+ Interfaces: []*graphql.Interface{
+ GQLInterfaceEvent(),
+ },
+ IsTypeOf: func(p graphql.IsTypeOfParams) bool {
+ _, ok := p.Value.(*EventQueue)
+ return ok
+ },
+ Fields: graphql.Fields{},
+ })
+ gql_type_event_queue.AddFieldConfig("ID", &graphql.Field{
+ Type: graphql.String,
+ Resolve: GQLEventID,
+ })
+ gql_type_event_queue.AddFieldConfig("Name", &graphql.Field{
+ Type: graphql.String,
+ Resolve: GQLEventName,
+ })
+ gql_type_event_queue.AddFieldConfig("Description", &graphql.Field{
+ Type: graphql.String,
+ Resolve: GQLEventDescription,
+ })
+ gql_type_event_queue.AddFieldConfig("Children", &graphql.Field{
+ Type: GQLListEvent(),
+ Resolve: GQLEventChildren,
+ })
+ }
+ return gql_type_event_queue
+}
+
+type GQLServer struct {
+ BaseResource
+ abort chan error
+ listen string
+ gql_channel chan error
+}
+
+func NewGQLServer(listen string) * GQLServer {
+ server := &GQLServer{
+ BaseResource: NewBaseResource("GQL Server", "graphql server for event signals", []Resource{}),
+ listen: listen,
+ abort: make(chan error, 1),
+ gql_channel: make(chan error, 1),
+ }
+
+ return server
+}
+
+func (server * GQLServer) update(signal GraphSignal) {
+ server.signal <- signal
+ server.BaseResource.update(signal)
+}
+
+func (server * GQLServer) Handler(extended_types map[reflect.Type]*graphql.Object) func(http.ResponseWriter, *http.Request) {
+ valid_events := map[reflect.Type]*graphql.Object{}
+ valid_events[reflect.TypeOf((*BaseEvent)(nil))] = GQLTypeBaseEvent()
+ valid_events[reflect.TypeOf((*EventQueue)(nil))] = GQLTypeEventQueue()
+
+ for go_t, gql_t := range(extended_types) {
+ valid_events[go_t] = gql_t
+ }
+
+ schemaConfig := graphql.SchemaConfig{
+ Types: []graphql.Type{GQLTypeBaseEvent(), GQLTypeEventQueue()},
+ Query: graphql.NewObject(graphql.ObjectConfig{
+ Name: "Query",
+ Fields: graphql.Fields{
+ "Owner": &graphql.Field{
+ Type: GQLInterfaceEvent(),
+ Resolve: func(p graphql.ResolveParams) (interface{}, error) {
+ server.lock_holder_lock.Lock()
+ defer server.lock_holder_lock.Unlock()
+
+ owner := server.Owner()
+
+ return owner, nil
+ },
+ },
+ },
+ }),
+ }
+
+ schema, err := graphql.NewSchema(schemaConfig)
+ if err != nil{
+ panic(err)
+ }
+
+ return GQLHandler(schema, context.WithValue(context.Background(), "valid_events", valid_events))
+}
+
+func (server * GQLServer) Init(abort chan error) bool {
+ go func(abort chan error) {
+ log.Logf("gql", "GOROUTINE_START for %s", server.ID())
+
+ mux := http.NewServeMux()
+ mux.HandleFunc("/gql", server.Handler(map[reflect.Type]*graphql.Object{}))
+ mux.HandleFunc("/", GraphiQLHandler())
+
+ srv := &http.Server{
+ Addr: server.listen,
+ Handler: mux,
+ }
+
+ http_done := &sync.WaitGroup{}
+ http_done.Add(1)
+ go func(srv *http.Server, http_done *sync.WaitGroup) {
+ defer http_done.Done()
+ err := srv.ListenAndServe()
+ if err != http.ErrServerClosed {
+ panic(fmt.Sprintf("Failed to start gql server: %s", err))
+ }
+ }(srv, http_done)
+
+ for true {
+ select {
+ case <-abort:
+ log.Logf("gql", "GOROUTINE_ABORT for %s", server.ID())
+ err := srv.Shutdown(context.Background())
+ if err != nil{
+ panic(fmt.Sprintf("Failed to shutdown gql server: %s", err))
+ }
+ http_done.Wait()
+ break
+ case signal:=<-server.signal:
+ log.Logf("gql", "GOROUTINE_SIGNAL for %s: %+v", server.ID(), signal)
+ // Take signals to resource and send to GQL subscriptions
+ }
+ }
+ }(abort)
+ return true
+}
diff --git a/resource.go b/resource.go
index b163400..cffc3b4 100644
--- a/resource.go
+++ b/resource.go
@@ -2,14 +2,8 @@ package main
import (
"fmt"
- "io"
- "reflect"
- "errors"
"sync"
- "net/http"
- "github.com/graphql-go/graphql"
- "context"
- "encoding/json"
+ "errors"
)
// Resources propagate update up to multiple parents, and not downwards
@@ -259,361 +253,3 @@ func NewResource(name string, description string, children []Resource) * BaseRes
resource := NewBaseResource(name, description, children)
return &resource
}
-
-type GQLServer struct {
- BaseResource
- abort chan error
- listen string
- gql_channel chan error
-}
-
-func NewGQLServer(listen string) * GQLServer {
- server := &GQLServer{
- BaseResource: NewBaseResource("GQL Server", "graphql server for event signals", []Resource{}),
- listen: listen,
- abort: make(chan error, 1),
- gql_channel: make(chan error, 1),
- }
-
- return server
-}
-
-func (server * GQLServer) update(signal GraphSignal) {
- server.signal <- signal
- server.BaseResource.update(signal)
-}
-
-func GQLEventFn(p graphql.ResolveParams, fn func(Event, graphql.ResolveParams)(interface{}, error))(interface{}, error) {
- if event, ok := p.Source.(Event); ok {
- return fn(event, p)
- }
- return nil, errors.New("Failed to cast source to event")
-}
-
-func GQLEventID(p graphql.ResolveParams) (interface{}, error) {
- return GQLEventFn(p, func(event Event, p graphql.ResolveParams)(interface{}, error) {
- return event.ID(), nil
- })
-}
-
-func GQLEventName(p graphql.ResolveParams) (interface{}, error) {
- return GQLEventFn(p, func(event Event, p graphql.ResolveParams)(interface{}, error) {
- return event.Name(), nil
- })
-}
-
-func GQLEventDescription(p graphql.ResolveParams) (interface{}, error) {
- return GQLEventFn(p, func(event Event, p graphql.ResolveParams)(interface{}, error) {
- return event.Description(), nil
- })
-}
-
-func GQLEventChildren(p graphql.ResolveParams) (interface{}, error) {
- return GQLEventFn(p, func(event Event, p graphql.ResolveParams)(interface{}, error) {
- return event.Children(), nil
- })
-}
-
-
-var gql_list_event * graphql.List = nil
-func GQLListEvent() * graphql.List {
- if gql_list_event == nil {
- gql_list_event = graphql.NewList(GQLInterfaceEvent())
- }
- return gql_list_event
-}
-
-var gql_interface_event * graphql.Interface = nil
-func GQLInterfaceEvent() * graphql.Interface {
- if gql_interface_event == nil {
- gql_interface_event = graphql.NewInterface(graphql.InterfaceConfig{
- Name: "Event",
- ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object {
- valid_events, ok := p.Context.Value("valid_events").(map[reflect.Type]*graphql.Object)
- if ok == false {
- return nil
- }
- for key, value := range(valid_events) {
- if reflect.TypeOf(p.Value) == key {
- return value
- }
- }
- return nil
- },
- Fields: graphql.Fields{},
- })
-
- if gql_list_event == nil {
- gql_list_event = graphql.NewList(gql_interface_event)
- }
-
- gql_interface_event.AddFieldConfig("ID", &graphql.Field{
- Type: graphql.String,
- })
-
- gql_interface_event.AddFieldConfig("Name", &graphql.Field{
- Type: graphql.String,
- })
-
- gql_interface_event.AddFieldConfig("Description", &graphql.Field{
- Type: graphql.String,
- })
-
- gql_interface_event.AddFieldConfig("Children", &graphql.Field{
- Type: gql_list_event,
- })
- }
-
- return gql_interface_event
-}
-
-var gql_type_base_event * graphql.Object = nil
-func GQLTypeBaseEvent() * graphql.Object {
- if gql_type_base_event == nil {
- gql_type_base_event = graphql.NewObject(graphql.ObjectConfig{
- Name: "BaseEvent",
- Interfaces: []*graphql.Interface{
- GQLInterfaceEvent(),
- },
- IsTypeOf: func(p graphql.IsTypeOfParams) bool {
- _, ok := p.Value.(*BaseEvent)
- return ok
- },
- Fields: graphql.Fields{},
- })
- gql_type_base_event.AddFieldConfig("ID", &graphql.Field{
- Type: graphql.String,
- Resolve: GQLEventID,
- })
-
- gql_type_base_event.AddFieldConfig("Name", &graphql.Field{
- Type: graphql.String,
- Resolve: GQLEventName,
- })
-
- gql_type_base_event.AddFieldConfig("Description", &graphql.Field{
- Type: graphql.String,
- Resolve: GQLEventDescription,
- })
-
- gql_type_base_event.AddFieldConfig("Children", &graphql.Field{
- Type: GQLListEvent(),
- Resolve: GQLEventChildren,
- })
- }
-
- return gql_type_base_event
-}
-
-var gql_type_event_queue * graphql.Object = nil
-func GQLTypeEventQueue() * graphql.Object {
- if gql_type_event_queue == nil {
- gql_type_event_queue = graphql.NewObject(graphql.ObjectConfig{
- Name: "EventQueue",
- Interfaces: []*graphql.Interface{
- GQLInterfaceEvent(),
- },
- IsTypeOf: func(p graphql.IsTypeOfParams) bool {
- _, ok := p.Value.(*EventQueue)
- return ok
- },
- Fields: graphql.Fields{},
- })
- gql_type_event_queue.AddFieldConfig("ID", &graphql.Field{
- Type: graphql.String,
- Resolve: GQLEventID,
- })
- gql_type_event_queue.AddFieldConfig("Name", &graphql.Field{
- Type: graphql.String,
- Resolve: GQLEventName,
- })
- gql_type_event_queue.AddFieldConfig("Description", &graphql.Field{
- Type: graphql.String,
- Resolve: GQLEventDescription,
- })
- gql_type_event_queue.AddFieldConfig("Children", &graphql.Field{
- Type: GQLListEvent(),
- Resolve: GQLEventChildren,
- })
- }
- return gql_type_event_queue
-}
-
-func (server * GQLServer) Handler() func(http.ResponseWriter, *http.Request) {
- valid_events := map[reflect.Type]*graphql.Object{}
- valid_events[reflect.TypeOf((*BaseEvent)(nil))] = GQLTypeBaseEvent()
- valid_events[reflect.TypeOf((*EventQueue)(nil))] = GQLTypeEventQueue()
-
- schemaConfig := graphql.SchemaConfig{
- Types: []graphql.Type{GQLTypeBaseEvent(), GQLTypeEventQueue()},
- Query: graphql.NewObject(graphql.ObjectConfig{
- Name: "Query",
- Fields: graphql.Fields{
- "Owner": &graphql.Field{
- Type: GQLInterfaceEvent(),
- Resolve: func(p graphql.ResolveParams) (interface{}, error) {
- server.lock_holder_lock.Lock()
- defer server.lock_holder_lock.Unlock()
-
- owner := server.Owner()
-
- return owner, nil
- },
- },
- },
- }),
- }
-
- schema, err := graphql.NewSchema(schemaConfig)
- if err != nil{
- panic(err)
- }
-
- return GQLHandler(schema, context.WithValue(context.Background(), "valid_events", valid_events))
-}
-
-func GraphiQLHandler() func(http.ResponseWriter, *http.Request) {
- graphiql_string := `
-
-
-
-
- GraphiQL
-
-
-
-
-
-
-
-
-
-
-
- Loading...
-
-
-
-
-`
-
- return func(w http.ResponseWriter, r * http.Request) {
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
- w.WriteHeader(http.StatusOK)
- io.WriteString(w, graphiql_string)
- }
-
-}
-
-type GQLQuery struct {
- Query string `json:"query"`
-}
-
-func GQLHandler(schema graphql.Schema, ctx context.Context) func(http.ResponseWriter, *http.Request) {
- return func(w http.ResponseWriter, r * http.Request) {
- str, err := io.ReadAll(r.Body)
- if err != nil {
- log.Logf("gql", "failed to read request body: %s", err)
- return
- }
- res := GQLQuery{}
- json.Unmarshal(str, &res)
- result := graphql.Do(graphql.Params{
- Schema: schema,
- Context: ctx,
- RequestString: res.Query,
- })
- if len(result.Errors) > 0 {
- log.Logf("gql", "wrong result, unexpected errors: %v", result.Errors)
- }
- json.NewEncoder(w).Encode(result)
- }
-}
-
-func (server * GQLServer) Init(abort chan error) bool {
- go func(abort chan error) {
- log.Logf("gql", "GOROUTINE_START for %s", server.ID())
-
- mux := http.NewServeMux()
- mux.HandleFunc("/gql", server.Handler())
- mux.HandleFunc("/", GraphiQLHandler())
-
- srv := &http.Server{
- Addr: server.listen,
- Handler: mux,
- }
-
- http_done := &sync.WaitGroup{}
- http_done.Add(1)
- go func(srv *http.Server, http_done *sync.WaitGroup) {
- defer http_done.Done()
- err := srv.ListenAndServe()
- if err != http.ErrServerClosed {
- panic(fmt.Sprintf("Failed to start gql server: %s", err))
- }
- }(srv, http_done)
-
- for true {
- select {
- case <-abort:
- log.Logf("gql", "GOROUTINE_ABORT for %s", server.ID())
- err := srv.Shutdown(context.Background())
- if err != nil{
- panic(fmt.Sprintf("Failed to shutdown gql server: %s", err))
- }
- http_done.Wait()
- break
- case signal:=<-server.signal:
- log.Logf("gql", "GOROUTINE_SIGNAL for %s: %+v", server.ID(), signal)
- // Take signals to resource and send to GQL subscriptions
- }
- }
- }(abort)
- return true
-}