|
|
@ -19,12 +19,16 @@ type NodeLoadFunc func(*Context, NodeID, []byte, NodeMap)(Node, error)
|
|
|
|
type NodeDef struct {
|
|
|
|
type NodeDef struct {
|
|
|
|
Load NodeLoadFunc
|
|
|
|
Load NodeLoadFunc
|
|
|
|
Type NodeType
|
|
|
|
Type NodeType
|
|
|
|
|
|
|
|
GQLType *graphql.Object
|
|
|
|
|
|
|
|
Reflect reflect.Type
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func NewNodeDef(type_name string, load_func NodeLoadFunc) NodeDef {
|
|
|
|
func NewNodeDef(type_name string, reflect reflect.Type, load_func NodeLoadFunc, gql_type *graphql.Object) NodeDef {
|
|
|
|
return NodeDef{
|
|
|
|
return NodeDef{
|
|
|
|
Type: NodeType(type_name),
|
|
|
|
Type: NodeType(type_name),
|
|
|
|
Load: load_func,
|
|
|
|
Load: load_func,
|
|
|
|
|
|
|
|
GQLType: gql_type,
|
|
|
|
|
|
|
|
Reflect: reflect,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -32,181 +36,158 @@ type Context struct {
|
|
|
|
DB * badger.DB
|
|
|
|
DB * badger.DB
|
|
|
|
Log Logger
|
|
|
|
Log Logger
|
|
|
|
Types map[uint64]NodeDef
|
|
|
|
Types map[uint64]NodeDef
|
|
|
|
GQL * GQLContext
|
|
|
|
GQL GQLContext
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (ctx * Context) RegisterNodeType(type_name string, load_func NodeLoadFunc) error {
|
|
|
|
func (ctx * Context) RebuildSchema() error {
|
|
|
|
if load_func == nil {
|
|
|
|
schemaConfig := graphql.SchemaConfig{
|
|
|
|
return fmt.Errorf("Cannot register a node without a load function")
|
|
|
|
Types: ctx.GQL.TypeList,
|
|
|
|
}
|
|
|
|
Query: ctx.GQL.Query,
|
|
|
|
|
|
|
|
Mutation: ctx.GQL.Mutation,
|
|
|
|
def := NodeDef{
|
|
|
|
Subscription: ctx.GQL.Subscription,
|
|
|
|
Type: NodeType(type_name),
|
|
|
|
|
|
|
|
Load: load_func,
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type_hash := def.Type.Hash()
|
|
|
|
schema, err := graphql.NewSchema(schemaConfig)
|
|
|
|
_, exists := ctx.Types[type_hash]
|
|
|
|
if err != nil {
|
|
|
|
if exists == true {
|
|
|
|
return err
|
|
|
|
return fmt.Errorf("Cannot register node of type %s, type already exists in context", type_name)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ctx.Types[type_hash] = def
|
|
|
|
ctx.GQL.Schema = schema
|
|
|
|
return nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type TypeList []graphql.Type
|
|
|
|
func (ctx * Context) AddGQLType(gql_type graphql.Type) {
|
|
|
|
type ObjTypeMap map[reflect.Type]*graphql.Object
|
|
|
|
ctx.GQL.TypeList = append(ctx.GQL.TypeList, gql_type)
|
|
|
|
type FieldMap map[string]*graphql.Field
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type GQLContext struct {
|
|
|
|
|
|
|
|
Schema graphql.Schema
|
|
|
|
|
|
|
|
ValidNodes ObjTypeMap
|
|
|
|
|
|
|
|
NodeType reflect.Type
|
|
|
|
|
|
|
|
ValidLockables ObjTypeMap
|
|
|
|
|
|
|
|
LockableType reflect.Type
|
|
|
|
|
|
|
|
ValidThreads ObjTypeMap
|
|
|
|
|
|
|
|
ThreadType reflect.Type
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func NewGQLContext(additional_types TypeList, extended_types ObjTypeMap, extended_queries FieldMap, extended_subscriptions FieldMap, extended_mutations FieldMap) (*GQLContext, error) {
|
|
|
|
func (ctx * Context) RegisterNodeType(def NodeDef) error {
|
|
|
|
type_list := TypeList{
|
|
|
|
if def.Load == nil {
|
|
|
|
GQLTypeSignalInput(),
|
|
|
|
return fmt.Errorf("Cannot register a node without a load function: %s", def.Type)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, gql_type := range(additional_types) {
|
|
|
|
if def.Reflect == nil {
|
|
|
|
type_list = append(type_list, gql_type)
|
|
|
|
return fmt.Errorf("Cannot register a node without a reflect type: %s", def.Type)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type_map := ObjTypeMap{}
|
|
|
|
if def.GQLType == nil {
|
|
|
|
type_map[reflect.TypeOf((*GraphNode)(nil))] = GQLTypeBaseNode()
|
|
|
|
return fmt.Errorf("Cannot register a node without a gql type: %s", def.Type)
|
|
|
|
type_map[reflect.TypeOf((*SimpleLockable)(nil))] = GQLTypeBaseLockable()
|
|
|
|
|
|
|
|
type_map[reflect.TypeOf((*SimpleThread)(nil))] = GQLTypeBaseThread()
|
|
|
|
|
|
|
|
type_map[reflect.TypeOf((*GQLThread)(nil))] = GQLTypeGQLThread()
|
|
|
|
|
|
|
|
type_map[reflect.TypeOf((*BaseSignal)(nil))] = GQLTypeSignal()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for go_t, gql_t := range(extended_types) {
|
|
|
|
|
|
|
|
type_map[go_t] = gql_t
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
valid_nodes := ObjTypeMap{}
|
|
|
|
type_hash := def.Type.Hash()
|
|
|
|
valid_lockables := ObjTypeMap{}
|
|
|
|
_, exists := ctx.Types[type_hash]
|
|
|
|
valid_threads := ObjTypeMap{}
|
|
|
|
if exists == true {
|
|
|
|
|
|
|
|
return fmt.Errorf("Cannot register node of type %s, type already exists in context", def.Type)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
node_type := reflect.TypeOf((*Node)(nil)).Elem()
|
|
|
|
ctx.Types[type_hash] = def
|
|
|
|
lockable_type := reflect.TypeOf((*Lockable)(nil)).Elem()
|
|
|
|
|
|
|
|
thread_type := reflect.TypeOf((*Thread)(nil)).Elem()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for go_t, gql_t := range(type_map) {
|
|
|
|
if def.Reflect.Implements(ctx.GQL.NodeType) {
|
|
|
|
if go_t.Implements(node_type) {
|
|
|
|
ctx.GQL.ValidNodes[def.Reflect] = def.GQLType
|
|
|
|
valid_nodes[go_t] = gql_t
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if go_t.Implements(lockable_type) {
|
|
|
|
|
|
|
|
valid_lockables[go_t] = gql_t
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if go_t.Implements(thread_type) {
|
|
|
|
if def.Reflect.Implements(ctx.GQL.LockableType) {
|
|
|
|
valid_threads[go_t] = gql_t
|
|
|
|
ctx.GQL.ValidLockables[def.Reflect] = def.GQLType
|
|
|
|
}
|
|
|
|
}
|
|
|
|
type_list = append(type_list, gql_t)
|
|
|
|
if def.Reflect.Implements(ctx.GQL.ThreadType) {
|
|
|
|
|
|
|
|
ctx.GQL.ValidThreads[def.Reflect] = def.GQLType
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.GQL.TypeList = append(ctx.GQL.TypeList, def.GQLType)
|
|
|
|
|
|
|
|
|
|
|
|
queries := graphql.Fields{
|
|
|
|
return nil
|
|
|
|
"Self": GQLQuerySelf(),
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for key, val := range(extended_queries) {
|
|
|
|
type TypeList []graphql.Type
|
|
|
|
queries[key] = val
|
|
|
|
type ObjTypeMap map[reflect.Type]*graphql.Object
|
|
|
|
}
|
|
|
|
type FieldMap map[string]*graphql.Field
|
|
|
|
|
|
|
|
|
|
|
|
subscriptions := graphql.Fields{
|
|
|
|
type GQLContext struct {
|
|
|
|
"Update": GQLSubscriptionUpdate(),
|
|
|
|
Schema graphql.Schema
|
|
|
|
"Self": GQLSubscriptionSelf(),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for key, val := range(extended_subscriptions) {
|
|
|
|
NodeType reflect.Type
|
|
|
|
subscriptions[key] = val
|
|
|
|
LockableType reflect.Type
|
|
|
|
}
|
|
|
|
ThreadType reflect.Type
|
|
|
|
|
|
|
|
|
|
|
|
mutations := graphql.Fields{
|
|
|
|
TypeList TypeList
|
|
|
|
"SendUpdate": GQLMutationSendUpdate(),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for key, val := range(extended_mutations) {
|
|
|
|
ValidNodes ObjTypeMap
|
|
|
|
mutations[key] = val
|
|
|
|
ValidLockables ObjTypeMap
|
|
|
|
|
|
|
|
ValidThreads ObjTypeMap
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Query *graphql.Object
|
|
|
|
|
|
|
|
Mutation *graphql.Object
|
|
|
|
|
|
|
|
Subscription *graphql.Object
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
schemaConfig := graphql.SchemaConfig{
|
|
|
|
func NewGQLContext() GQLContext {
|
|
|
|
Types: type_list,
|
|
|
|
query := graphql.NewObject(graphql.ObjectConfig{
|
|
|
|
Query: graphql.NewObject(graphql.ObjectConfig{
|
|
|
|
|
|
|
|
Name: "Query",
|
|
|
|
Name: "Query",
|
|
|
|
Fields: queries,
|
|
|
|
Fields: graphql.Fields{},
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
Mutation: graphql.NewObject(graphql.ObjectConfig{
|
|
|
|
|
|
|
|
|
|
|
|
mutation := graphql.NewObject(graphql.ObjectConfig{
|
|
|
|
Name: "Mutation",
|
|
|
|
Name: "Mutation",
|
|
|
|
Fields: mutations,
|
|
|
|
Fields: graphql.Fields{},
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
Subscription: graphql.NewObject(graphql.ObjectConfig{
|
|
|
|
|
|
|
|
Name: "Subscription",
|
|
|
|
|
|
|
|
Fields: subscriptions,
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
schema, err := graphql.NewSchema(schemaConfig)
|
|
|
|
subscription := graphql.NewObject(graphql.ObjectConfig{
|
|
|
|
if err != nil{
|
|
|
|
Name: "Subscription",
|
|
|
|
return nil, err
|
|
|
|
Fields: graphql.Fields{},
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
ctx := GQLContext{
|
|
|
|
ctx := GQLContext{
|
|
|
|
Schema: schema,
|
|
|
|
Schema: graphql.Schema{},
|
|
|
|
ValidNodes: valid_nodes,
|
|
|
|
TypeList: TypeList{},
|
|
|
|
NodeType: node_type,
|
|
|
|
ValidNodes: ObjTypeMap{},
|
|
|
|
ValidThreads: valid_threads,
|
|
|
|
NodeType: reflect.TypeOf((*Node)(nil)).Elem(),
|
|
|
|
ThreadType: thread_type,
|
|
|
|
ValidThreads: ObjTypeMap{},
|
|
|
|
ValidLockables: valid_lockables,
|
|
|
|
ThreadType: reflect.TypeOf((*Thread)(nil)).Elem(),
|
|
|
|
LockableType: lockable_type,
|
|
|
|
ValidLockables: ObjTypeMap{},
|
|
|
|
|
|
|
|
LockableType: reflect.TypeOf((*Lockable)(nil)).Elem(),
|
|
|
|
|
|
|
|
Query: query,
|
|
|
|
|
|
|
|
Mutation: mutation,
|
|
|
|
|
|
|
|
Subscription: subscription,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return &ctx, nil
|
|
|
|
return ctx
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func NewContext(db * badger.DB, log Logger, extra_nodes map[string]NodeLoadFunc, types TypeList, type_map ObjTypeMap, queries FieldMap, subscriptions FieldMap, mutations FieldMap) * Context {
|
|
|
|
|
|
|
|
gql, err := NewGQLContext(types, type_map, queries, subscriptions, mutations)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
panic(err)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func NewContext(db * badger.DB, log Logger) * Context {
|
|
|
|
ctx := &Context{
|
|
|
|
ctx := &Context{
|
|
|
|
GQL: gql,
|
|
|
|
GQL: NewGQLContext(),
|
|
|
|
DB: db,
|
|
|
|
DB: db,
|
|
|
|
Log: log,
|
|
|
|
Log: log,
|
|
|
|
Types: map[uint64]NodeDef{},
|
|
|
|
Types: map[uint64]NodeDef{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
err := ctx.RegisterNodeType(NewNodeDef("graph_node", reflect.TypeOf((*GraphNode)(nil)), LoadGraphNode, GQLTypeGraphNode()))
|
|
|
|
|
|
|
|
|
|
|
|
err = ctx.RegisterNodeType("graph_node", LoadGraphNode)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err = ctx.RegisterNodeType("simple_lockable", LoadSimpleLockable)
|
|
|
|
err = ctx.RegisterNodeType(NewNodeDef("simple_lockable", reflect.TypeOf((*SimpleLockable)(nil)), LoadSimpleLockable, GQLTypeSimpleLockable()))
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err = ctx.RegisterNodeType("simple_thread", LoadSimpleThread)
|
|
|
|
err = ctx.RegisterNodeType(NewNodeDef("simple_thread", reflect.TypeOf((*SimpleThread)(nil)), LoadSimpleThread, GQLTypeSimpleThread()))
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err = ctx.RegisterNodeType("gql_thread", LoadGQLThread)
|
|
|
|
err = ctx.RegisterNodeType(NewNodeDef("gql_thread", reflect.TypeOf((*GQLThread)(nil)), LoadGQLThread, GQLTypeGQLThread()))
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for name, load_fn := range(extra_nodes) {
|
|
|
|
ctx.AddGQLType(GQLTypeSignal())
|
|
|
|
err := ctx.RegisterNodeType(name, load_fn)
|
|
|
|
|
|
|
|
|
|
|
|
ctx.GQL.Query.AddFieldConfig("Self", GQLQuerySelf())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ctx.GQL.Subscription.AddFieldConfig("Update", GQLSubscriptionUpdate())
|
|
|
|
|
|
|
|
ctx.GQL.Subscription.AddFieldConfig("Self", GQLSubscriptionSelf())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ctx.GQL.Mutation.AddFieldConfig("SendUpdate", GQLMutationSendUpdate())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
err = ctx.RebuildSchema()
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ctx
|
|
|
|
return ctx
|
|
|
|
}
|
|
|
|
}
|
|
|
|