raylu 14 жил өмнө
parent
commit
578e1a2e6c
2 өөрчлөгдсөн 68 нэмэгдсэн , 28 устгасан
  1. 13 17
      main.go
  2. 55 11
      updates.go

+ 13 - 17
main.go

@@ -262,25 +262,21 @@ func poll(w http.ResponseWriter, r *http.Request) {
 			http.Error(w, err.String(), http.StatusInternalServerError)
 			return
 		}
-		var update *Update
-		for i := 0; i < 30; i++ {
-			update = getUpdates(q.Get("pid"), timestamp)
-			if update != nil {
-				w.Write([]byte("["))
-				for update != nil {
-					output, err := json.MarshalForHTML(update)
-					if err == nil {
-						w.Write(output)
-					}
-					update = update.Next
-					if update != nil {
-						w.Write([]byte(","))
-					}
+		update := getUpdates(q.Get("pid"), timestamp)
+		if update != nil {
+			w.Write([]byte("["))
+			for update != nil {
+				output, err := json.MarshalForHTML(update)
+				if err == nil {
+					w.Write(output)
+				}
+				update = update.Next
+				if update != nil {
+					w.Write([]byte(","))
 				}
-				w.Write([]byte("]"))
-				return
 			}
-			time.Sleep(1e9) // 1 second
+			w.Write([]byte("]"))
+			return
 		}
 		w.Write([]byte("[]"))
 	}

+ 55 - 11
updates.go

@@ -2,6 +2,7 @@ package main
 
 import (
 	"time"
+	"sync"
 )
 
 const (
@@ -16,12 +17,20 @@ type Update struct {
 	Timestamp int64
 	Next *Update
 }
+type Listener struct {
+	L chan bool
+	Next *Listener
+}
+
 var headUpdates map[int]*Update
 var tailUpdates map[int]*Update
+var listeners map[int]*Listener
+var updateLock sync.Mutex
 
 func init() {
 	headUpdates = make(map[int]*Update)
 	tailUpdates = make(map[int]*Update)
+	listeners = make(map[int]*Listener)
 }
 
 func addUpdate(pid int, action uint, song *Song) {
@@ -29,13 +38,36 @@ func addUpdate(pid int, action uint, song *Song) {
 	update.Song = song
 	update.Action = action
 	update.Timestamp = time.Nanoseconds()
-	pup, ok := tailUpdates[pid]
-	if ok {
+
+	updateLock.Lock()
+	defer updateLock.Unlock()
+
+	pup := tailUpdates[pid]
+	if pup != nil {
 		pup.Next = update
 	} else {
 		headUpdates[pid] = update
 	}
 	tailUpdates[pid] = update
+
+	listener := listeners[pid]
+	for listener != nil {
+		listener.L <- true
+		listener = listener.Next
+	}
+	listeners[pid] = nil
+}
+
+// assumes locked
+func checkUpdates(pid int, timestamp int64) *Update {
+	pup, _ := headUpdates[pid]
+	for pup != nil {
+		if pup.Timestamp > timestamp {
+			return pup
+		}
+		pup = pup.Next
+	}
+	return nil
 }
 
 func getUpdates(id string, timestamp int64) *Update {
@@ -45,15 +77,27 @@ func getUpdates(id string, timestamp int64) *Update {
 	if pid == -1 {
 		return nil
 	}
-	pup, ok := headUpdates[pid]
-	if !ok {
-		return nil
+
+	updateLock.Lock()
+	pup := checkUpdates(pid, timestamp)
+	if pup != nil {
+		updateLock.Unlock()
+		return pup
 	}
-	for pup != nil {
-		if pup.Timestamp > timestamp {
-			return pup
-		}
-		pup = pup.Next
+
+	// didn't get updates
+	listener := new(Listener)
+	listener.L = make(chan bool)
+	lhead := listeners[pid]
+	if lhead != nil {
+		listener.Next = lhead
 	}
-	return nil
+	listeners[pid] = listener
+	updateLock.Unlock()
+	<-listener.L
+
+	updateLock.Lock()
+	pup = checkUpdates(pid, timestamp)
+	updateLock.Unlock()
+	return pup
 }