code.gitea.io/gitea@v1.19.3/modules/eventsource/manager_run.go (about)

     1  // Copyright 2020 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package eventsource
     5  
     6  import (
     7  	"context"
     8  	"time"
     9  
    10  	activities_model "code.gitea.io/gitea/models/activities"
    11  	issues_model "code.gitea.io/gitea/models/issues"
    12  	"code.gitea.io/gitea/modules/graceful"
    13  	"code.gitea.io/gitea/modules/json"
    14  	"code.gitea.io/gitea/modules/log"
    15  	"code.gitea.io/gitea/modules/process"
    16  	"code.gitea.io/gitea/modules/setting"
    17  	"code.gitea.io/gitea/modules/timeutil"
    18  	"code.gitea.io/gitea/services/convert"
    19  )
    20  
    21  // Init starts this eventsource
    22  func (m *Manager) Init() {
    23  	if setting.UI.Notification.EventSourceUpdateTime <= 0 {
    24  		return
    25  	}
    26  	go graceful.GetManager().RunWithShutdownContext(m.Run)
    27  }
    28  
    29  // Run runs the manager within a provided context
    30  func (m *Manager) Run(ctx context.Context) {
    31  	ctx, _, finished := process.GetManager().AddTypedContext(ctx, "Service: EventSource", process.SystemProcessType, true)
    32  	defer finished()
    33  
    34  	then := timeutil.TimeStampNow().Add(-2)
    35  	timer := time.NewTicker(setting.UI.Notification.EventSourceUpdateTime)
    36  loop:
    37  	for {
    38  		select {
    39  		case <-ctx.Done():
    40  			timer.Stop()
    41  			break loop
    42  		case <-timer.C:
    43  			m.mutex.Lock()
    44  			connectionCount := len(m.messengers)
    45  			if connectionCount == 0 {
    46  				log.Trace("Event source has no listeners")
    47  				// empty the connection channel
    48  				select {
    49  				case <-m.connection:
    50  				default:
    51  				}
    52  			}
    53  			m.mutex.Unlock()
    54  			if connectionCount == 0 {
    55  				// No listeners so the source can be paused
    56  				log.Trace("Pausing the eventsource")
    57  				select {
    58  				case <-ctx.Done():
    59  					break loop
    60  				case <-m.connection:
    61  					log.Trace("Connection detected - restarting the eventsource")
    62  					// OK we're back so lets reset the timer and start again
    63  					// We won't change the "then" time because there could be concurrency issues
    64  					select {
    65  					case <-timer.C:
    66  					default:
    67  					}
    68  					continue
    69  				}
    70  			}
    71  
    72  			now := timeutil.TimeStampNow().Add(-2)
    73  
    74  			uidCounts, err := activities_model.GetUIDsAndNotificationCounts(then, now)
    75  			if err != nil {
    76  				log.Error("Unable to get UIDcounts: %v", err)
    77  			}
    78  			for _, uidCount := range uidCounts {
    79  				m.SendMessage(uidCount.UserID, &Event{
    80  					Name: "notification-count",
    81  					Data: uidCount,
    82  				})
    83  			}
    84  			then = now
    85  
    86  			if setting.Service.EnableTimetracking {
    87  				usersStopwatches, err := issues_model.GetUIDsAndStopwatch()
    88  				if err != nil {
    89  					log.Error("Unable to get GetUIDsAndStopwatch: %v", err)
    90  					return
    91  				}
    92  
    93  				for _, userStopwatches := range usersStopwatches {
    94  					apiSWs, err := convert.ToStopWatches(userStopwatches.StopWatches)
    95  					if err != nil {
    96  						if !issues_model.IsErrIssueNotExist(err) {
    97  							log.Error("Unable to APIFormat stopwatches: %v", err)
    98  						}
    99  						continue
   100  					}
   101  					dataBs, err := json.Marshal(apiSWs)
   102  					if err != nil {
   103  						log.Error("Unable to marshal stopwatches: %v", err)
   104  						continue
   105  					}
   106  					m.SendMessage(userStopwatches.UserID, &Event{
   107  						Name: "stopwatches",
   108  						Data: string(dataBs),
   109  					})
   110  				}
   111  			}
   112  		}
   113  	}
   114  	m.UnregisterAll()
   115  }