diff --git a/resource.go b/resource.go index 0e3e4ad..1bd6703 100644 --- a/resource.go +++ b/resource.go @@ -2,14 +2,14 @@ package main import ( "fmt" + "io" "reflect" "errors" "sync" "net/http" - "io" "github.com/graphql-go/graphql" - "github.com/graphql-go/handler" "context" + "encoding/json" ) // Resources propagate update up to multiple parents, and not downwards @@ -260,76 +260,6 @@ func NewResource(name string, description string, children []Resource) * BaseRes return &resource } -const graphiql_string string = ` - - - - - GraphiQL - - - - - - - - - - - -
Loading...
- - - - -` - type GQLServer struct { BaseResource abort chan error @@ -339,7 +269,7 @@ type GQLServer struct { func NewGQLServer(listen string) * GQLServer { server := &GQLServer{ - BaseResource: NewBaseResource("GQL Connection", "Connection to a GQL server", []Resource{}), + BaseResource: NewBaseResource("GQL Server", "graphql server for event signals", []Resource{}), listen: listen, abort: make(chan error, 1), gql_channel: make(chan error, 1), @@ -367,32 +297,57 @@ func GQLEventChildren(p graphql.ResolveParams) (interface{}, error) { return nil, errors.New("Failed to cast source to event") } -func (server * GQLServer) Schema() * graphql.Schema { - valid_events := map[reflect.Type]*graphql.Object{} - gql_interface_event := graphql.NewInterface(graphql.InterfaceConfig{ - Name: "Event", - Fields: graphql.Fields{}, - ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { - for key, value := range(valid_events) { - if reflect.TypeOf(p.Value) == key { - return value +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 } - } - return nil - }, - }) - gql_type_event_list := graphql.NewList(gql_interface_event) - gql_interface_event.AddFieldConfig("ID", &graphql.Field{ - Type: graphql.String, - }) - gql_interface_event.AddFieldConfig("Children", &graphql.Field{ - Type: gql_type_event_list, - }) + 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(GQLInterfaceEvent()) + } + + gql_interface_event.AddFieldConfig("ID", &graphql.Field{ + Type: graphql.String, + }) + + gql_interface_event.AddFieldConfig("Children", &graphql.Field{ + Type: gql_list_event, + }) + } + + return gql_interface_event +} + +func (server * GQLServer) Handler() func(http.ResponseWriter, *http.Request) { + valid_events := map[reflect.Type]*graphql.Object{} gql_type_base_event := graphql.NewObject(graphql.ObjectConfig{ Name: "BaseEvent", Interfaces: []*graphql.Interface{ - gql_interface_event, + GQLInterfaceEvent(), }, IsTypeOf: func(p graphql.IsTypeOfParams) bool { _, ok := p.Value.(*BaseEvent) @@ -403,27 +358,17 @@ func (server * GQLServer) Schema() * graphql.Schema { valid_events[reflect.TypeOf((*BaseEvent)(nil))] = gql_type_base_event gql_type_base_event.AddFieldConfig("ID", &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) (interface{}, error) { - if event, ok := p.Source.(Event); ok { - return event.ID(), nil - } - return nil, errors.New("Failed to cast source to event") - }, + Resolve: GQLEventID, }) gql_type_base_event.AddFieldConfig("Children", &graphql.Field{ - Type: gql_type_event_list, - Resolve: func(p graphql.ResolveParams) (interface{}, error) { - if event, ok := p.Source.(Event); ok { - return event.Children(), nil - } - return nil, errors.New("Failed to cast source to event") - }, + Type: GQLListEvent(), + Resolve: GQLEventChildren, }) gql_type_event_queue := graphql.NewObject(graphql.ObjectConfig{ Name: "EventQueue", Interfaces: []*graphql.Interface{ - gql_interface_event, + GQLInterfaceEvent(), }, IsTypeOf: func(p graphql.IsTypeOfParams) bool { _, ok := p.Value.(*EventQueue) @@ -437,7 +382,7 @@ func (server * GQLServer) Schema() * graphql.Schema { Resolve: GQLEventID, }) gql_type_event_queue.AddFieldConfig("Children", &graphql.Field{ - Type: gql_type_event_list, + Type: GQLListEvent(), Resolve: GQLEventChildren, }) @@ -447,7 +392,7 @@ func (server * GQLServer) Schema() * graphql.Schema { Name: "Query", Fields: graphql.Fields{ "Event": &graphql.Field{ - Type: gql_interface_event, + Type: GQLInterfaceEvent(), Resolve: func(p graphql.ResolveParams) (interface{}, error) { server.lock_holder_lock.Lock() defer server.lock_holder_lock.Unlock() @@ -466,21 +411,122 @@ func (server * GQLServer) Schema() * graphql.Schema { panic(err) } - return &schema + 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{} + log.Logf("gql", "GQL_REQ: %s", str) + json.Unmarshal(str, &res) + log.Logf("gql", "GQL_QUERY: %s", res.Query) + 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()) - h := handler.New(&handler.Config{Schema: server.Schema(), Pretty: true}) mux := http.NewServeMux() - mux.Handle("/gql", h) - mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { - w.Header().Set("Content-Type", "text/html; charset=utf-8") - w.WriteHeader(http.StatusOK) - io.WriteString(w, graphiql_string) - }) + mux.HandleFunc("/gql", server.Handler()) + mux.HandleFunc("/", GraphiQLHandler()) srv := &http.Server{ Addr: server.listen,