Added updateEvent to event tree and tested cancelling the event over graphql

graph-rework
noah metz 2023-06-08 16:41:51 -06:00
parent fd144eea02
commit be2e227a1d
3 changed files with 181 additions and 21 deletions

157
gql.go

@ -10,6 +10,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"sync" "sync"
"time"
) )
func GraphiQLHandler() func(http.ResponseWriter, *http.Request) { func GraphiQLHandler() func(http.ResponseWriter, *http.Request) {
@ -93,6 +94,8 @@ func GraphiQLHandler() func(http.ResponseWriter, *http.Request) {
type GQLQuery struct { type GQLQuery struct {
Query string `json:"query"` Query string `json:"query"`
OperationName string `json:"operationName"`
Variables map[string]interface{} `json:"variables"`
} }
func GQLHandler(schema graphql.Schema, ctx context.Context) func(http.ResponseWriter, *http.Request) { func GQLHandler(schema graphql.Schema, ctx context.Context) func(http.ResponseWriter, *http.Request) {
@ -104,13 +107,24 @@ func GQLHandler(schema graphql.Schema, ctx context.Context) func(http.ResponseWr
} }
res := GQLQuery{} res := GQLQuery{}
json.Unmarshal(str, &res) json.Unmarshal(str, &res)
result := graphql.Do(graphql.Params{ params := graphql.Params{
Schema: schema, Schema: schema,
Context: ctx, Context: ctx,
RequestString: res.Query, RequestString: res.Query,
}) }
if res.OperationName != "" {
params.OperationName = res.OperationName
}
if len(res.Variables) > 0 {
log.Logf("gql", "VARIABLES: %+v", res.Variables)
params.VariableValues = res.Variables
}
result := graphql.Do(params)
if len(result.Errors) > 0 { if len(result.Errors) > 0 {
log.Logf("gql", "wrong result, unexpected errors: %v", result.Errors) extra_fields := map[string]interface{}{}
extra_fields["body"] = string(str)
extra_fields["headers"] = r.Header
log.Logm("gql", extra_fields, "wrong result, unexpected errors: %v", result.Errors)
} }
json.NewEncoder(w).Encode(result) json.NewEncoder(w).Encode(result)
} }
@ -395,6 +409,93 @@ func GQLTypeEventQueue() * graphql.Object {
return gql_type_event_queue return gql_type_event_queue
} }
func GQLSignalFn(p graphql.ResolveParams, fn func(GraphSignal, graphql.ResolveParams)(interface{}, error))(interface{}, error) {
if signal, ok := p.Source.(GraphSignal); ok {
return fn(signal, p)
}
return nil, errors.New("Failed to cast source to event")
}
func GQLSignalType(p graphql.ResolveParams) (interface{}, error) {
return GQLSignalFn(p, func(signal GraphSignal, p graphql.ResolveParams)(interface{}, error){
return signal.Type(), nil
})
}
func GQLSignalDesc(p graphql.ResolveParams) (interface{}, error) {
return GQLSignalFn(p, func(signal GraphSignal, p graphql.ResolveParams)(interface{}, error){
return signal.Description(), nil
})
}
func GQLSignalTime(p graphql.ResolveParams) (interface{}, error) {
return GQLSignalFn(p, func(signal GraphSignal, p graphql.ResolveParams)(interface{}, error){
return signal.Time(), nil
})
}
func GQLSignalString(p graphql.ResolveParams) (interface{}, error) {
return GQLSignalFn(p, func(signal GraphSignal, p graphql.ResolveParams)(interface{}, error){
return signal.String(), nil
})
}
var gql_type_signal *graphql.Object = nil
func GQLTypeSignal() *graphql.Object {
if gql_type_signal == nil {
gql_type_signal = graphql.NewObject(graphql.ObjectConfig{
Name: "SignalOut",
IsTypeOf: func(p graphql.IsTypeOfParams) bool {
_, ok := p.Value.(GraphSignal)
return ok
},
Fields: graphql.Fields{},
})
gql_type_signal.AddFieldConfig("Type", &graphql.Field{
Type: graphql.String,
Resolve: GQLSignalType,
})
gql_type_signal.AddFieldConfig("Description", &graphql.Field{
Type: graphql.String,
Resolve: GQLSignalDesc,
})
gql_type_signal.AddFieldConfig("Time", &graphql.Field{
Type: graphql.DateTime,
Resolve: GQLSignalTime,
})
gql_type_signal.AddFieldConfig("String", &graphql.Field{
Type: graphql.String,
Resolve: GQLSignalString,
})
}
return gql_type_signal
}
var gql_type_signal_input *graphql.InputObject = nil
func GQLTypeSignalInput() *graphql.InputObject {
if gql_type_signal_input == nil {
gql_type_signal_input = graphql.NewInputObject(graphql.InputObjectConfig{
Name: "SignalIn",
Fields: graphql.InputObjectConfigFieldMap{},
})
gql_type_signal_input.AddFieldConfig("Type", &graphql.InputObjectFieldConfig{
Type: graphql.String,
})
gql_type_signal_input.AddFieldConfig("Description", &graphql.InputObjectFieldConfig{
Type: graphql.String,
DefaultValue: "",
})
gql_type_signal_input.AddFieldConfig("Time", &graphql.InputObjectFieldConfig{
Type: graphql.DateTime,
DefaultValue: time.Now(),
})
}
return gql_type_signal_input
}
type GQLServer struct { type GQLServer struct {
BaseResource BaseResource
abort chan error abort chan error
@ -428,7 +529,7 @@ func (server * GQLServer) Handler() func(http.ResponseWriter, *http.Request) {
valid_resources := map[reflect.Type]*graphql.Object{} valid_resources := map[reflect.Type]*graphql.Object{}
valid_resources[reflect.TypeOf((*BaseResource)(nil))] = GQLTypeBaseResource() valid_resources[reflect.TypeOf((*BaseResource)(nil))] = GQLTypeBaseResource()
gql_types := []graphql.Type{GQLTypeBaseEvent(), GQLTypeEventQueue()} gql_types := []graphql.Type{GQLTypeBaseEvent(), GQLTypeEventQueue(), GQLTypeSignal(), GQLTypeSignalInput()}
for go_t, gql_t := range(server.extended_types) { for go_t, gql_t := range(server.extended_types) {
valid_events[go_t] = gql_t valid_events[go_t] = gql_t
gql_types = append(gql_types, gql_t) gql_types = append(gql_types, gql_t)
@ -436,6 +537,54 @@ func (server * GQLServer) Handler() func(http.ResponseWriter, *http.Request) {
schemaConfig := graphql.SchemaConfig{ schemaConfig := graphql.SchemaConfig{
Types: gql_types, Types: gql_types,
Mutation: graphql.NewObject(graphql.ObjectConfig{
Name: "Mutation",
Fields: graphql.Fields{
"updateEvent": &graphql.Field{
Type: GQLTypeSignal(),
Args: graphql.FieldConfigArgument{
"id": &graphql.ArgumentConfig{
Type: graphql.String,
},
"signal": &graphql.ArgumentConfig{
Type: GQLTypeSignalInput(),
},
},
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
signal_map, ok := p.Args["signal"].(map[string]interface{})
if ok == false {
return nil, errors.New(fmt.Sprintf("Failed to cast arg signal to GraphSignal: %+v", p.Args["signal"]))
}
signal := NewSignal(server, signal_map["Type"].(string))
signal.description = signal_map["Description"].(string)
signal.time = signal_map["Time"].(time.Time)
id , ok := p.Args["id"].(string)
if ok == false {
return nil, errors.New("Failed to cast arg id to string")
}
owner := server.Owner()
if owner == nil {
return nil, errors.New("Cannot send update without owner")
}
root_event, ok := owner.(Event)
if ok == false {
return nil, errors.New("Cannot send update to Event unless owned by an Event")
}
node := FindChild(root_event, id)
if node == nil {
return nil, errors.New("Failed to find id in event tree from server")
}
SendUpdate(node, signal)
return signal, nil
},
},
},
}),
Query: graphql.NewObject(graphql.ObjectConfig{ Query: graphql.NewObject(graphql.ObjectConfig{
Name: "Query", Name: "Query",
Fields: graphql.Fields{ Fields: graphql.Fields{

@ -13,6 +13,7 @@ import (
type Logger interface { type Logger interface {
Init() error Init() error
Logf(component string, format string, items ... interface{}) Logf(component string, format string, items ... interface{})
Logm(component string, fields map[string]interface{}, format string, items ... interface{})
} }
type DefaultLogger struct { type DefaultLogger struct {
@ -25,6 +26,15 @@ var log DefaultLogger = DefaultLogger{loggers: map[string]zerolog.Logger{}}
var all_components = []string{"update", "graph", "event", "resource", "manager", "test", "gql"} var all_components = []string{"update", "graph", "event", "resource", "manager", "test", "gql"}
func (logger * DefaultLogger) Init(components []string) error { func (logger * DefaultLogger) Init(components []string) error {
logger.init_lock.Lock()
defer logger.init_lock.Unlock()
if logger.init == true {
return nil
}
logger.init = true
file, err := os.OpenFile("test.log", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0666) file, err := os.OpenFile("test.log", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil { if err != nil {
return err return err
@ -40,24 +50,28 @@ func (logger * DefaultLogger) Init(components []string) error {
} }
writer := io.MultiWriter(file, os.Stdout) writer := io.MultiWriter(file, os.Stdout)
for _, c := range([]string{"gql"}) { for _, c := range(all_components) {
if component_enabled(c) == true { if component_enabled(c) == true {
logger.loggers[c] = zerolog.New(writer).With().Timestamp().Str("component", c).Logger() logger.loggers[c] = zerolog.New(writer).With().Timestamp().Str("component", c).Logger()
} else {
panic(fmt.Sprintf("%s is not a component in DefaultLogger", c))
} }
} }
return nil return nil
} }
func (logger * DefaultLogger) Logf(component string, format string, items ... interface{}) { func (logger * DefaultLogger) Logm(component string, fields map[string]interface{}, format string, items ... interface{}) {
logger.init_lock.Lock() logger.Init([]string{"gql"})
if logger.init == false { l, exists := logger.loggers[component]
logger.Init(all_components) if exists == true {
logger.init = true log := l.Log()
for key, value := range(fields) {
log = log.Str(key, fmt.Sprintf("%+v", value))
}
log.Msg(fmt.Sprintf(format, items...))
}
} }
logger.init_lock.Unlock()
func (logger * DefaultLogger) Logf(component string, format string, items ... interface{}) {
logger.Init([]string{"gql"})
l, exists := logger.loggers[component] l, exists := logger.loggers[component]
if exists == true { if exists == true {
l.Log().Msg(fmt.Sprintf(format, items...)) l.Log().Msg(fmt.Sprintf(format, items...))

@ -241,7 +241,7 @@ func (client * FakeClient) process_update(update GraphSignal) {
} }
func main() { func main() {
event_manager, arenas_div1, arenas_div2 := fake_data() event_manager, _, _ := fake_data()
sigs := make(chan os.Signal, 1) sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
@ -261,11 +261,12 @@ func main() {
pprof.WriteHeapProfile(memfile) pprof.WriteHeapProfile(memfile)
}() }()
// Fake arena clients /*// Fake arena clients
arena_1_client := NewFakeClient(arenas_div1[0]) arena_1_client := NewFakeClient(arenas_div1[0])
arena_2_client := NewFakeClient(arenas_div1[1]) arena_2_client := NewFakeClient(arenas_div1[1])
arena_3_client := NewFakeClient(arenas_div2[0]) arena_3_client := NewFakeClient(arenas_div2[0])
arena_4_client := NewFakeClient(arenas_div2[1]) arena_4_client := NewFakeClient(arenas_div2[1])
*/
go func() { go func() {
for true { for true {
select { select {
@ -276,7 +277,7 @@ func main() {
time.Sleep(time.Second * 5) time.Sleep(time.Second * 5)
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1) pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
break break
case update := <- arena_1_client.update: /*case update := <- arena_1_client.update:
arena_1_client.process_update(update) arena_1_client.process_update(update)
case update := <- arena_2_client.update: case update := <- arena_2_client.update:
arena_2_client.process_update(update) arena_2_client.process_update(update)
@ -291,7 +292,7 @@ func main() {
arena_4_client.games_done == 12 { arena_4_client.games_done == 12 {
//signal := NewSignal(nil, "cancel") //signal := NewSignal(nil, "cancel")
//signal.description = event_manager.root_event.ID() //signal.description = event_manager.root_event.ID()
//SendUpdate(event_manager.root_event, signal) //SendUpdate(event_manager.root_event, signal)*/
} }
} }
}() }()
@ -302,10 +303,6 @@ func main() {
log.Logf("test", "Error running event_manager: %s", err) log.Logf("test", "Error running event_manager: %s", err)
} else { } else {
log.Logf("test", "Finished event_manager") log.Logf("test", "Finished event_manager")
log.Logf("test", "Client 1 games: %d", arena_1_client.games_done)
log.Logf("test", "Client 2 games: %d", arena_2_client.games_done)
log.Logf("test", "Client 3 games: %d", arena_3_client.games_done)
log.Logf("test", "Client 4 games: %d", arena_4_client.games_done)
} }
pprof.StopCPUProfile() pprof.StopCPUProfile()
} }