github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/core/state/state.go (about)

     1  /*
     2   * Copyright (C) 2019 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package state
    19  
    20  import (
    21  	"math/big"
    22  	"sync"
    23  	"time"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/jinzhu/copier"
    27  	"github.com/rs/zerolog/log"
    28  
    29  	"github.com/mysteriumnetwork/node/consumer/bandwidth"
    30  	"github.com/mysteriumnetwork/node/consumer/session"
    31  	"github.com/mysteriumnetwork/node/core/connection/connectionstate"
    32  	"github.com/mysteriumnetwork/node/core/discovery/proposal"
    33  	"github.com/mysteriumnetwork/node/core/service"
    34  	"github.com/mysteriumnetwork/node/core/service/servicestate"
    35  	stateEvent "github.com/mysteriumnetwork/node/core/state/event"
    36  	"github.com/mysteriumnetwork/node/eventbus"
    37  	"github.com/mysteriumnetwork/node/identity"
    38  	"github.com/mysteriumnetwork/node/identity/registry"
    39  	"github.com/mysteriumnetwork/node/market"
    40  	nodeSession "github.com/mysteriumnetwork/node/session"
    41  	sessionEvent "github.com/mysteriumnetwork/node/session/event"
    42  	"github.com/mysteriumnetwork/node/session/pingpong"
    43  	pingpongEvent "github.com/mysteriumnetwork/node/session/pingpong/event"
    44  	"github.com/mysteriumnetwork/node/tequilapi/contract"
    45  )
    46  
    47  // DefaultDebounceDuration is the default time interval suggested for debouncing
    48  const DefaultDebounceDuration = time.Millisecond * 200
    49  
    50  type publisher interface {
    51  	Publish(topic string, data interface{})
    52  }
    53  
    54  type serviceLister interface {
    55  	List(includeAll bool) []*service.Instance
    56  }
    57  
    58  type identityProvider interface {
    59  	GetIdentities() []identity.Identity
    60  }
    61  
    62  type channelAddressCalculator interface {
    63  	GetActiveChannelAddress(chainID int64, id common.Address) (common.Address, error)
    64  	GetActiveHermes(chainID int64) (common.Address, error)
    65  }
    66  
    67  type balanceProvider interface {
    68  	GetBalance(chainID int64, id identity.Identity) *big.Int
    69  }
    70  
    71  type earningsProvider interface {
    72  	List(chainID int64) []pingpong.HermesChannel
    73  	GetEarningsDetailed(chainID int64, id identity.Identity) *pingpongEvent.EarningsDetailed
    74  }
    75  
    76  // Keeper keeps track of state through eventual consistency.
    77  // This should become the de-facto place to get your info about node.
    78  type Keeper struct {
    79  	state *stateEvent.State
    80  	lock  sync.RWMutex
    81  	deps  KeeperDeps
    82  
    83  	// provider
    84  	consumeServiceStateEvent             func(e interface{})
    85  	consumeServiceSessionStatisticsEvent func(e interface{})
    86  	consumeServiceSessionEarningsEvent   func(e interface{})
    87  	consumeNATStatusUpdateEvent          func(e interface{})
    88  	// consumer
    89  	consumeConnectionStatisticsEvent func(interface{})
    90  	consumeConnectionThroughputEvent func(interface{})
    91  	consumeConnectionSpendingEvent   func(interface{})
    92  
    93  	announceStateChanges func(e interface{})
    94  }
    95  
    96  // KeeperDeps to construct the state.Keeper.
    97  type KeeperDeps struct {
    98  	Publisher                 publisher
    99  	ServiceLister             serviceLister
   100  	IdentityProvider          identityProvider
   101  	IdentityRegistry          registry.IdentityRegistry
   102  	IdentityChannelCalculator channelAddressCalculator
   103  	BalanceProvider           balanceProvider
   104  	EarningsProvider          earningsProvider
   105  	ChainID                   int64
   106  	ProposalPricer            proposalPricer
   107  }
   108  
   109  type proposalPricer interface {
   110  	EnrichProposalWithPrice(in market.ServiceProposal) (proposal.PricedServiceProposal, error)
   111  }
   112  
   113  // NewKeeper returns a new instance of the keeper.
   114  func NewKeeper(deps KeeperDeps, debounceDuration time.Duration) *Keeper {
   115  	k := &Keeper{
   116  		state: &stateEvent.State{
   117  			Sessions:    make([]session.History, 0),
   118  			Connections: make(map[string]stateEvent.Connection),
   119  		},
   120  		deps: deps,
   121  	}
   122  	k.state.Identities = k.fetchIdentities()
   123  	k.state.ProviderChannels = k.deps.EarningsProvider.List(deps.ChainID)
   124  
   125  	// provider
   126  	k.consumeServiceStateEvent = debounce(k.updateServiceState, debounceDuration)
   127  	k.consumeServiceSessionStatisticsEvent = debounce(k.updateSessionStats, debounceDuration)
   128  	k.consumeServiceSessionEarningsEvent = debounce(k.updateSessionEarnings, debounceDuration)
   129  
   130  	// consumer
   131  	k.consumeConnectionStatisticsEvent = debounce(k.updateConnectionStats, debounceDuration)
   132  	k.consumeConnectionThroughputEvent = debounce(k.updateConnectionThroughput, debounceDuration)
   133  	k.consumeConnectionSpendingEvent = debounce(k.updateConnectionSpending, debounceDuration)
   134  	k.announceStateChanges = debounce(k.announceState, debounceDuration)
   135  
   136  	return k
   137  }
   138  
   139  func (k *Keeper) fetchIdentities() []stateEvent.Identity {
   140  	ids := k.deps.IdentityProvider.GetIdentities()
   141  	identities := make([]stateEvent.Identity, len(ids))
   142  	for idx, id := range ids {
   143  		status, err := k.deps.IdentityRegistry.GetRegistrationStatus(k.deps.ChainID, id)
   144  		if err != nil {
   145  			log.Warn().Err(err).Msgf("Could not get registration status for %s", id.Address)
   146  			status = registry.Unknown
   147  		}
   148  		hermesID, err := k.deps.IdentityChannelCalculator.GetActiveHermes(k.deps.ChainID)
   149  		if err != nil {
   150  			log.Warn().Err(err).Msgf("Could not retrieve hermesID for %s", id.Address)
   151  		}
   152  		channelAddress, err := k.deps.IdentityChannelCalculator.GetActiveChannelAddress(k.deps.ChainID, id.ToCommonAddress())
   153  		if err != nil {
   154  			log.Warn().Err(err).Msgf("Could not calculate channel address for %s", id.Address)
   155  		}
   156  		earnings := k.deps.EarningsProvider.GetEarningsDetailed(k.deps.ChainID, id)
   157  		balance := k.deps.BalanceProvider.GetBalance(k.deps.ChainID, id)
   158  
   159  		stateIdentity := stateEvent.Identity{
   160  			Address:            id.Address,
   161  			RegistrationStatus: status,
   162  			ChannelAddress:     channelAddress,
   163  			Balance:            balance,
   164  			Earnings:           earnings.Total.UnsettledBalance,
   165  			EarningsTotal:      earnings.Total.LifetimeBalance,
   166  			HermesID:           hermesID,
   167  			EarningsPerHermes:  earnings.PerHermes,
   168  		}
   169  		identities[idx] = stateIdentity
   170  	}
   171  	return identities
   172  }
   173  
   174  // Subscribe subscribes to the event bus.
   175  func (k *Keeper) Subscribe(bus eventbus.Subscriber) error {
   176  	if err := bus.SubscribeAsync(servicestate.AppTopicServiceStatus, k.consumeServiceStateEvent); err != nil {
   177  		return err
   178  	}
   179  	if err := bus.SubscribeAsync(sessionEvent.AppTopicSession, k.consumeServiceSessionEvent); err != nil {
   180  		return err
   181  	}
   182  	if err := bus.SubscribeAsync(sessionEvent.AppTopicDataTransferred, k.consumeServiceSessionStatisticsEvent); err != nil {
   183  		return err
   184  	}
   185  	if err := bus.SubscribeAsync(sessionEvent.AppTopicTokensEarned, k.consumeServiceSessionEarningsEvent); err != nil {
   186  		return err
   187  	}
   188  	if err := bus.SubscribeAsync(connectionstate.AppTopicConnectionState, k.consumeConnectionStateEvent); err != nil {
   189  		return err
   190  	}
   191  	if err := bus.SubscribeAsync(connectionstate.AppTopicConnectionStatistics, k.consumeConnectionStatisticsEvent); err != nil {
   192  		return err
   193  	}
   194  	if err := bus.SubscribeAsync(bandwidth.AppTopicConnectionThroughput, k.consumeConnectionThroughputEvent); err != nil {
   195  		return err
   196  	}
   197  	if err := bus.SubscribeAsync(pingpongEvent.AppTopicInvoicePaid, k.consumeConnectionSpendingEvent); err != nil {
   198  		return err
   199  	}
   200  	if err := bus.SubscribeAsync(identity.AppTopicIdentityCreated, k.consumeIdentityCreatedEvent); err != nil {
   201  		return err
   202  	}
   203  	if err := bus.SubscribeAsync(registry.AppTopicIdentityRegistration, k.consumeIdentityRegistrationEvent); err != nil {
   204  		return err
   205  	}
   206  	if err := bus.SubscribeAsync(pingpongEvent.AppTopicBalanceChanged, k.consumeBalanceChangedEvent); err != nil {
   207  		return err
   208  	}
   209  	if err := bus.SubscribeAsync(pingpongEvent.AppTopicEarningsChanged, k.consumeEarningsChangedEvent); err != nil {
   210  		return err
   211  	}
   212  	return nil
   213  }
   214  
   215  func (k *Keeper) announceState(_ interface{}) {
   216  	var state stateEvent.State
   217  	func() {
   218  		k.lock.RLock()
   219  		defer k.lock.RUnlock()
   220  		if err := copier.CopyWithOption(&state, *k.state, copier.Option{DeepCopy: true}); err != nil {
   221  			panic(err)
   222  		}
   223  	}()
   224  	k.deps.Publisher.Publish(stateEvent.AppTopicState, state)
   225  }
   226  
   227  func (k *Keeper) updateServiceState(_ interface{}) {
   228  	k.lock.Lock()
   229  	defer k.lock.Unlock()
   230  	k.updateServices()
   231  	go k.announceStateChanges(nil)
   232  }
   233  
   234  func (k *Keeper) updateServices() {
   235  	services := k.deps.ServiceLister.List(false)
   236  	result := make([]contract.ServiceInfoDTO, len(services))
   237  
   238  	i := 0
   239  	for _, v := range services {
   240  		// merge in the connection statistics
   241  		match, _ := k.getServiceByID(string(v.ID))
   242  
   243  		proposal := v.CopyProposal()
   244  		priced, err := k.deps.ProposalPricer.EnrichProposalWithPrice(proposal)
   245  		if err != nil {
   246  			log.Warn().Msgf("could not load price for proposal %v(%v)", proposal.ProviderID, proposal.ServiceType)
   247  		}
   248  
   249  		prop := contract.NewProposalDTO(priced)
   250  		if match.ConnectionStatistics == nil {
   251  			match.ConnectionStatistics = &contract.ServiceStatisticsDTO{}
   252  		}
   253  		result[i] = contract.ServiceInfoDTO{
   254  			ID:                   string(v.ID),
   255  			ProviderID:           v.ProviderID.Address,
   256  			Type:                 v.Type,
   257  			Options:              v.Options,
   258  			Status:               string(v.State()),
   259  			Proposal:             &prop,
   260  			ConnectionStatistics: match.ConnectionStatistics,
   261  		}
   262  		i++
   263  	}
   264  
   265  	k.state.Services = result
   266  }
   267  
   268  func (k *Keeper) getServiceByID(id string) (se contract.ServiceInfoDTO, found bool) {
   269  	for i := range k.state.Services {
   270  		if k.state.Services[i].ID == id {
   271  			se = k.state.Services[i]
   272  			found = true
   273  			return
   274  		}
   275  	}
   276  	return
   277  }
   278  
   279  // consumeServiceSessionEvent consumes the session change events
   280  func (k *Keeper) consumeServiceSessionEvent(e sessionEvent.AppEventSession) {
   281  	k.lock.Lock()
   282  	defer k.lock.Unlock()
   283  
   284  	switch e.Status {
   285  	case sessionEvent.CreatedStatus:
   286  		k.addSession(e)
   287  		k.incrementConnectCount(e.Service.ID, false)
   288  	case sessionEvent.RemovedStatus:
   289  		k.removeSession(e)
   290  	case sessionEvent.AcknowledgedStatus:
   291  		k.incrementConnectCount(e.Service.ID, true)
   292  	}
   293  
   294  	go k.announceStateChanges(nil)
   295  }
   296  
   297  func (k *Keeper) addSession(e sessionEvent.AppEventSession) {
   298  	k.state.Sessions = append(k.state.Sessions, session.History{
   299  		SessionID:       nodeSession.ID(e.Session.ID),
   300  		Direction:       session.DirectionProvided,
   301  		ConsumerID:      e.Session.ConsumerID,
   302  		HermesID:        e.Session.HermesID.Hex(),
   303  		ProviderID:      identity.FromAddress(e.Session.Proposal.ProviderID),
   304  		ServiceType:     e.Session.Proposal.ServiceType,
   305  		ConsumerCountry: e.Session.ConsumerLocation.Country,
   306  		ProviderCountry: e.Session.Proposal.Location.Country,
   307  		Started:         e.Session.StartedAt,
   308  		Status:          session.StatusNew,
   309  		Tokens:          big.NewInt(0),
   310  	})
   311  }
   312  
   313  func (k *Keeper) removeSession(e sessionEvent.AppEventSession) {
   314  	found := false
   315  	for i := range k.state.Sessions {
   316  		if string(k.state.Sessions[i].SessionID) == e.Session.ID {
   317  			k.state.Sessions = append(k.state.Sessions[:i], k.state.Sessions[i+1:]...)
   318  			found = true
   319  			break
   320  		}
   321  	}
   322  	if !found {
   323  		log.Warn().Msgf("Couldn't find a matching session for session remove: %s", e.Session.ID)
   324  	}
   325  }
   326  
   327  // updates the data transfer info on the session
   328  func (k *Keeper) updateSessionStats(e interface{}) {
   329  	k.lock.Lock()
   330  	defer k.lock.Unlock()
   331  
   332  	evt, ok := e.(sessionEvent.AppEventDataTransferred)
   333  	if !ok {
   334  		log.Warn().Msg("Received a wrong kind of event for session state update")
   335  		return
   336  	}
   337  
   338  	var session *session.History
   339  	for i := range k.state.Sessions {
   340  		if string(k.state.Sessions[i].SessionID) == evt.ID {
   341  			session = &k.state.Sessions[i]
   342  		}
   343  	}
   344  	if session == nil {
   345  		log.Warn().Msgf("Couldn't find a matching session for data transferred change: %+v", evt)
   346  		return
   347  	}
   348  
   349  	// From a server perspective, bytes up are the actual bytes the client downloaded(aka the bytes we pushed to the consumer)
   350  	// To lessen the confusion, I suggest having the bytes reversed on the session instance.
   351  	// This way, the session will show that it downloaded the bytes in a manner that is easier to comprehend.
   352  	session.DataReceived = evt.Up
   353  	session.DataSent = evt.Down
   354  	go k.announceStateChanges(nil)
   355  }
   356  
   357  // updates total tokens earned during the session.
   358  func (k *Keeper) updateSessionEarnings(e interface{}) {
   359  	k.lock.Lock()
   360  	defer k.lock.Unlock()
   361  
   362  	evt, ok := e.(sessionEvent.AppEventTokensEarned)
   363  	if !ok {
   364  		log.Warn().Msg("Received a wrong kind of event for connection state update")
   365  		return
   366  	}
   367  
   368  	var session *session.History
   369  	for i := range k.state.Sessions {
   370  		if string(k.state.Sessions[i].SessionID) == evt.SessionID {
   371  			session = &k.state.Sessions[i]
   372  		}
   373  	}
   374  	if session == nil {
   375  		log.Warn().Msgf("Couldn't find a matching session for earnings change: %s", evt.SessionID)
   376  		return
   377  	}
   378  
   379  	session.Tokens = evt.Total
   380  	go k.announceStateChanges(nil)
   381  }
   382  
   383  func (k *Keeper) consumeConnectionStateEvent(e interface{}) {
   384  	k.lock.Lock()
   385  	defer k.lock.Unlock()
   386  	evt, ok := e.(connectionstate.AppEventConnectionState)
   387  	if !ok {
   388  		log.Warn().Msg("Received a wrong kind of event for connection state update")
   389  		return
   390  	}
   391  
   392  	if evt.State == connectionstate.NotConnected {
   393  		delete(k.state.Connections, evt.UUID)
   394  	} else {
   395  		conn := k.state.Connections[evt.UUID]
   396  		conn.Session = evt.SessionInfo
   397  		k.state.Connections[evt.UUID] = conn
   398  
   399  		log.Info().Msgf("Session %s", conn.String())
   400  	}
   401  
   402  	go k.announceStateChanges(nil)
   403  }
   404  
   405  func (k *Keeper) updateConnectionStats(e interface{}) {
   406  	k.lock.Lock()
   407  	defer k.lock.Unlock()
   408  	evt, ok := e.(connectionstate.AppEventConnectionStatistics)
   409  	if !ok {
   410  		log.Warn().Msg("Received a wrong kind of event for connection state update")
   411  		return
   412  	}
   413  
   414  	conn := k.state.Connections[string(evt.UUID)]
   415  	conn.Statistics = evt.Stats
   416  	k.state.Connections[evt.UUID] = conn
   417  
   418  	go k.announceStateChanges(nil)
   419  }
   420  
   421  func (k *Keeper) updateConnectionThroughput(e interface{}) {
   422  	k.lock.Lock()
   423  	defer k.lock.Unlock()
   424  	evt, ok := e.(bandwidth.AppEventConnectionThroughput)
   425  	if !ok {
   426  		log.Warn().Msg("Received a wrong kind of event for connection state update")
   427  		return
   428  	}
   429  
   430  	conn := k.state.Connections[evt.UUID]
   431  	conn.Throughput = evt.Throughput
   432  	k.state.Connections[evt.UUID] = conn
   433  
   434  	go k.announceStateChanges(nil)
   435  }
   436  
   437  func (k *Keeper) updateConnectionSpending(e interface{}) {
   438  	k.lock.Lock()
   439  	defer k.lock.Unlock()
   440  	evt, ok := e.(pingpongEvent.AppEventInvoicePaid)
   441  	if !ok {
   442  		log.Warn().Msg("Received a wrong kind of event for connection state update")
   443  		return
   444  	}
   445  
   446  	conn := k.state.Connections[evt.UUID]
   447  	conn.Invoice = evt.Invoice
   448  	k.state.Connections[evt.UUID] = conn
   449  
   450  	log.Info().Msgf("Session %s", conn.String())
   451  
   452  	go k.announceStateChanges(nil)
   453  }
   454  
   455  func (k *Keeper) consumeBalanceChangedEvent(e interface{}) {
   456  	k.lock.Lock()
   457  	defer k.lock.Unlock()
   458  	evt, ok := e.(pingpongEvent.AppEventBalanceChanged)
   459  	if !ok {
   460  		log.Warn().Msg("Received a wrong kind of event for balance change")
   461  		return
   462  	}
   463  	var id *stateEvent.Identity
   464  	for i := range k.state.Identities {
   465  		if k.state.Identities[i].Address == evt.Identity.Address {
   466  			id = &k.state.Identities[i]
   467  			break
   468  		}
   469  	}
   470  	if id == nil {
   471  		log.Warn().Msgf("Couldn't find a matching identity for balance change: %s", evt.Identity.Address)
   472  		return
   473  	}
   474  	id.Balance = evt.Current
   475  	go k.announceStateChanges(nil)
   476  }
   477  
   478  func (k *Keeper) consumeEarningsChangedEvent(e interface{}) {
   479  	k.lock.Lock()
   480  	defer k.lock.Unlock()
   481  	evt, ok := e.(pingpongEvent.AppEventEarningsChanged)
   482  	if !ok {
   483  		log.Warn().Msg("Received a wrong kind of event for earnings change")
   484  		return
   485  	}
   486  
   487  	k.state.ProviderChannels = k.deps.EarningsProvider.List(k.deps.ChainID)
   488  
   489  	var id *stateEvent.Identity
   490  	for i := range k.state.Identities {
   491  		if k.state.Identities[i].Address == evt.Identity.Address {
   492  			id = &k.state.Identities[i]
   493  			break
   494  		}
   495  	}
   496  	if id == nil {
   497  		log.Warn().Msgf("Couldn't find a matching identity for earnings change: %s", evt.Identity.Address)
   498  		return
   499  	}
   500  
   501  	id.Earnings = evt.Current.Total.UnsettledBalance
   502  	id.EarningsTotal = evt.Current.Total.LifetimeBalance
   503  	id.EarningsPerHermes = evt.Current.PerHermes
   504  
   505  	go k.announceStateChanges(nil)
   506  }
   507  
   508  func (k *Keeper) consumeIdentityCreatedEvent(_ interface{}) {
   509  	k.lock.Lock()
   510  	defer k.lock.Unlock()
   511  	k.state.Identities = k.fetchIdentities()
   512  	go k.announceStateChanges(nil)
   513  }
   514  
   515  func (k *Keeper) consumeIdentityRegistrationEvent(e interface{}) {
   516  	k.lock.Lock()
   517  	defer k.lock.Unlock()
   518  	evt, ok := e.(registry.AppEventIdentityRegistration)
   519  	if !ok {
   520  		log.Warn().Msg("Received a wrong kind of event for identity registration")
   521  	}
   522  	var id *stateEvent.Identity
   523  	for i := range k.state.Identities {
   524  		if k.state.Identities[i].Address == evt.ID.Address {
   525  			id = &k.state.Identities[i]
   526  			break
   527  		}
   528  	}
   529  	if id == nil {
   530  		log.Warn().Msgf("Couldn't find a matching identity for balance change: %s", evt.ID.Address)
   531  		return
   532  	}
   533  	id.RegistrationStatus = evt.Status
   534  	go k.announceStateChanges(nil)
   535  }
   536  
   537  func (k *Keeper) incrementConnectCount(serviceID string, isSuccess bool) {
   538  	for i := range k.state.Services {
   539  		if k.state.Services[i].ID == serviceID {
   540  			if isSuccess {
   541  				k.state.Services[i].ConnectionStatistics.Successful++
   542  			} else {
   543  				k.state.Services[i].ConnectionStatistics.Attempted++
   544  			}
   545  			break
   546  		}
   547  	}
   548  }
   549  
   550  // GetState returns the current state
   551  func (k *Keeper) GetState() (res stateEvent.State) {
   552  	k.lock.RLock()
   553  	defer k.lock.RUnlock()
   554  
   555  	if err := copier.CopyWithOption(&res, *k.state, copier.Option{DeepCopy: true}); err != nil {
   556  		panic(err)
   557  	}
   558  	return
   559  }
   560  
   561  // GetConnection returns the connection state.
   562  func (k *Keeper) GetConnection(id string) (state stateEvent.Connection) {
   563  	k.lock.RLock()
   564  	defer k.lock.RUnlock()
   565  
   566  	for _, state := range k.state.Connections {
   567  		if len(id) == 0 || id == string(state.Session.SessionID) {
   568  			return state
   569  		}
   570  	}
   571  
   572  	state.Session.State = connectionstate.NotConnected
   573  
   574  	return state
   575  }
   576  
   577  // Debounce takes in the f and makes sure that it only gets called once if multiple calls are executed in the given interval d.
   578  // It returns the debounced instance of the function.
   579  func debounce(f func(interface{}), d time.Duration) func(interface{}) {
   580  	incoming := make(chan interface{})
   581  
   582  	go func() {
   583  		var e interface{}
   584  
   585  		t := time.NewTimer(d)
   586  		t.Stop()
   587  
   588  		for {
   589  			select {
   590  			case e = <-incoming:
   591  				t.Reset(d)
   592  			case <-t.C:
   593  				go f(e)
   594  			}
   595  		}
   596  	}()
   597  
   598  	return func(e interface{}) {
   599  		go func() { incoming <- e }()
   600  	}
   601  }