requesthook.go 3.34 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
	"github.com/ipld/go-ipld-prime"
	"github.com/ipld/go-ipld-prime/traversal"
	peer "github.com/libp2p/go-libp2p-core/peer"
Hannah Howard's avatar
Hannah Howard committed
10 11

	"github.com/ipfs/go-graphsync"
12 13 14 15
)

// PersistenceOptions is an interface for getting loaders by name
type PersistenceOptions interface {
Hannah Howard's avatar
Hannah Howard committed
16
	GetLinkSystem(name string) (ipld.LinkSystem, bool)
17 18 19 20 21
}

// IncomingRequestHooks is a set of incoming request hooks that can be processed
type IncomingRequestHooks struct {
	persistenceOptions PersistenceOptions
22 23 24 25 26 27 28 29 30 31 32 33 34 35
	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
36 37
}

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

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

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

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

Hannah Howard's avatar
Hannah Howard committed
70
type requestHookActions struct {
71 72
	persistenceOptions PersistenceOptions
	isValidated        bool
73
	isPaused           bool
74
	err                error
Hannah Howard's avatar
Hannah Howard committed
75
	linkSystem         ipld.LinkSystem
Eric Myhre's avatar
Eric Myhre committed
76
	chooser            traversal.LinkTargetNodePrototypeChooser
77 78 79
	extensions         []graphsync.ExtensionData
}

Hannah Howard's avatar
Hannah Howard committed
80 81
func (ha *requestHookActions) result() RequestResult {
	return RequestResult{
Hannah Howard's avatar
Hannah Howard committed
82 83 84 85 86 87
		IsValidated:      ha.isValidated,
		IsPaused:         ha.isPaused,
		CustomLinkSystem: ha.linkSystem,
		CustomChooser:    ha.chooser,
		Err:              ha.err,
		Extensions:       ha.extensions,
88 89 90
	}
}

Hannah Howard's avatar
Hannah Howard committed
91
func (ha *requestHookActions) SendExtensionData(ext graphsync.ExtensionData) {
92 93 94
	ha.extensions = append(ha.extensions, ext)
}

Hannah Howard's avatar
Hannah Howard committed
95
func (ha *requestHookActions) TerminateWithError(err error) {
96 97 98
	ha.err = err
}

Hannah Howard's avatar
Hannah Howard committed
99
func (ha *requestHookActions) ValidateRequest() {
100 101 102
	ha.isValidated = true
}

Hannah Howard's avatar
Hannah Howard committed
103
func (ha *requestHookActions) UsePersistenceOption(name string) {
Hannah Howard's avatar
Hannah Howard committed
104
	linkSystem, ok := ha.persistenceOptions.GetLinkSystem(name)
105 106 107 108
	if !ok {
		ha.TerminateWithError(errors.New("unknown loader option"))
		return
	}
Hannah Howard's avatar
Hannah Howard committed
109
	ha.linkSystem = linkSystem
110 111
}

Eric Myhre's avatar
Eric Myhre committed
112
func (ha *requestHookActions) UseLinkTargetNodePrototypeChooser(chooser traversal.LinkTargetNodePrototypeChooser) {
113 114
	ha.chooser = chooser
}
115 116 117 118

func (ha *requestHookActions) PauseResponse() {
	ha.isPaused = true
}