github.com/status-im/status-go@v1.1.0/services/ext/mailrequests.go (about)

     1  package ext
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/ethereum/go-ethereum/log"
     7  
     8  	"github.com/status-im/status-go/eth-node/types"
     9  	"github.com/status-im/status-go/services/ext/mailservers"
    10  )
    11  
    12  // EnvelopeState in local tracker
    13  type EnvelopeState int
    14  
    15  const (
    16  	// NotRegistered returned if asked hash wasn't registered in the tracker.
    17  	NotRegistered EnvelopeState = -1
    18  	// MailServerRequestSent is set when p2p request is sent to the mailserver
    19  	MailServerRequestSent
    20  )
    21  
    22  // MailRequestMonitor is responsible for monitoring history request to mailservers.
    23  type MailRequestMonitor struct {
    24  	eventSub mailservers.EnvelopeEventSubscriber
    25  	handler  EnvelopeEventsHandler
    26  
    27  	mu    sync.Mutex
    28  	cache map[types.Hash]EnvelopeState
    29  
    30  	requestsRegistry *RequestsRegistry
    31  
    32  	wg   sync.WaitGroup
    33  	quit chan struct{}
    34  }
    35  
    36  func NewMailRequestMonitor(eventSub mailservers.EnvelopeEventSubscriber, h EnvelopeEventsHandler, reg *RequestsRegistry) *MailRequestMonitor {
    37  	return &MailRequestMonitor{
    38  		eventSub:         eventSub,
    39  		handler:          h,
    40  		cache:            make(map[types.Hash]EnvelopeState),
    41  		requestsRegistry: reg,
    42  	}
    43  }
    44  
    45  // Start processing events.
    46  func (m *MailRequestMonitor) Start() {
    47  	m.quit = make(chan struct{})
    48  	m.wg.Add(1)
    49  	go func() {
    50  		m.handleEnvelopeEvents()
    51  		m.wg.Done()
    52  	}()
    53  }
    54  
    55  // Stop process events.
    56  func (m *MailRequestMonitor) Stop() {
    57  	close(m.quit)
    58  	m.wg.Wait()
    59  }
    60  
    61  func (m *MailRequestMonitor) GetState(hash types.Hash) EnvelopeState {
    62  	m.mu.Lock()
    63  	defer m.mu.Unlock()
    64  	state, exist := m.cache[hash]
    65  	if !exist {
    66  		return NotRegistered
    67  	}
    68  	return state
    69  }
    70  
    71  // handleEnvelopeEvents processes whisper envelope events
    72  func (m *MailRequestMonitor) handleEnvelopeEvents() {
    73  	events := make(chan types.EnvelopeEvent, 100) // must be buffered to prevent blocking whisper
    74  	sub := m.eventSub.SubscribeEnvelopeEvents(events)
    75  	defer sub.Unsubscribe()
    76  	for {
    77  		select {
    78  		case <-m.quit:
    79  			return
    80  		case event := <-events:
    81  			m.handleEvent(event)
    82  		}
    83  	}
    84  }
    85  
    86  // handleEvent based on type of the event either triggers
    87  // confirmation handler or removes hash from MailRequestMonitor
    88  func (m *MailRequestMonitor) handleEvent(event types.EnvelopeEvent) {
    89  	handlers := map[types.EventType]func(types.EnvelopeEvent){
    90  		types.EventMailServerRequestSent:      m.handleRequestSent,
    91  		types.EventMailServerRequestCompleted: m.handleEventMailServerRequestCompleted,
    92  		types.EventMailServerRequestExpired:   m.handleEventMailServerRequestExpired,
    93  	}
    94  
    95  	if handler, ok := handlers[event.Event]; ok {
    96  		handler(event)
    97  	}
    98  }
    99  
   100  func (m *MailRequestMonitor) handleRequestSent(event types.EnvelopeEvent) {
   101  	m.mu.Lock()
   102  	defer m.mu.Unlock()
   103  	m.cache[event.Hash] = MailServerRequestSent
   104  }
   105  
   106  func (m *MailRequestMonitor) handleEventMailServerRequestCompleted(event types.EnvelopeEvent) {
   107  	m.mu.Lock()
   108  	defer m.mu.Unlock()
   109  	m.requestsRegistry.Unregister(event.Hash)
   110  	state, ok := m.cache[event.Hash]
   111  	if !ok || state != MailServerRequestSent {
   112  		return
   113  	}
   114  	log.Debug("mailserver response received", "hash", event.Hash)
   115  	delete(m.cache, event.Hash)
   116  	if m.handler != nil {
   117  		if resp, ok := event.Data.(*types.MailServerResponse); ok {
   118  			m.handler.MailServerRequestCompleted(event.Hash, resp.LastEnvelopeHash, resp.Cursor, resp.Error)
   119  		}
   120  	}
   121  }
   122  
   123  func (m *MailRequestMonitor) handleEventMailServerRequestExpired(event types.EnvelopeEvent) {
   124  	m.mu.Lock()
   125  	defer m.mu.Unlock()
   126  	m.requestsRegistry.Unregister(event.Hash)
   127  	state, ok := m.cache[event.Hash]
   128  	if !ok || state != MailServerRequestSent {
   129  		return
   130  	}
   131  	log.Debug("mailserver response expired", "hash", event.Hash)
   132  	delete(m.cache, event.Hash)
   133  	if m.handler != nil {
   134  		m.handler.MailServerRequestExpired(event.Hash)
   135  	}
   136  }