requesthook.go 3.11 KB
Newer Older
Hannah Howard's avatar
Hannah Howard committed
1
package hooks
2 3 4 5

import (
	"errors"

6
	"github.com/hannahhoward/go-pubsub"
7 8 9 10 11 12 13 14 15 16 17 18 19 20
	"github.com/ipfs/go-graphsync"
	"github.com/ipld/go-ipld-prime"
	"github.com/ipld/go-ipld-prime/traversal"
	peer "github.com/libp2p/go-libp2p-core/peer"
)

// PersistenceOptions is an interface for getting loaders by name
type PersistenceOptions interface {
	GetLoader(name string) (ipld.Loader, bool)
}

// IncomingRequestHooks is a set of incoming request hooks that can be processed
type IncomingRequestHooks struct {
	persistenceOptions PersistenceOptions
21 22 23 24 25 26 27 28 29 30 31 32 33 34
	pubSub             *pubsub.PubSub
}

type internalRequestHookEvent struct {
	p       peer.ID
	request graphsync.RequestData
	rha     *requestHookActions
}

func requestHookDispatcher(event pubsub.Event, subscriberFn pubsub.SubscriberFn) error {
	ie := event.(internalRequestHookEvent)
	hook := subscriberFn.(graphsync.OnIncomingRequestHook)
	hook(ie.p, ie.request, ie.rha)
	return ie.rha.err
35 36
}

Hannah Howard's avatar
Hannah Howard committed
37 38
// NewRequestHooks returns a new list of incoming request hooks
func NewRequestHooks(persistenceOptions PersistenceOptions) *IncomingRequestHooks {
39 40
	return &IncomingRequestHooks{
		persistenceOptions: persistenceOptions,
41
		pubSub:             pubsub.New(requestHookDispatcher),
42 43 44 45 46
	}
}

// Register registers an extension to process new incoming requests
func (irh *IncomingRequestHooks) Register(hook graphsync.OnIncomingRequestHook) graphsync.UnregisterHookFunc {
47
	return graphsync.UnregisterHookFunc(irh.pubSub.Subscribe(hook))
48 49
}

Hannah Howard's avatar
Hannah Howard committed
50 51
// RequestResult is the outcome of running requesthooks
type RequestResult struct {
52 53
	IsValidated   bool
	CustomLoader  ipld.Loader
Hannah Howard's avatar
Hannah Howard committed
54
	CustomChooser traversal.LinkTargetNodeStyleChooser
55 56 57 58 59
	Err           error
	Extensions    []graphsync.ExtensionData
}

// ProcessRequestHooks runs request hooks against an incoming request
Hannah Howard's avatar
Hannah Howard committed
60 61
func (irh *IncomingRequestHooks) ProcessRequestHooks(p peer.ID, request graphsync.RequestData) RequestResult {
	ha := &requestHookActions{
62 63
		persistenceOptions: irh.persistenceOptions,
	}
64
	_ = irh.pubSub.Publish(internalRequestHookEvent{p, request, ha})
65 66 67
	return ha.result()
}

Hannah Howard's avatar
Hannah Howard committed
68
type requestHookActions struct {
69 70 71 72
	persistenceOptions PersistenceOptions
	isValidated        bool
	err                error
	loader             ipld.Loader
Hannah Howard's avatar
Hannah Howard committed
73
	chooser            traversal.LinkTargetNodeStyleChooser
74 75 76
	extensions         []graphsync.ExtensionData
}

Hannah Howard's avatar
Hannah Howard committed
77 78
func (ha *requestHookActions) result() RequestResult {
	return RequestResult{
79 80 81 82 83 84 85 86
		IsValidated:   ha.isValidated,
		CustomLoader:  ha.loader,
		CustomChooser: ha.chooser,
		Err:           ha.err,
		Extensions:    ha.extensions,
	}
}

Hannah Howard's avatar
Hannah Howard committed
87
func (ha *requestHookActions) SendExtensionData(ext graphsync.ExtensionData) {
88 89 90
	ha.extensions = append(ha.extensions, ext)
}

Hannah Howard's avatar
Hannah Howard committed
91
func (ha *requestHookActions) TerminateWithError(err error) {
92 93 94
	ha.err = err
}

Hannah Howard's avatar
Hannah Howard committed
95
func (ha *requestHookActions) ValidateRequest() {
96 97 98
	ha.isValidated = true
}

Hannah Howard's avatar
Hannah Howard committed
99
func (ha *requestHookActions) UsePersistenceOption(name string) {
100 101 102 103 104 105 106 107
	loader, ok := ha.persistenceOptions.GetLoader(name)
	if !ok {
		ha.TerminateWithError(errors.New("unknown loader option"))
		return
	}
	ha.loader = loader
}

Hannah Howard's avatar
Hannah Howard committed
108
func (ha *requestHookActions) UseLinkTargetNodeStyleChooser(chooser traversal.LinkTargetNodeStyleChooser) {
109 110
	ha.chooser = chooser
}