2020-05-08 00:49:00 +03:00
// Copyright 2020 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2020-05-08 00:49:00 +03:00
package events
import (
"net/http"
"time"
"code.gitea.io/gitea/modules/eventsource"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
2022-01-02 16:12:35 +03:00
"code.gitea.io/gitea/routers/web/auth"
2024-02-27 10:12:22 +03:00
"code.gitea.io/gitea/services/context"
2020-05-08 00:49:00 +03:00
)
// Events listens for events
func Events ( ctx * context . Context ) {
// FIXME: Need to check if resp is actually a http.Flusher! - how though?
// Set the headers related to event streaming.
ctx . Resp . Header ( ) . Set ( "Content-Type" , "text/event-stream" )
ctx . Resp . Header ( ) . Set ( "Cache-Control" , "no-cache" )
ctx . Resp . Header ( ) . Set ( "Connection" , "keep-alive" )
ctx . Resp . Header ( ) . Set ( "X-Accel-Buffering" , "no" )
ctx . Resp . WriteHeader ( http . StatusOK )
2021-03-20 23:39:43 +03:00
if ! ctx . IsSigned {
// Return unauthorized status event
2021-04-09 10:40:34 +03:00
event := & eventsource . Event {
2021-04-05 00:37:50 +03:00
Name : "close" ,
Data : "unauthorized" ,
2021-04-09 10:40:34 +03:00
}
2021-03-20 23:39:43 +03:00
_ , _ = event . WriteTo ( ctx )
ctx . Resp . Flush ( )
return
}
2020-05-08 00:49:00 +03:00
// Listen to connection close and un-register messageChan
2021-05-31 09:18:11 +03:00
notify := ctx . Done ( )
2020-05-08 00:49:00 +03:00
ctx . Resp . Flush ( )
shutdownCtx := graceful . GetManager ( ) . ShutdownContext ( )
2022-03-22 10:03:22 +03:00
uid := ctx . Doer . ID
2020-05-08 00:49:00 +03:00
messageChan := eventsource . GetManager ( ) . Register ( uid )
unregister := func ( ) {
eventsource . GetManager ( ) . Unregister ( uid , messageChan )
// ensure the messageChan is closed
for {
_ , ok := <- messageChan
if ! ok {
break
}
}
}
if _ , err := ctx . Resp . Write ( [ ] byte ( "\n" ) ) ; err != nil {
log . Error ( "Unable to write to EventStream: %v" , err )
unregister ( )
return
}
timer := time . NewTicker ( 30 * time . Second )
loop :
for {
select {
case <- timer . C :
event := & eventsource . Event {
Name : "ping" ,
}
_ , err := event . WriteTo ( ctx . Resp )
if err != nil {
2022-03-22 10:03:22 +03:00
log . Error ( "Unable to write to EventStream for user %s: %v" , ctx . Doer . Name , err )
2020-05-08 00:49:00 +03:00
go unregister ( )
break loop
}
ctx . Resp . Flush ( )
case <- notify :
go unregister ( )
break loop
case <- shutdownCtx . Done ( ) :
go unregister ( )
break loop
case event , ok := <- messageChan :
if ! ok {
break loop
}
// Handle logout
if event . Name == "logout" {
if ctx . Session . ID ( ) == event . Data {
_ , _ = ( & eventsource . Event {
Name : "logout" ,
Data : "here" ,
} ) . WriteTo ( ctx . Resp )
ctx . Resp . Flush ( )
go unregister ( )
2022-01-02 16:12:35 +03:00
auth . HandleSignOut ( ctx )
2020-05-08 00:49:00 +03:00
break loop
}
// Replace the event - we don't want to expose the session ID to the user
2021-04-09 10:40:34 +03:00
event = & eventsource . Event {
2020-05-08 00:49:00 +03:00
Name : "logout" ,
Data : "elsewhere" ,
2021-04-09 10:40:34 +03:00
}
2020-05-08 00:49:00 +03:00
}
_ , err := event . WriteTo ( ctx . Resp )
if err != nil {
2022-03-22 10:03:22 +03:00
log . Error ( "Unable to write to EventStream for user %s: %v" , ctx . Doer . Name , err )
2020-05-08 00:49:00 +03:00
go unregister ( )
break loop
}
ctx . Resp . Flush ( )
}
}
timer . Stop ( )
}