travebing/backend/notifier/session.go

140 lines
2.6 KiB
Go

package notifier
import (
// "compress/gzip"
"context"
"errors"
"io"
"log"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
type Session struct {
user string
id string
w gin.ResponseWriter
blockChan chan int
ctx context.Context
cancel context.CancelFunc
flusher http.Flusher
writer io.Writer
}
func NewSession(c *gin.Context) (*Session, error) {
user := c.Param("plan")
clientID := uuid.New().String()
ctx, cancel := context.WithCancel(context.Background())
session := Session{
user: user,
id: clientID,
blockChan: make(chan int),
ctx: ctx,
cancel: cancel,
}
useGzip := false
if strings.Contains(c.GetHeader("Accept-Encoding"), "gzip") {
useGzip = true
}
err := session.init(useGzip, c.Writer)
return &session, err
}
func (s *Session) WriteString(str string) error {
_, err := s.writer.Write([]byte(str))
if err == nil {
s.flusher.Flush()
}
return err
}
func (s *Session) Write(msg Message) error {
if s.writer == nil {
return errors.New("conn is nil")
}
data, err := msg.SSEBytes()
if err != nil {
return err
}
n, err := s.writer.Write(msg.SSEIDBytes())
if err != nil {
log.Println("msg type write failed ", s.id, n, err)
return err
}
n, err = s.writer.Write(data)
if err != nil {
log.Println("msg data write failed ", s.id, n, err)
return err
}
s.flusher.Flush()
return err
}
func (s *Session) init(gz bool, writer gin.ResponseWriter) error {
// header := writer.Header()
// header.Set("Content-Type", "text/event-stream")
// header.Set("Cache-Control", "no-cache")
// header.Set("Connection", "keep-alive")
// header.Set("Access-Control-Allow-Origin", "*")
// header.Set("Session-ID", s.id)
// if gz {
// header.Set("Content-Encoding", "gzip")
// }
// writer.WriteHeader(http.StatusOK)
// writer.Flush()
s.w = writer
flusher, ok := writer.(http.Flusher)
if !ok {
return errors.New("flusher not support")
}
s.flusher = flusher
w, ok := writer.(io.Writer)
if !ok {
return errors.New("writer not support")
}
s.writer = w
// if gz {
// s.writer = gzip.NewWriter(s.writer)
// }
// err := s.Write(Message{Type: MessageTypeOpened, Data: s.id, To: s.id})
return nil
}
func (s *Session) ID() string {
return s.id
}
func (s *Session) User() string {
return s.user
}
func (s *Session) Run(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
case <-s.ctx.Done():
return
}
}
}
func (s *Session) Flush() {
if s.flusher != nil {
s.flusher.Flush()
}
}
func (s *Session) Close() {
defer s.cancel()
}
func (s *Session) Messages() <-chan Message {
return nil
}