Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pluggable Vocabulary System into pub #66

Closed
cjslep opened this issue Aug 1, 2018 · 5 comments

Comments

Projects
None yet
2 participants
@cjslep
Copy link
Member

commented Aug 1, 2018

#65 solves getting a read-in vocabulary into Go code. However, once generated, the dumb thing to do would be to hardcode every single vocabulary into the go-fed library.

Not every client wants every single vocabulary. The Core and Extended ActivityStream types will always be provided, due to the default behaviors supported by pub. However, extensions beyond these vocabularies should be optionally compiled in and/or supported by the client application.

The golang-esque thing to do would be to design a system similar to the sql.Driver system. There, database vendors are able to call sql.Register (MySql ex) at init time in their driver library. The drivers are stored in a global map in database/sql. At runtime, the map is accessed in a thread-safe manner, but the drivers may be concurrently managing a pool of connections to the resulting client code.

For go-fed/pub this would look like:

  • Every vocabulary has an implementation that satisfies a pub.Vocabulary interface type (which provides 2 things: the context string, and a func (vocab.Activity, pub.Callbacker) bool)
  • Have clients pass in a pub.Callbacker still. It could also handle extended activity types.
  • Every vocabulary and extension would call pub.Register with their own implementation of pub.Vocabulary. This means pub would now have access to the different vocabularies
  • All the @context can then be added to outgoing messages
  • The incoming messages would then work as follows: handle the activity with the vocab.Resolver (currently stream.Resolver) for core types. If the Activity type is not handled, iterate through all pub.Vocabulary types to find if the func (vocab.Activity, pub.Callbacker) bool was able to send its specific activity (inspecting the type value) to the client-supplied pub.Callbacker (type assertion).

This means a client would have myApp.MyCallbacker implement the following pub interface as usual:

type Callbacker interface {
  Create(c context.Context, s *vocab.Create) error
  Update(c context.Context, s *vocab.Update) error
  Delete(c context.Context, s *vocab.Delete) error
  Add(c context.Context, s *vocab.Add) error
  Remove(c context.Context, s *vocab.Remove) error
  Like(c context.Context, s *vocab.Like) error
  Block(c context.Context, s *vocab.Block) error
  Follow(c context.Context, s *vocab.Follow) error
  Undo(c context.Context, s *vocab.Undo) error
  Accept(c context.Context, s *vocab.Accept) error
  Reject(c context.Context, s *vocab.Reject) error
}

But then could also have myApp.MyCallbacker implement a anExtendedVocab.Callbacker interface as well:

type Callbacker interface {
  FirstExtendedActivity(c context.Context, s *FirstExtendedActivity) error
  SecondExtendedActivity(c context.Context, s *SecondExtendedActivity) error
  ThirdExtendedActivity(c context.Context, s *ThirdExtendedActivity) error
}

Finally, the client application would just need to make sure to compile against all vocabularies desired, so that their init functions can call pub.Register:

import (
  "github.com/go-fed/activity/pub" // github.com/go-fed/activity/vocab already implied here
  _ "github.com/go-fed/activity/anExtendedVocab"
)

// Make sure myApp's Callbacker will be successfully type asserted
var _ anExtendedVocab.Callbacker = &myApp.MyCallbacker{}
var _ pub.Callbacker = &myApp.MyCallbacker{}
@transitracer

This comment has been minimized.

Copy link

commented Aug 6, 2018

Have you considered the route of using actual go plugins for this? They're not very properly documented in many places it doesn't seem like, but here's an example of their use: https://medium.com/learning-the-go-programming-language/writing-modular-go-programs-with-plugins-ec46381ee1a9

It's the approach I was planning on using with pubstomp

That said, I haven't looked too deeply into the structure of this lib to see how it would work in your specific context, but if it were able to generate plugins for extensions it would solve the "compile-in" problem

@cjslep

This comment has been minimized.

Copy link
Member Author

commented Aug 6, 2018

Wow, I must have fallen asleep during the Go 1.8 release. This is great!

Plugins could definitely work. A bummer is that it only works for Linux and macOS architectures. So my gut feeling is I would like to provide both options: static lib for those that cannot have plugins and/or don't want to have dynamic loading (vuln concern), dynamic lib for those who want to be able to drag-and-drop new vocabularies (and, presumably, their new application logic for their app to dynamically load too).

Additional challenges (which can be overcome) to this I see are:

  • plugins must use the main package name, but static libraries will want to use descriptive package names.
  • Automatically (fsnotify?) or periodically detecting new vocabularies for dynamically provided libs
  • Having clear enough instructions for others to know how to compile using the static method, or load via the dynamic one (so they don't compile their app statically but use go-fed dynamically).

The confusion around this last bullet point is a small motivation for just picking one (static, dynamic linking) and sticking with it.

@cjslep

This comment has been minimized.

Copy link
Member Author

commented Jan 26, 2019

Unfortunately it seems that doing a dynamic library solution is not going to happen for go-fed v1, based on my experience developing the latest update to the tool in tools/exp.

However, still leaving this bug open to work on getting pub over to the new system, which should be a "pluggable" one.

@cjslep

This comment has been minimized.

Copy link
Member Author

commented Feb 15, 2019

The v1 pub package can now support arbitrary ActivityStreams vocabulary:

  • Obtain an OWL definition of all ontologies.
  • Run the astool with all vocabularies desired and all their dependencies in the streams package.
  • (New pub app) Build an application using the pub package.
  • (Existing pub app) Add some new callback functions, make sure they're returned by SocialProtocol.Callbacks or FederatingProtocol.Callbacks.

I originally set out with go-fed to "not care about linked data" but now that I'm staring the astool in the face... I hate to admit I'm probably some kind of RDF/linked data developer now.

@cjslep cjslep closed this Feb 15, 2019

@cjslep

This comment has been minimized.

Copy link
Member Author

commented Feb 15, 2019

(note that at runtime, go-fed is still not RDF/linked data aware, which is fine by me)

@cjslep cjslep self-assigned this Feb 15, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.