package main import ( "context" "log" "sort" "time" ) func (this *Application) sync(ctx context.Context) (bool, error) { // List repositories on Gitea repos, err := this.repos(ctx) if err != nil { return false, err } // Compare this list of repositories to our existing one // If the repository is new, or if it's update-time has changed since we last // saw it, then re-refresh its real git commit timestamps // Otherwise copy them from the previous version this.reposMut.RLock() // readonly anyChanges := false if len(repos) != len(this.reposCache) { anyChanges = true } for i, rr := range repos { if idx, ok := this.reposAlphabeticalOrder[rr.Name]; ok && this.reposCache[idx].GiteaUpdated == rr.GiteaUpdated { // Already exists in cache with same Gitea update time // Copy timestamps repos[i] = this.reposCache[idx] } else { // New repo, or Gitea has updated timestamp anyChanges = true // Refresh timestamps this.populateCommitInfo(ctx, &rr) // Refresh topics if t, err := this.topicsForRepo(ctx, rr.Name); err == nil { rr.topics = t } // Save repos[i] = rr } } this.reposMut.RUnlock() // if !anyChanges { return false, nil // nothing to do } // We have a final updated repos array // Sort repos once alphabetically, to get alphabetical indexes... sort.Slice(repos, func(i, j int) bool { return repos[i].Name < repos[j].Name }) alphabeticalOrderIndexes := make(map[string]int, len(repos)) for idx, repo := range repos { alphabeticalOrderIndexes[repo.Name] = idx } // But then make sure the final sort is by most-recently-created sort.Slice(repos, func(i, j int) bool { return repos[i].GiteaCreated.After(repos[j].GiteaCreated) }) // Commit our changes for the other threads to look at this.reposMut.Lock() this.reposCache = repos this.reposAlphabeticalOrder = alphabeticalOrderIndexes this.reposMut.Unlock() // Done return true, nil } func (this *Application) syncWorker(ctx context.Context) { t := time.NewTicker(30 * time.Minute) defer t.Stop() for { anyChanges, err := this.sync(ctx) if err != nil { // log and continue log.Printf("Refreshing repositories: %s", err.Error()) } if anyChanges { log.Printf("Repositories updated") } select { case <-t.C: continue case <-ctx.Done(): return } } }