Fix: sse changes
This commit is contained in:
		| @@ -4,7 +4,6 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"log/slog" | 	"log/slog" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"strings" |  | ||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -73,19 +72,22 @@ func (broker *Broker) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |||||||
| 	messageChan := make(NotifierChan) | 	messageChan := make(NotifierChan) | ||||||
| 	broker.newClients <- messageChan | 	broker.newClients <- messageChan | ||||||
| 	defer func() { broker.closingClients <- messageChan }() | 	defer func() { broker.closingClients <- messageChan }() | ||||||
|  | 	ctx := r.Context() | ||||||
| 	for { | 	for { | ||||||
| 		event := <-messageChan | 		select { | ||||||
| 		// // Proper SSE formatting | 		case <-ctx.Done(): | ||||||
| 		// fmt.Fprintf(w, "event: %s\n", event.EventName)  // Event name line | 			// Client disconnected | ||||||
| 		// fmt.Fprintf(w, "data: %s\n\n", event.Payload)   // Data line + empty line | 			return | ||||||
| 		// Alternative for multi-line data: | 		case event := <-messageChan: | ||||||
| 		fmt.Fprintf(w, "event: %s\n", event.EventName) | 			_, err := fmt.Fprintf(w, "event: %s\ndata: %s\n\n", event.EventName, event.Payload) | ||||||
| 		for _, line := range strings.Split(event.Payload, "\n") { | 			if err != nil { | ||||||
| 			fmt.Fprintf(w, "data: %s\n", line) | 				fmt.Println(err) | ||||||
|  | 				// Client disconnected | ||||||
|  | 				return | ||||||
| 			} | 			} | ||||||
| 		fmt.Fprintf(w, "\n") |  | ||||||
| 			w.(http.Flusher).Flush() | 			w.(http.Flusher).Flush() | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // Listen for new notifications and redistribute them to clients | // Listen for new notifications and redistribute them to clients | ||||||
|   | |||||||
| @@ -1,4 +1,8 @@ | |||||||
| {{define "main"}} | {{define "main"}} | ||||||
|  | 	<div hx-ext="sse" sse-connect="/sub/sse" sse-swap="test"> | ||||||
|  | 	    Contents of this box will be updated in real time | ||||||
|  | 	    with every SSE message received from the chatroom. | ||||||
|  | 	</div> | ||||||
| 	<!-- user has no username -> login form --> | 	<!-- user has no username -> login form --> | ||||||
| 	{{ if not . }} | 	{{ if not . }} | ||||||
| 	{{template "login"}} | 	{{template "login"}} | ||||||
|   | |||||||
| @@ -78,6 +78,7 @@ func HandleFrontLogin(w http.ResponseWriter, r *http.Request) { | |||||||
| 	fi := &models.FullInfo{ | 	fi := &models.FullInfo{ | ||||||
| 		State: userstate, | 		State: userstate, | ||||||
| 	} | 	} | ||||||
|  | 	fi.List = listPublicRooms() | ||||||
| 	// save state to cache | 	// save state to cache | ||||||
| 	if err := saveState(cleanName, userstate); err != nil { | 	if err := saveState(cleanName, userstate); err != nil { | ||||||
| 		// if err := saveFullInfo(fi); err != nil { | 		// if err := saveFullInfo(fi); err != nil { | ||||||
|   | |||||||
| @@ -1,18 +1,22 @@ | |||||||
| package handlers | package handlers | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"golias/broker" | ||||||
| 	"golias/config" | 	"golias/config" | ||||||
| 	"golias/pkg/cache" | 	"golias/pkg/cache" | ||||||
| 	"html/template" | 	"html/template" | ||||||
| 	"log/slog" | 	"log/slog" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"os" | 	"os" | ||||||
|  | 	"time" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	log      *slog.Logger | 	log      *slog.Logger | ||||||
| 	cfg      *config.Config | 	cfg      *config.Config | ||||||
| 	memcache cache.Cache | 	memcache cache.Cache | ||||||
|  | 	Notifier *broker.Broker | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func init() { | func init() { | ||||||
| @@ -22,6 +26,20 @@ func init() { | |||||||
| 	})) | 	})) | ||||||
| 	memcache = cache.MemCache | 	memcache = cache.MemCache | ||||||
| 	cfg = config.LoadConfigOrDefault("") | 	cfg = config.LoadConfigOrDefault("") | ||||||
|  | 	Notifier = broker.NewBroker() | ||||||
|  | 	go Notifier.Listen() | ||||||
|  | 	ticker := time.NewTicker(2 * time.Second) | ||||||
|  | 	go func() { | ||||||
|  | 		counter := 0 | ||||||
|  | 		for { | ||||||
|  | 			<-ticker.C | ||||||
|  | 			Notifier.Notifier <- broker.NotificationEvent{ | ||||||
|  | 				EventName: "test", | ||||||
|  | 				Payload:   fmt.Sprintf("%v test call of notifier", counter), | ||||||
|  | 			} | ||||||
|  | 			counter++ | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
| } | } | ||||||
|  |  | ||||||
| var roundWords = map[string]string{ | var roundWords = map[string]string{ | ||||||
| @@ -69,10 +87,8 @@ func HandleHome(w http.ResponseWriter, r *http.Request) { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if fi != nil && fi.Room == nil { | 	if fi != nil && fi.Room == nil { | ||||||
| 		log.Debug("loading list") |  | ||||||
| 		fi.List = listPublicRooms() | 		fi.List = listPublicRooms() | ||||||
| 	} | 	} | ||||||
| 	log.Debug("data debug", "fi", fi) |  | ||||||
| 	if err := tmpl.ExecuteTemplate(w, "base", fi); err != nil { | 	if err := tmpl.ExecuteTemplate(w, "base", fi); err != nil { | ||||||
| 		log.Error("failed to exec templ;", "error", err, "templ", "base") | 		log.Error("failed to exec templ;", "error", err, "templ", "base") | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -11,29 +11,16 @@ import ( | |||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // responseWriterWrapper wraps http.ResponseWriter to capture status code |  | ||||||
| type responseWriterWrapper struct { |  | ||||||
| 	http.ResponseWriter |  | ||||||
| 	status int |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (w *responseWriterWrapper) WriteHeader(status int) { |  | ||||||
| 	w.status = status |  | ||||||
| 	w.ResponseWriter.WriteHeader(status) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // LogRequests logs all HTTP requests with method, path and duration | // LogRequests logs all HTTP requests with method, path and duration | ||||||
| func LogRequests(next http.Handler) http.Handler { | func LogRequests(next http.Handler) http.Handler { | ||||||
| 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		start := time.Now() | 		start := time.Now() | ||||||
| 		// Wrap response writer to capture status code | 		// Wrap response writer to capture status code | ||||||
| 		ww := &responseWriterWrapper{ResponseWriter: w} | 		next.ServeHTTP(w, r) | ||||||
| 		next.ServeHTTP(ww, r) |  | ||||||
| 		duration := time.Since(start) | 		duration := time.Since(start) | ||||||
| 		log.Debug("request completed", | 		log.Debug("request completed", | ||||||
| 			"method", r.Method, | 			"method", r.Method, | ||||||
| 			"path", r.URL.RequestURI(), | 			"path", r.URL.RequestURI(), | ||||||
| 			"status", ww.status, |  | ||||||
| 			"duration", duration.String(), | 			"duration", duration.String(), | ||||||
| 		) | 		) | ||||||
| 	}) | 	}) | ||||||
|   | |||||||
							
								
								
									
										5
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								main.go
									
									
									
									
									
								
							| @@ -14,7 +14,8 @@ func ListenToRequests(port string) error { | |||||||
| 		Handler:     handlers.LogRequests(handlers.GetSession(mux)), | 		Handler:     handlers.LogRequests(handlers.GetSession(mux)), | ||||||
| 		Addr:        port, | 		Addr:        port, | ||||||
| 		ReadTimeout: time.Second * 5, | 		ReadTimeout: time.Second * 5, | ||||||
| 		WriteTimeout: time.Second * 5, | 		// WriteTimeout: time.Second * 5, | ||||||
|  | 		WriteTimeout: 0, // sse streaming | ||||||
| 	} | 	} | ||||||
| 	fs := http.FileServer(http.Dir("assets/")) | 	fs := http.FileServer(http.Dir("assets/")) | ||||||
| 	mux.Handle("GET /assets/", http.StripPrefix("/assets/", fs)) | 	mux.Handle("GET /assets/", http.StripPrefix("/assets/", fs)) | ||||||
| @@ -34,6 +35,8 @@ func ListenToRequests(port string) error { | |||||||
| 	mux.HandleFunc("GET /room/hideform", handlers.HandleHideCreateForm) | 	mux.HandleFunc("GET /room/hideform", handlers.HandleHideCreateForm) | ||||||
| 	mux.HandleFunc("GET /word/show-color", handlers.HandleShowColor) | 	mux.HandleFunc("GET /word/show-color", handlers.HandleShowColor) | ||||||
| 	mux.HandleFunc("POST /check/name", handlers.HandleNameCheck) | 	mux.HandleFunc("POST /check/name", handlers.HandleNameCheck) | ||||||
|  | 	// sse | ||||||
|  | 	mux.Handle("GET /sub/sse", handlers.Notifier) | ||||||
| 	slog.Info("Listening", "addr", port) | 	slog.Info("Listening", "addr", port) | ||||||
| 	return server.ListenAndServe() | 	return server.ListenAndServe() | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Grail Finder
					Grail Finder