@@ -4,10 +4,11 @@ import (
44 "bytes"
55 "encoding/json"
66 "fmt"
7- "io/ioutil "
7+ "io"
88 "net/http"
99 "os"
1010 "strings"
11+ "sync"
1112 "time"
1213
1314 "cloud.google.com/go/profiler"
@@ -35,6 +36,7 @@ type StreamersRepo struct {
3536 language string
3637 game string
3738 client * helix.Client
39+ mutex * sync.Mutex
3840}
3941
4042// NoChangeNeededError is a struct for a custom error handler
@@ -50,6 +52,8 @@ func (e *NoChangeNeededError) Error() string {
5052
5153// gitPush pushes the repository to github and return and error.
5254func (s * StreamersRepo ) gitPush () error {
55+ s .mutex .Lock ()
56+ defer s .mutex .Unlock ()
5357 err := s .repo .Push (& git.PushOptions {
5458 RemoteName : "origin" ,
5559 Auth : s .auth ,
@@ -62,8 +66,11 @@ func (s *StreamersRepo) gitPush() error {
6266}
6367
6468// gitCommit makes a commit to the repository and returns an error.
69+ // The Below code has a race condition. Suggest a fix:
6570func (s * StreamersRepo ) gitCommit () error {
71+ s .mutex .Lock ()
6672 w , err := s .repo .Worktree ()
73+ s .mutex .Unlock ()
6774 if err != nil {
6875 return err
6976 }
@@ -73,26 +80,32 @@ func (s *StreamersRepo) gitCommit() error {
7380 } else {
7481 commitMessage = fmt .Sprintf ("☠️ %s has gone offline! [no ci]" , s .streamer )
7582 }
83+ s .mutex .Lock ()
7684 _ , err = w .Commit (commitMessage , & git.CommitOptions {
7785 Author : & object.Signature {
7886 Name : "🤖 STATUSS (Seriously Totally Automated Twitch Updating StreamStatus)" ,
7987 Email : "goproslowyo+statuss@users.noreply.github.com" ,
8088 When : time .Now (),
8189 },
8290 })
91+ s .mutex .Unlock ()
8392 if err != nil {
8493 return err
8594 }
95+ s .mutex .Lock ()
8696 commit , err := s .getHeadCommit ()
97+ s .mutex .Unlock ()
8798 if err != nil {
8899 return err
89100 }
90- log .Println ( commit )
101+ log .Printf ( "Current HEAD commit: %s \n " , commit )
91102 return nil
92103}
93104
94105// gitAdd adds the index file to the repository and returns an error.
95106func (s * StreamersRepo ) gitAdd () error {
107+ s .mutex .Lock ()
108+ defer s .mutex .Unlock ()
96109 w , err := s .repo .Worktree ()
97110 if err != nil {
98111 return err
@@ -126,18 +139,20 @@ func (s *StreamersRepo) getHeadCommit() (string, error) {
126139func (s * StreamersRepo ) getRepo () error {
127140 directory := strings .SplitN (s .url , "/" , 5 )[4 ]
128141 repo , err := git .PlainClone (directory , false , & git.CloneOptions {
129- // The intended use of a GitHub personal access token is in replace of your password
130- // because access tokens can easily be revoked.
142+ // The intended use of a GitHub personal access token is to replace passwords because
143+ // access tokens can easily be revoked.
131144 // https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/
132145 Auth : s .auth ,
133146 URL : s .url ,
134147 // We're discarding the stdout out here. If you'd like to see it toggle
135148 // `Progress` to something like os.Stdout.
136- Progress : ioutil .Discard ,
149+ Progress : io .Discard ,
137150 })
138151
139152 if err == nil {
153+ s .mutex .Lock ()
140154 s .repo = repo
155+ s .mutex .Unlock ()
141156 return nil
142157 }
143158 // Check if the error is that the repo exists and if it is on disk open it.
@@ -160,20 +175,26 @@ func (s *StreamersRepo) getRepo() error {
160175 ReferenceName : "HEAD" ,
161176 RemoteName : "origin" ,
162177 })
178+ s .mutex .Lock ()
163179 s .repo = repo
180+ s .mutex .Unlock ()
164181 return nil
165182}
166183
167184// writeFile writes given text and returns an error.
168185func (s * StreamersRepo ) writefile (activeText , inactiveText string ) error {
169186 bytesToWrite := []byte (activeText )
170- err := ioutil .WriteFile (s .indexFilePath , bytesToWrite , 0644 )
187+ s .mutex .Lock ()
188+ err := os .WriteFile (s .indexFilePath , bytesToWrite , 0644 )
189+ s .mutex .Unlock ()
171190 if err != nil {
172191 return err
173192 }
174193
175194 bytesToWrite = []byte (inactiveText )
176- err = ioutil .WriteFile (s .inactiveFilePath , bytesToWrite , 0644 )
195+ s .mutex .Lock ()
196+ err = os .WriteFile (s .inactiveFilePath , bytesToWrite , 0644 )
197+ s .mutex .Unlock ()
177198 if err != nil {
178199 return err
179200 }
@@ -220,8 +241,10 @@ func (s *StreamersRepo) updateStreamStatus() error {
220241 }
221242 }
222243 }
244+ s .mutex .Lock ()
223245 s .indexMdText = strings .Join (indexMdLines , "\n " )
224246 s .inactiveMdText = strings .Join (inactiveMdLines , "\n " )
247+ s .mutex .Unlock ()
225248
226249 return nil
227250}
@@ -250,14 +273,18 @@ func (s *StreamersRepo) generateStreamerLine(otherInfo string) string {
250273// readFile reads in a slice of bytes from the provided path and returns a string or an error.
251274func (s * StreamersRepo ) readFile () error {
252275 // Read index.md
276+ s .mutex .Lock ()
253277 markdownText , err := os .ReadFile (s .indexFilePath )
278+ s .mutex .Unlock ()
254279 if err != nil {
255280 return err
256281 }
257282 s .indexMdText = string (markdownText )
258283
259284 // Read inactive.md
285+ s .mutex .Lock ()
260286 iMarkdownText , err := os .ReadFile (s .inactiveFilePath )
287+ s .mutex .Unlock ()
261288 if err != nil {
262289 return err
263290 }
@@ -324,7 +351,7 @@ type eventSubNotification struct {
324351// eventsubStatus takes and http Request and ResponseWriter to handle the incoming webhook request.
325352func (s * StreamersRepo ) eventsubStatus (w http.ResponseWriter , r * http.Request ) {
326353 // Read the request body.
327- body , err := ioutil .ReadAll (r .Body )
354+ body , err := io .ReadAll (r .Body )
328355 if err != nil {
329356 log .Println (err )
330357 return
@@ -452,16 +479,19 @@ func lineIndex(arr []string, item string) int {
452479 return 1
453480}
454481
455- // main do the work .
456- func main () {
482+ // init function for the profiler .
483+ func init () {
457484 // Setup profiler.
458485 cfg := profiler.Config {
459486 Service : "streamstatus" ,
460- ServiceVersion : "1.0 .0" ,
487+ ServiceVersion : "1.1 .0" ,
461488 }
462489 // Profiler initialization, best done as early as possible.
463490 profiler .Start (cfg )
491+ }
464492
493+ // main do the work.
494+ func main () {
465495 // Setup file and repo paths.
466496 var repoUrl string
467497 if len (os .Getenv ("SS_GH_REPO" )) == 0 {
@@ -509,6 +539,7 @@ func main() {
509539 repoPath : repoPath ,
510540 url : repoUrl ,
511541 client : client ,
542+ mutex : & sync.Mutex {},
512543 }
513544 port := ":8080"
514545 // Google Cloud Run defaults to 8080. Their platform
0 commit comments