Added gql_signal.go
parent
92d8dfd006
commit
0941c6c64e
@ -0,0 +1,193 @@
|
||||
package graphvent
|
||||
|
||||
import (
|
||||
graphql "github.com/graphql-go/graphql"
|
||||
"reflect"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type GQLTypeInfo struct {
|
||||
graphql.Type
|
||||
FromGQL func(interface{})(reflect.Value, error)
|
||||
}
|
||||
|
||||
var kind_gql_map = map[reflect.Kind]GQLTypeInfo{
|
||||
reflect.String: {
|
||||
graphql.String,
|
||||
func(value interface{})(reflect.Value, error) {
|
||||
return reflect.ValueOf(value), nil
|
||||
},
|
||||
},
|
||||
reflect.Bool: {
|
||||
graphql.Boolean,
|
||||
func(value interface{})(reflect.Value, error) {
|
||||
return reflect.ValueOf(value), nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var type_gql_map = map[reflect.Type]GQLTypeInfo{
|
||||
reflect.TypeOf(&NodeID{}): {
|
||||
graphql.String,
|
||||
func(value interface{}) (reflect.Value, error) {
|
||||
str, ok := value.(string)
|
||||
if ok == false {
|
||||
return reflect.Value{}, fmt.Errorf("value is not string")
|
||||
}
|
||||
|
||||
if str == "" {
|
||||
return reflect.New(reflect.TypeOf(NodeID{})), nil
|
||||
}
|
||||
|
||||
id_parsed, err := ParseID(str)
|
||||
if err != nil {
|
||||
return reflect.Value{}, err
|
||||
}
|
||||
|
||||
return reflect.ValueOf(&id_parsed), nil
|
||||
},
|
||||
},
|
||||
reflect.TypeOf(NodeID{}): {
|
||||
graphql.String,
|
||||
func(value interface{})(reflect.Value, error) {
|
||||
str, ok := value.(string)
|
||||
if ok == false {
|
||||
return reflect.Value{}, fmt.Errorf("value is not string")
|
||||
}
|
||||
|
||||
id_parsed, err := ParseID(str)
|
||||
if err != nil {
|
||||
return reflect.Value{}, err
|
||||
}
|
||||
|
||||
return reflect.ValueOf(id_parsed), nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type StructFieldInfo struct {
|
||||
Name string
|
||||
Type reflect.Type
|
||||
GQL *GQLTypeInfo
|
||||
Index []int
|
||||
}
|
||||
|
||||
func SignalFromArgs(signal_type reflect.Type, fields []StructFieldInfo, args map[string]interface{}) (Signal, error) {
|
||||
signal_value := reflect.New(signal_type)
|
||||
for _, field := range(fields) {
|
||||
arg, arg_exists := args[field.Name]
|
||||
if arg_exists == false {
|
||||
return nil, fmt.Errorf("No arg provided named %s", field.Name)
|
||||
}
|
||||
field_value := signal_value.Elem().FieldByIndex(field.Index)
|
||||
if field_value.CanConvert(field.Type) == false {
|
||||
return nil, fmt.Errorf("Arg %s wrong type %s/%s", field.Name, field_value.Type(), field.Type)
|
||||
}
|
||||
value, err := field.GQL.FromGQL(arg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
field_value.Set(value)
|
||||
}
|
||||
return signal_value.Interface().(Signal), nil
|
||||
}
|
||||
|
||||
func (ext *GQLExtContext) AddSignalMutation(name string, send_id_key string, signal_type reflect.Type) error {
|
||||
args := graphql.FieldConfigArgument{}
|
||||
arg_info := []StructFieldInfo{}
|
||||
|
||||
for _, field := range(reflect.VisibleFields(signal_type)) {
|
||||
gv_tag, tagged_gv := field.Tag.Lookup("gv")
|
||||
if tagged_gv {
|
||||
if gv_tag == "id" {
|
||||
continue
|
||||
}
|
||||
if gv_tag == "direction" {
|
||||
continue
|
||||
}
|
||||
_, exists := args[gv_tag]
|
||||
if exists == true {
|
||||
return fmt.Errorf("Signal has repeated tag %s", gv_tag)
|
||||
}
|
||||
var gql_info GQLTypeInfo
|
||||
var type_mapped bool
|
||||
gql_info, type_mapped = type_gql_map[field.Type]
|
||||
if type_mapped == false {
|
||||
var kind_mapped bool
|
||||
gql_info, kind_mapped = kind_gql_map[field.Type.Kind()]
|
||||
if kind_mapped == false {
|
||||
return fmt.Errorf("Signal has unsupported type/kind: %s/%s", field.Type, field.Type.Kind())
|
||||
}
|
||||
}
|
||||
|
||||
args[gv_tag] = &graphql.ArgumentConfig{
|
||||
Type: gql_info.Type,
|
||||
}
|
||||
arg_info = append(arg_info, StructFieldInfo{
|
||||
gv_tag,
|
||||
field.Type,
|
||||
&gql_info,
|
||||
field.Index,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
_, send_exists := args[send_id_key]
|
||||
if send_exists == false {
|
||||
args[send_id_key] = &graphql.ArgumentConfig{
|
||||
Type: graphql.String,
|
||||
}
|
||||
}
|
||||
|
||||
resolve_signal := func(p graphql.ResolveParams) (interface{}, error) {
|
||||
ctx, err := PrepResolve(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
send_id, err := ExtractID(p, send_id_key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
signal, err := SignalFromArgs(signal_type, arg_info, p.Args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msgs := Messages{}
|
||||
msgs = msgs.Add(ctx.Context, ctx.User, ctx.Key, signal, send_id)
|
||||
|
||||
response_chan := ctx.Ext.GetResponseChannel(signal.ID())
|
||||
err = ctx.Context.Send(msgs)
|
||||
if err != nil {
|
||||
ctx.Ext.FreeResponseChannel(signal.ID())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response, err := WaitForResponse(response_chan, 100*time.Millisecond, signal.ID())
|
||||
if err != nil {
|
||||
ctx.Ext.FreeResponseChannel(signal.ID())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, is_success := response.(*SuccessSignal)
|
||||
if is_success == true {
|
||||
return "success", nil
|
||||
}
|
||||
|
||||
error_response, is_error := response.(*ErrorSignal)
|
||||
if is_error == true {
|
||||
return "error", fmt.Errorf(error_response.Error)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("response of unhandled type %s", reflect.TypeOf(response))
|
||||
}
|
||||
|
||||
ext.Mutation.AddFieldConfig(name, &graphql.Field{
|
||||
Type: graphql.String,
|
||||
Args: args,
|
||||
Resolve: resolve_signal,
|
||||
})
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue