github.com/kaleido-io/firefly@v0.0.0-20210622132723-8b4b6aacb971/internal/events/event_manager.go (about)

     1  // Copyright © 2021 Kaleido, Inc.
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  //
     5  // Licensed under the Apache License, Version 2.0 (the "License");
     6  // you may not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //     http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  
    17  package events
    18  
    19  import (
    20  	"context"
    21  	"strconv"
    22  
    23  	"github.com/kaleido-io/firefly/internal/broadcast"
    24  	"github.com/kaleido-io/firefly/internal/config"
    25  	"github.com/kaleido-io/firefly/internal/data"
    26  	"github.com/kaleido-io/firefly/internal/i18n"
    27  	"github.com/kaleido-io/firefly/internal/log"
    28  	"github.com/kaleido-io/firefly/internal/privatemessaging"
    29  	"github.com/kaleido-io/firefly/internal/retry"
    30  	"github.com/kaleido-io/firefly/pkg/blockchain"
    31  	"github.com/kaleido-io/firefly/pkg/database"
    32  	"github.com/kaleido-io/firefly/pkg/dataexchange"
    33  	"github.com/kaleido-io/firefly/pkg/fftypes"
    34  	"github.com/kaleido-io/firefly/pkg/identity"
    35  	"github.com/kaleido-io/firefly/pkg/publicstorage"
    36  )
    37  
    38  type EventManager interface {
    39  	NewPins() chan<- int64
    40  	NewEvents() chan<- int64
    41  	NewSubscriptions() chan<- *fftypes.UUID
    42  	DeletedSubscriptions() chan<- *fftypes.UUID
    43  	DeleteDurableSubscription(ctx context.Context, subDef *fftypes.Subscription) (err error)
    44  	CreateDurableSubscription(ctx context.Context, subDef *fftypes.Subscription) (err error)
    45  	Start() error
    46  	WaitStop()
    47  
    48  	// Bound blockchain callbacks
    49  	TxSubmissionUpdate(bi blockchain.Plugin, txTrackingID string, txState blockchain.TransactionStatus, protocolTxID, errorMessage string, additionalInfo fftypes.JSONObject) error
    50  	BatchPinComplete(bi blockchain.Plugin, batch *blockchain.BatchPin, signingIdentity string, protocolTxID string, additionalInfo fftypes.JSONObject) error
    51  
    52  	// Bound dataexchange callbacks
    53  	TransferResult(dx dataexchange.Plugin, trackingID string, status fftypes.OpStatus, info string, additionalInfo fftypes.JSONObject)
    54  	BLOBReceived(dx dataexchange.Plugin, peerID string, ns string, id fftypes.UUID)
    55  	MessageReceived(dx dataexchange.Plugin, peerID string, data []byte)
    56  }
    57  
    58  type eventManager struct {
    59  	ctx                  context.Context
    60  	publicstorage        publicstorage.Plugin
    61  	database             database.Plugin
    62  	identity             identity.Plugin
    63  	broadcast            broadcast.Manager
    64  	messaging            privatemessaging.Manager
    65  	data                 data.Manager
    66  	subManager           *subscriptionManager
    67  	retry                retry.Retry
    68  	aggregator           *aggregator
    69  	newEventNotifier     *eventNotifier
    70  	newPinNotifier       *eventNotifier
    71  	opCorrelationRetries int
    72  	defaultTransport     string
    73  }
    74  
    75  func NewEventManager(ctx context.Context, pi publicstorage.Plugin, di database.Plugin, ii identity.Plugin, bm broadcast.Manager, pm privatemessaging.Manager, dm data.Manager) (EventManager, error) {
    76  	if pi == nil || di == nil || ii == nil || dm == nil {
    77  		return nil, i18n.NewError(ctx, i18n.MsgInitializationNilDepError)
    78  	}
    79  	newPinNotifier := newEventNotifier(ctx, "pins")
    80  	newEventNotifier := newEventNotifier(ctx, "events")
    81  	em := &eventManager{
    82  		ctx:           log.WithLogField(ctx, "role", "event-manager"),
    83  		publicstorage: pi,
    84  		database:      di,
    85  		identity:      ii,
    86  		broadcast:     bm,
    87  		messaging:     pm,
    88  		data:          dm,
    89  		retry: retry.Retry{
    90  			InitialDelay: config.GetDuration(config.EventAggregatorRetryInitDelay),
    91  			MaximumDelay: config.GetDuration(config.EventAggregatorRetryMaxDelay),
    92  			Factor:       config.GetFloat64(config.EventAggregatorRetryFactor),
    93  		},
    94  		defaultTransport:     config.GetString(config.EventTransportsDefault),
    95  		opCorrelationRetries: config.GetInt(config.EventAggregatorOpCorrelationRetries),
    96  		newEventNotifier:     newEventNotifier,
    97  		newPinNotifier:       newPinNotifier,
    98  		aggregator:           newAggregator(ctx, di, bm, pm, dm, newPinNotifier),
    99  	}
   100  
   101  	var err error
   102  	if em.subManager, err = newSubscriptionManager(ctx, di, newEventNotifier); err != nil {
   103  		return nil, err
   104  	}
   105  
   106  	return em, nil
   107  }
   108  
   109  func (em *eventManager) Start() (err error) {
   110  	err = em.subManager.start()
   111  	if err == nil {
   112  		err = em.aggregator.start()
   113  	}
   114  	return err
   115  }
   116  
   117  func (em *eventManager) NewEvents() chan<- int64 {
   118  	return em.newEventNotifier.newEvents
   119  }
   120  
   121  func (em *eventManager) NewPins() chan<- int64 {
   122  	return em.newPinNotifier.newEvents
   123  }
   124  
   125  func (em *eventManager) NewSubscriptions() chan<- *fftypes.UUID {
   126  	return em.subManager.newSubscriptions
   127  }
   128  
   129  func (em *eventManager) DeletedSubscriptions() chan<- *fftypes.UUID {
   130  	return em.subManager.deletedSubscriptions
   131  }
   132  
   133  func (em *eventManager) WaitStop() {
   134  	em.subManager.close()
   135  	<-em.aggregator.eventPoller.closed
   136  }
   137  
   138  func (em *eventManager) CreateDurableSubscription(ctx context.Context, subDef *fftypes.Subscription) (err error) {
   139  	if subDef.Namespace == "" || subDef.Name == "" || subDef.ID == nil {
   140  		return i18n.NewError(ctx, i18n.MsgInvalidSubscription)
   141  	}
   142  
   143  	if subDef.Transport == "" {
   144  		subDef.Transport = em.defaultTransport
   145  	}
   146  	// Check it can be parsed before inserting (the submanager will check again when processing the creation, so we discard the result)
   147  	if _, err = em.subManager.parseSubscriptionDef(ctx, subDef); err != nil {
   148  		return err
   149  	}
   150  
   151  	// Do a check first for existence, to give a nice 409 if we find one
   152  	existing, _ := em.database.GetSubscriptionByName(ctx, subDef.Namespace, subDef.Name)
   153  	if existing != nil {
   154  		return i18n.NewError(ctx, i18n.MsgAlreadyExists, "subscription", subDef.Namespace, subDef.Name)
   155  	}
   156  
   157  	// We lock in the starting sequence at creation time, rather than when the first dispatcher
   158  	// starts, as that's a more obvious behavior for users
   159  	sequence, err := calcFirstOffset(ctx, em.database, subDef.Options.FirstEvent)
   160  	if err != nil {
   161  		return err
   162  	}
   163  	lockedInFirstEvent := fftypes.SubOptsFirstEvent(strconv.FormatInt(sequence, 10))
   164  	subDef.Options.FirstEvent = &lockedInFirstEvent
   165  
   166  	// The event in the database for the creation of the susbscription, will asynchronously update the submanager
   167  	return em.database.UpsertSubscription(ctx, subDef, false)
   168  }
   169  
   170  func (em *eventManager) DeleteDurableSubscription(ctx context.Context, subDef *fftypes.Subscription) (err error) {
   171  	// The event in the database for the deletion of the susbscription, will asynchronously update the submanager
   172  	return em.database.DeleteSubscriptionByID(ctx, subDef.ID)
   173  }