package relay import ( "fmt" "net/http" "sync" ) const Port = 19765 type Server struct { mu sync.Mutex clients map[chan string]struct{} currentURL string server *http.Server } func New() *Server { return &Server{clients: make(map[chan string]struct{})} } func (s *Server) Start() { mux := http.NewServeMux() mux.HandleFunc("/sse", s.handleSSE) mux.HandleFunc("/jira", s.handleJira) mux.HandleFunc("/", s.handleIndex) s.server = &http.Server{ Addr: fmt.Sprintf("127.0.0.1:%d", Port), Handler: mux, } go func() { _ = s.server.ListenAndServe() }() } func (s *Server) Stop() { if s.server != nil { _ = s.server.Close() } } // Broadcast sends a new Jira URL to all connected relay pages. func (s *Server) Broadcast(url string) { s.mu.Lock() s.currentURL = url clients := make([]chan string, 0, len(s.clients)) for ch := range s.clients { clients = append(clients, ch) } s.mu.Unlock() for _, ch := range clients { select { case ch <- url: default: } } } func (s *Server) handleSSE(w http.ResponseWriter, r *http.Request) { flusher, ok := w.(http.Flusher) if !ok { http.Error(w, "streaming unsupported", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") w.Header().Set("Access-Control-Allow-Origin", "*") ch := make(chan string, 2) s.mu.Lock() s.clients[ch] = struct{}{} current := s.currentURL s.mu.Unlock() defer func() { s.mu.Lock() delete(s.clients, ch) s.mu.Unlock() }() // Send current URL immediately so relay opens Jira right on connect. if current != "" { _, _ = fmt.Fprintf(w, "data: %s\n\n", current) flusher.Flush() } for { select { case url := <-ch: _, _ = fmt.Fprintf(w, "data: %s\n\n", url) flusher.Flush() case <-r.Context().Done(): return } } } func (s *Server) handleIndex(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Cache-Control", "no-cache") _, _ = fmt.Fprint(w, relayHTML) } // handleJira redirects to the Jira URL passed in the ?url= query param. // This intermediate hop keeps the navigation same-origin so the relay page // can reliably set w.location.href without cross-origin restrictions. func (s *Server) handleJira(w http.ResponseWriter, r *http.Request) { target := r.URL.Query().Get("url") if target == "" { http.Error(w, "missing url param", http.StatusBadRequest) return } w.Header().Set("Cache-Control", "no-cache") http.Redirect(w, r, target, http.StatusFound) } const relayHTML = "" + "
Daily Timer \xe2\x80\x94 Jira relay
" + "\xd0\xbd\xd0\xb5 \xd0\xb7\xd0xb0\xd0\xba\xd1\x80\xd1\x8b\xd0\xb2\xd0\xb0\xd0\xb9\xd1\x82\xd0\xb5 \xd1\x8d\xd1\x82\xd1\x83 \xd0\xb2\xd0\xba\xd0\xbb\xd0\xb0\xd0\xb4\xd0\xba\xd1\x83
" + "" + "" + "" + ""