diff --git a/main.go b/main.go index ae30620..0a97761 100644 --- a/main.go +++ b/main.go @@ -273,6 +273,8 @@ func main() { signal := NewSignal(nil, "abort") signal.description = event_manager.root_event.ID() SendUpdate(event_manager.root_event, signal) + time.Sleep(time.Second * 5) + pprof.Lookup("goroutine").WriteTo(os.Stdout, 1) break case update := <- arena_1_client.update: arena_1_client.process_update(update) @@ -287,10 +289,9 @@ func main() { arena_2_client.games_done == 12 && arena_3_client.games_done == 12 && arena_4_client.games_done == 12 { - signal := NewSignal(nil, "cancel") - signal.description = event_manager.root_event.ID() - SendUpdate(event_manager.root_event, signal) - break + //signal := NewSignal(nil, "cancel") + //signal.description = event_manager.root_event.ID() + //SendUpdate(event_manager.root_event, signal) } } }() diff --git a/manager.go b/manager.go index 4c7c82c..43c9225 100644 --- a/manager.go +++ b/manager.go @@ -3,11 +3,6 @@ package main import ( "fmt" "errors" - - "io" - "net/http" - "github.com/graphql-go/graphql" - "github.com/graphql-go/handler" ) type EventManager struct { @@ -16,106 +11,6 @@ type EventManager struct { aborts []chan error } -const graphiql_string string = ` - - - - - GraphiQL - - - - - - - - - - - -
Loading...
- - - - -` - -func (manager * EventManager) GQL() error { - fields := graphql.Fields{ - "hello": &graphql.Field{ - Type: graphql.String, - Resolve: func(p graphql.ResolveParams)(interface{}, error) { - return "world", nil - }, - }, - } - rootQuery := graphql.ObjectConfig{Name: "RootQuery", Fields: fields} - schemaConfig := graphql.SchemaConfig{Query: graphql.NewObject(rootQuery)} - schema, err := graphql.NewSchema(schemaConfig) - if err != nil { - return err - } - - h := handler.New(&handler.Config{Schema: &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) - }) - - http.ListenAndServe(":8080", mux) - - return nil -} - // root_event's requirements must be in dag_nodes, and dag_nodes must be ordered by dependency(children first) func NewEventManager(root_event Event, dag_nodes []Resource) * EventManager { diff --git a/resource.go b/resource.go index 27b501c..0e3e4ad 100644 --- a/resource.go +++ b/resource.go @@ -2,8 +2,14 @@ package main import ( "fmt" + "reflect" "errors" "sync" + "net/http" + "io" + "github.com/graphql-go/graphql" + "github.com/graphql-go/handler" + "context" ) // Resources propagate update up to multiple parents, and not downwards @@ -254,6 +260,76 @@ func NewResource(name string, description string, children []Resource) * BaseRes return &resource } +const graphiql_string string = ` + + + + + GraphiQL + + + + + + + + + + + +
Loading...
+ + + + +` + type GQLServer struct { BaseResource abort chan error @@ -277,18 +353,163 @@ func (server * GQLServer) update(signal GraphSignal) { server.BaseResource.update(signal) } +func GQLEventID(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") +} + +func GQLEventChildren(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") +} + +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 + } + } + 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, + }) + + gql_type_base_event := graphql.NewObject(graphql.ObjectConfig{ + Name: "BaseEvent", + Interfaces: []*graphql.Interface{ + gql_interface_event, + }, + IsTypeOf: func(p graphql.IsTypeOfParams) bool { + _, ok := p.Value.(*BaseEvent) + return ok + }, + Fields: graphql.Fields{}, + }) + 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") + }, + }) + 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") + }, + }) + + gql_type_event_queue := graphql.NewObject(graphql.ObjectConfig{ + Name: "EventQueue", + Interfaces: []*graphql.Interface{ + gql_interface_event, + }, + IsTypeOf: func(p graphql.IsTypeOfParams) bool { + _, ok := p.Value.(*EventQueue) + return ok + }, + Fields: graphql.Fields{}, + }) + valid_events[reflect.TypeOf((*EventQueue)(nil))] = gql_type_event_queue + gql_type_event_queue.AddFieldConfig("ID", &graphql.Field{ + Type: graphql.String, + Resolve: GQLEventID, + }) + gql_type_event_queue.AddFieldConfig("Children", &graphql.Field{ + Type: gql_type_event_list, + Resolve: GQLEventChildren, + }) + + schemaConfig := graphql.SchemaConfig{ + Types: []graphql.Type{gql_type_base_event, gql_type_event_queue}, + Query: graphql.NewObject(graphql.ObjectConfig{ + Name: "Query", + Fields: graphql.Fields{ + "Event": &graphql.Field{ + Type: gql_interface_event, + 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 &schema +} + 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) + }) + + 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 <-server.signal: + case signal:=<-server.signal: + log.Logf("gql", "GOROUTINE_SIGNAL fot %s: %+v", server.ID(), signal) // Take signals to resource and send to GQL subscriptions - case <-server.gql_channel: - // Parse GQL query from channel and reply with resolved query } } }(abort)