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 }