From 272d7239f391f98bbc30fabbcc5bb85e49eaa634 Mon Sep 17 00:00:00 2001 From: Cory Slep Date: Fri, 15 Feb 2019 22:47:59 +0100 Subject: [PATCH] Generate generic ToType function. --- astool/convert/convert.go | 6 +- astool/gen/resolver.go | 99 ++++++++---- pub/base_actor.go | 4 +- pub/federating_wrapped_callbacks.go | 4 +- pub/resolvers.go | 234 ---------------------------- pub/side_effect_actor.go | 4 +- pub/social_wrapped_callbacks.go | 2 +- pub/util.go | 2 +- streams/gen_resolver_utils.go | 174 +++++++++++++++++++++ 9 files changed, 259 insertions(+), 270 deletions(-) diff --git a/astool/convert/convert.go b/astool/convert/convert.go index 758768e..ac4fdc6 100644 --- a/astool/convert/convert.go +++ b/astool/convert/convert.go @@ -1103,7 +1103,7 @@ func (c *Converter) propertyPackageFiles(pg *gen.PropertyGenerator, vocabName st // resolverFiles creates the files necessary for the resolvers. func (c *Converter) resolverFiles(pkg gen.Package, manGen *gen.ManagerGenerator, root vocabulary) (files []*File, e error) { rg := gen.NewResolverGenerator(root.allTypeArray(), manGen, pkg) - jsonRes, typeRes, typePredRes, errDefs, isUnFn, iFaces := rg.Definition() + jsonRes, typeRes, typePredRes, errDefs, fns, iFaces := rg.Definition() // Utils file := jen.NewFilePath(pkg.Path()) for _, errDef := range errDefs { @@ -1112,7 +1112,9 @@ func (c *Converter) resolverFiles(pkg gen.Package, manGen *gen.ManagerGenerator, for _, iFace := range iFaces { file.Add(iFace.Definition()).Line() } - file.Add(isUnFn.Definition()) + for _, fn := range fns { + file.Add(fn.Definition()).Line() + } files = append(files, &File{ F: file, FileName: "gen_resolver_utils.go", diff --git a/astool/gen/resolver.go b/astool/gen/resolver.go index f0a594a..7e7261c 100644 --- a/astool/gen/resolver.go +++ b/astool/gen/resolver.go @@ -44,7 +44,7 @@ type ResolverGenerator struct { cachedErrPredicateUnmatched jen.Code cachedErrCannotTypeAssert jen.Code cachedErrCannotTypeAssertPredicate jen.Code - cachedIsUnFn *codegen.Function + cachedFns []*codegen.Function cachedASInterface *codegen.Interface cachedResolverInterface *codegen.Interface } @@ -67,7 +67,7 @@ func NewResolverGenerator( // Definition returns the TypeResolver and PredicateTypeResolver. // // This function signature is pure garbage and yet I keep heaping it on. -func (r *ResolverGenerator) Definition() (jsonRes, typeRes, typePredRes *codegen.Struct, errs []jen.Code, isUnFn *codegen.Function, iFaces []*codegen.Interface) { +func (r *ResolverGenerator) Definition() (jsonRes, typeRes, typePredRes *codegen.Struct, errs []jen.Code, fns []*codegen.Function, iFaces []*codegen.Interface) { r.cacheOnce.Do(func() { r.cachedJSON = codegen.NewStruct( fmt.Sprintf("%s resolves a JSON-deserialized map into "+ @@ -139,7 +139,7 @@ func (r *ResolverGenerator) Definition() (jsonRes, typeRes, typePredRes *codegen r.cachedErrPredicateUnmatched = r.errorPredicateUnmatched() r.cachedErrCannotTypeAssert = r.errorCannotTypeAssert() r.cachedErrCannotTypeAssertPredicate = r.errorCannotTypeAssertPredicate() - r.cachedIsUnFn = r.isUnFn() + r.cachedFns = r.fns() r.cachedASInterface = r.asInterface() r.cachedResolverInterface = r.resolverInterface() }) @@ -149,7 +149,7 @@ func (r *ResolverGenerator) Definition() (jsonRes, typeRes, typePredRes *codegen r.cachedErrPredicateUnmatched, r.cachedErrCannotTypeAssert, r.cachedErrCannotTypeAssertPredicate, - }, r.cachedIsUnFn, []*codegen.Interface{ + }, r.cachedFns, []*codegen.Interface{ r.cachedASInterface, r.cachedResolverInterface, } @@ -205,28 +205,75 @@ func (r *ResolverGenerator) errorPredicateUnmatched() jen.Code { ).Line().Var().Id(errorPredicateUnmatched).Error().Op("=").Qual("errors", "New").Call(jen.Lit("activity stream did not match type demanded by predicate")) } -// isUnFn returns a function that returns true if an error is one dealing with -// Unmatched or Unhandled errors. -func (r *ResolverGenerator) isUnFn() *codegen.Function { - return codegen.NewCommentedFunction( - r.pkg.Path(), - isUnFnName, - []jen.Code{ - jen.Err().Error(), - }, - []jen.Code{ - jen.Bool(), - }, - []jen.Code{ - jen.Return( - jen.Err().Op("==").Id(errorPredicateUnmatched).Op( - "||", - ).Err().Op("==").Id(errorUnhandled).Op( - "||", - ).Err().Op("==").Id(errorNoMatch), - ), - }, - fmt.Sprintf("%s is true when the error indicates that a Resolver was unsuccessful due to the ActivityStreams value not matching its callbacks or predicates.", isUnFnName)) +// fns returns all utility functions. +func (r *ResolverGenerator) fns() []*codegen.Function { + allTypeFns := make([]jen.Code, 0) + for _, t := range r.types { + allTypeFns = append(allTypeFns, jen.Func().Params( + jen.Id("ctx").Qual("context", "Context"), + jen.Id("i").Qual(t.PublicPackage().Path(), t.InterfaceName()), + ).Error().Block( + jen.Id("t").Op("=").Id("i"), + jen.Return(jen.Nil()), + )) + } + return []*codegen.Function{ + codegen.NewCommentedFunction( + r.pkg.Path(), + isUnFnName, + []jen.Code{ + jen.Err().Error(), + }, + []jen.Code{ + jen.Bool(), + }, + []jen.Code{ + jen.Return( + jen.Err().Op("==").Id(errorPredicateUnmatched).Op( + "||", + ).Err().Op("==").Id(errorUnhandled).Op( + "||", + ).Err().Op("==").Id(errorNoMatch), + ), + }, + fmt.Sprintf("%s is true when the error indicates that a Resolver was unsuccessful due to the ActivityStreams value not matching its callbacks or predicates.", isUnFnName)), + codegen.NewCommentedFunction( + r.types[0].PublicPackage().Path(), + fmt.Sprintf("To%s", typeInterfaceName), + []jen.Code{ + jen.Id("c").Qual("context", "Context"), + jen.Id("m").Map(jen.String()).Interface(), + }, + []jen.Code{ + jen.Id("t").Qual(r.types[0].PublicPackage().Path(), typeInterfaceName), + jen.Err().Error(), + }, + []jen.Code{ + jen.Var().Id("r").Op("*").Qual(r.pkg.Path(), jsonResolverStructName), + jen.List( + jen.Id("r"), + jen.Err(), + ).Op("=").Qual( + r.pkg.Path(), + fmt.Sprintf("%s%s", constructorName, jsonResolverStructName), + ).Call( + jen.List( + allTypeFns..., + ), + ), + jen.If( + jen.Err().Op("!=").Nil(), + ).Block( + jen.Return(), + ), + jen.Err().Op("=").Id("r").Dot(resolveMethod).Call( + jen.Id("c"), + jen.Id("m"), + ), + jen.Return(), + }, + fmt.Sprintf("To%s attempts to resolve the generic JSON map into a Type.", typeInterfaceName)), + } } // jsonResolverMethods returns the methods for the TypeResolver. diff --git a/pub/base_actor.go b/pub/base_actor.go index 4f1ab9b..0daf8ec 100644 --- a/pub/base_actor.go +++ b/pub/base_actor.go @@ -171,7 +171,7 @@ func (b *baseActor) PostInbox(c context.Context, w http.ResponseWriter, r *http. if err = json.Unmarshal(raw, &m); err != nil { return true, err } - asValue, err := toType(c, m) + asValue, err := streams.ToType(c, m) if err != nil && !streams.IsUnmatchedErr(err) { return true, err } else if streams.IsUnmatchedErr(err) { @@ -302,7 +302,7 @@ func (b *baseActor) PostOutbox(c context.Context, w http.ResponseWriter, r *http // not known to go-fed. This prevents accidentally wrapping an Activity // type unknown to go-fed in a Create below. Instead, // streams.ErrUnhandledType will be returned here. - asValue, err := toType(c, m) + asValue, err := streams.ToType(c, m) if err != nil && !streams.IsUnmatchedErr(err) { return true, err } else if streams.IsUnmatchedErr(err) { diff --git a/pub/federating_wrapped_callbacks.go b/pub/federating_wrapped_callbacks.go index ac83cf3..8ed1751 100644 --- a/pub/federating_wrapped_callbacks.go +++ b/pub/federating_wrapped_callbacks.go @@ -246,7 +246,7 @@ func (w FederatingWrappedCallbacks) create(c context.Context, a vocab.ActivitySt if err = json.Unmarshal(b, &m); err != nil { return err } - t, err = toType(c, m) + t, err = streams.ToType(c, m) if err != nil { return err } @@ -505,7 +505,7 @@ func (w FederatingWrappedCallbacks) accept(c context.Context, a vocab.ActivitySt if err = json.Unmarshal(b, &m); err != nil { return err } - t, err = toType(c, m) + t, err = streams.ToType(c, m) if err != nil { return err } diff --git a/pub/resolvers.go b/pub/resolvers.go index 47d46f5..f94df4a 100644 --- a/pub/resolvers.go +++ b/pub/resolvers.go @@ -13,240 +13,6 @@ func IsAnActivityType(value vocab.Type) bool { return value.GetTypeName() == "Activity" || streams.ActivityStreamsActivityIsExtendedBy(value) } -// toAsType converts a generic map[string]interface{} into a known Type. -// -// Returns errors under the same conditions as streams.JSONResolver does. -func toType(c context.Context, m map[string]interface{}) (a vocab.Type, e error) { - var r *streams.JSONResolver - // Every time new types are added, need to update this list. It looks - // painful, but in practice VIM macros make it easier to manage. - // - // TODO: Somehow generate this more easily. - r, e = streams.NewJSONResolver( - func(ctx context.Context, i vocab.ActivityStreamsAccept) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsActivity) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsAdd) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsAnnounce) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsApplication) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsArrive) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsArticle) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsAudio) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsBlock) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsCollection) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsCollectionPage) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsCreate) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsDelete) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsDislike) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsDocument) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsEvent) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsFlag) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsFollow) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsGroup) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsIgnore) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsImage) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsIntransitiveActivity) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsInvite) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsJoin) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsLeave) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsLike) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsLink) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsListen) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsMention) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsMove) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsNote) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsObject) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsOffer) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsOrderedCollection) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsOrderedCollectionPage) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsOrganization) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsPage) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsPerson) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsPlace) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsProfile) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsQuestion) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsRead) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsReject) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsRelationship) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsRemove) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsService) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsTentativeAccept) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsTentativeReject) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsTombstone) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsTravel) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsUndo) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsUpdate) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsVideo) error { - a = i - return nil - }, - func(ctx context.Context, i vocab.ActivityStreamsView) error { - a = i - return nil - }, - ) - if e != nil { - return - } - e = r.Resolve(c, m) - return -} - // addToCreate adds the object to the Create activity. func addToCreate(ctx context.Context, c vocab.ActivityStreamsCreate, o vocab.Type) error { obj := c.GetActivityStreamsObject() diff --git a/pub/side_effect_actor.go b/pub/side_effect_actor.go index e6b2c15..ac880b6 100644 --- a/pub/side_effect_actor.go +++ b/pub/side_effect_actor.go @@ -543,7 +543,7 @@ func (a *sideEffectActor) hasInboxForwardingValues(c context.Context, inboxIRI * if err = json.Unmarshal(b, &m); err != nil { return false, err } - t, err := toType(c, m) + t, err := streams.ToType(c, m) if err != nil { // Do not fail the entire process if we cannot handle // the type. @@ -729,7 +729,7 @@ func (a *sideEffectActor) dereferenceForResolvingInboxes(c context.Context, t Tr if err = json.Unmarshal(resp, &m); err != nil { return } - actor, err = toType(c, m) + actor, err = streams.ToType(c, m) if err != nil { return } diff --git a/pub/social_wrapped_callbacks.go b/pub/social_wrapped_callbacks.go index 4a9dc86..973e9c5 100644 --- a/pub/social_wrapped_callbacks.go +++ b/pub/social_wrapped_callbacks.go @@ -322,7 +322,7 @@ func (w SocialWrappedCallbacks) update(c context.Context, a vocab.ActivityStream delete(m, k) } } - newT, err := toType(c, m) + newT, err := streams.ToType(c, m) if err != nil { return err } diff --git a/pub/util.go b/pub/util.go index 5076212..00f5122 100644 --- a/pub/util.go +++ b/pub/util.go @@ -799,7 +799,7 @@ func mustHaveActivityActorsMatchObjectActors(c context.Context, if err = json.Unmarshal(b, &m); err != nil { return err } - t, err = toType(c, m) + t, err = streams.ToType(c, m) if err != nil { return err } diff --git a/streams/gen_resolver_utils.go b/streams/gen_resolver_utils.go index 4388cf6..1ce4fd7 100644 --- a/streams/gen_resolver_utils.go +++ b/streams/gen_resolver_utils.go @@ -3,6 +3,7 @@ package streams import ( "context" "errors" + vocab "github.com/go-fed/activity/streams/vocab" ) // ErrNoCallbackMatch indicates a Resolver could not match the ActivityStreams value to a callback function. @@ -42,3 +43,176 @@ type Resolver interface { func IsUnmatchedErr(err error) bool { return err == ErrPredicateUnmatched || err == ErrUnhandledType || err == ErrNoCallbackMatch } + +// ToType attempts to resolve the generic JSON map into a Type. +func ToType(c context.Context, m map[string]interface{}) (t vocab.Type, err error) { + var r *JSONResolver + r, err = NewJSONResolver(func(ctx context.Context, i vocab.ActivityStreamsAccept) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsActivity) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsAdd) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsAnnounce) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsApplication) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsArrive) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsArticle) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsAudio) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsBlock) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsCollection) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsCollectionPage) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsCreate) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsDelete) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsDislike) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsDocument) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsEvent) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsFlag) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsFollow) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsGroup) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsIgnore) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsImage) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsIntransitiveActivity) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsInvite) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsJoin) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsLeave) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsLike) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsLink) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsListen) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsMention) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsMove) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsNote) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsObject) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsOffer) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsOrderedCollection) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsOrderedCollectionPage) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsOrganization) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsPage) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsPerson) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsPlace) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsProfile) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsQuestion) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsRead) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsReject) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsRelationship) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsRemove) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsService) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsTentativeAccept) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsTentativeReject) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsTombstone) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsTravel) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsUndo) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsUpdate) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsVideo) error { + t = i + return nil + }, func(ctx context.Context, i vocab.ActivityStreamsView) error { + t = i + return nil + }) + if err != nil { + return + } + err = r.Resolve(c, m) + return +}