@@ -56,6 +56,8 @@ type EventManager struct {
56
56
filesystem Filesystem
57
57
notificationManager * NotificationManager
58
58
defaultDownloadDir string
59
+
60
+ events chan []Event
59
61
}
60
62
61
63
// NewEventManager loads transfer state from storage, or creates empty state if loading fails.
@@ -66,14 +68,50 @@ func NewEventManager(
66
68
filesystem Filesystem ,
67
69
defaultDownloadDir string ,
68
70
) * EventManager {
69
- return & EventManager {
71
+ em := & EventManager {
70
72
isProd : isProd ,
71
73
liveTransfers : map [string ]* LiveTransfer {},
72
74
transferSubscriptions : map [string ]chan TransferProgressInfo {},
73
75
meshClient : meshClient ,
74
76
osInfo : osInfo ,
75
77
filesystem : filesystem ,
76
78
defaultDownloadDir : defaultDownloadDir ,
79
+ events : make (chan []Event , 32 ),
80
+ }
81
+ go em .process ()
82
+
83
+ return em
84
+ }
85
+
86
+ func (em * EventManager ) process () {
87
+ fn := func (ev []Event ) {
88
+ em .mutex .Lock ()
89
+ defer em .mutex .Unlock ()
90
+ for _ , e := range ev {
91
+ em .handleEvent (e )
92
+ }
93
+ }
94
+
95
+ for {
96
+ events , ok := <- em .events
97
+ if ! ok {
98
+ log .Println (internal .WarningPrefix , "events channel closed" )
99
+ return
100
+ }
101
+ fn (events )
102
+ }
103
+ }
104
+
105
+ // Event sends an event to the event manager in an asynchronous manner
106
+ //
107
+ // This function should return immediately,
108
+ // unless the Events channel is full, in which case it will block until there is space
109
+ func (em * EventManager ) Event (event ... Event ) {
110
+ select {
111
+ case em .events <- event :
112
+ default :
113
+ log .Println (internal .WarningPrefix , "async events channel is full. Event() will block until there is space" )
114
+ em .events <- event
77
115
}
78
116
}
79
117
@@ -126,11 +164,7 @@ func (em *EventManager) DisableNotifications() error {
126
164
return nil
127
165
}
128
166
129
- // OnEvent processes events and handles live transfer state.
130
- func (em * EventManager ) OnEvent (event Event ) {
131
- em .mutex .Lock ()
132
- defer em .mutex .Unlock ()
133
-
167
+ func (em * EventManager ) handleEvent (event Event ) {
134
168
if ! em .isProd {
135
169
log .Printf (internal .InfoPrefix + " DROP EVENT: %s\n " , EventToString (event ))
136
170
}
@@ -206,6 +240,29 @@ func (em *EventManager) handleRequestReceivedEvent(event EventKindRequestReceive
206
240
}
207
241
}
208
242
243
+ func (em * EventManager ) withProgressCh (transferID string , fn func (ch chan TransferProgressInfo )) {
244
+ if ch , ok := em .transferSubscriptions [transferID ]; ok {
245
+ fn (ch )
246
+ }
247
+ }
248
+
249
+ func (em * EventManager ) reportProgress (transferID string , status pb.Status , transferred uint32 ) {
250
+ em .withProgressCh (transferID , func (ch chan TransferProgressInfo ) {
251
+ progress := TransferProgressInfo {
252
+ TransferID : transferID ,
253
+ Transferred : transferred ,
254
+ Status : status ,
255
+ }
256
+ select {
257
+ case ch <- progress :
258
+ default :
259
+ log .Println (internal .WarningPrefix , " progress channel is full. removing oldest item and sending" )
260
+ <- ch
261
+ ch <- progress
262
+ }
263
+ })
264
+ }
265
+
209
266
func (em * EventManager ) handleFileProgressEvent (event EventKindFileProgress ) {
210
267
transfer , err := em .getLiveTransfer (event .TransferId )
211
268
if err != nil {
@@ -223,17 +280,11 @@ func (em *EventManager) handleFileProgressEvent(event EventKindFileProgress) {
223
280
transfer .TotalTransferred += event .Transferred - file .Transferred // add only delta
224
281
file .Transferred = event .Transferred
225
282
226
- if progressCh , ok := em .transferSubscriptions [transfer .ID ]; ok {
227
- var progressPercent uint32
228
- if transfer .TotalSize > 0 { // transfer progress percentage should be reported to subscriber
229
- progressPercent = uint32 (float64 (transfer .TotalTransferred ) / float64 (transfer .TotalSize ) * 100 )
230
- }
231
- progressCh <- TransferProgressInfo {
232
- TransferID : event .TransferId ,
233
- Transferred : progressPercent ,
234
- Status : pb .Status_ONGOING ,
235
- }
283
+ var progressPercent uint32
284
+ if transfer .TotalSize > 0 { // transfer progress percentage should be reported to subscriber
285
+ progressPercent = uint32 (float64 (transfer .TotalTransferred ) / float64 (transfer .TotalSize ) * 100 )
236
286
}
287
+ em .reportProgress (transfer .ID , pb .Status_ONGOING , progressPercent )
237
288
}
238
289
239
290
func (em * EventManager ) handleFileDownloadedEvent (event EventKindFileDownloaded ) {
@@ -367,16 +418,13 @@ func (em *EventManager) handleTransferFinalizedEvent(event EventKindTransferFina
367
418
}
368
419
369
420
func (em * EventManager ) finalizeTransfer (transfer * LiveTransfer , status pb.Status ) {
370
- if progressCh , ok := em .transferSubscriptions [transfer .ID ]; ok {
371
- progressCh <- TransferProgressInfo {
372
- TransferID : transfer .ID ,
373
- Status : status ,
374
- }
421
+ em .reportProgress (transfer .ID , status , 0 )
422
+ em .withProgressCh (transfer .ID , func (ch chan TransferProgressInfo ) {
375
423
// unsubscribe finished transfer
376
- close (progressCh )
377
- delete (em .transferSubscriptions , transfer .ID )
378
- }
424
+ close (ch )
425
+ })
379
426
427
+ delete (em .transferSubscriptions , transfer .ID )
380
428
delete (em .liveTransfers , transfer .ID )
381
429
}
382
430
@@ -601,7 +649,7 @@ func (em *EventManager) Subscribe(id string) <-chan TransferProgressInfo {
601
649
em .mutex .Lock ()
602
650
defer em .mutex .Unlock ()
603
651
604
- em .transferSubscriptions [id ] = make (chan TransferProgressInfo )
652
+ em .transferSubscriptions [id ] = make (chan TransferProgressInfo , 32 ) // use buffered channels, because we don't want to block the event processing
605
653
606
654
return em .transferSubscriptions [id ]
607
655
}
0 commit comments