mirror of
				https://github.com/AlexxIT/go2rtc.git
				synced 2025-10-31 11:46:26 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			135 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package api
 | |
| 
 | |
| import (
 | |
| 	"encoding/json"
 | |
| 	"github.com/AlexxIT/go2rtc/cmd/app"
 | |
| 	"github.com/AlexxIT/go2rtc/cmd/streams"
 | |
| 	"github.com/AlexxIT/go2rtc/pkg/streamer"
 | |
| 	"github.com/gorilla/websocket"
 | |
| 	"github.com/rs/zerolog"
 | |
| 	"net"
 | |
| 	"net/http"
 | |
| )
 | |
| 
 | |
| func Init() {
 | |
| 	var cfg struct {
 | |
| 		Mod struct {
 | |
| 			Listen    string `yaml:"listen"`
 | |
| 			BasePath  string `yaml:"base_path"`
 | |
| 			StaticDir string `yaml:"static_dir"`
 | |
| 		} `yaml:"api"`
 | |
| 	}
 | |
| 
 | |
| 	// default config
 | |
| 	cfg.Mod.Listen = ":1984"
 | |
| 
 | |
| 	// load config from YAML
 | |
| 	app.LoadConfig(&cfg)
 | |
| 
 | |
| 	if cfg.Mod.Listen == "" {
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	basePath = cfg.Mod.BasePath
 | |
| 	log = app.GetLogger("api")
 | |
| 
 | |
| 	initStatic(cfg.Mod.StaticDir)
 | |
| 	initWS()
 | |
| 
 | |
| 	HandleFunc("api/streams", streamsHandler)
 | |
| 	HandleFunc("api/ws", apiWS)
 | |
| 
 | |
| 	// ensure we can listen without errors
 | |
| 	listener, err := net.Listen("tcp", cfg.Mod.Listen)
 | |
| 	if err != nil {
 | |
| 		log.Fatal().Err(err).Msg("[api] listen")
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	log.Info().Str("addr", cfg.Mod.Listen).Msg("[api] listen")
 | |
| 
 | |
| 	go func() {
 | |
| 		s := http.Server{}
 | |
| 
 | |
| 		if log.Trace().Enabled() {
 | |
| 			s.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | |
| 				log.Trace().Stringer("url", r.URL).Msgf("[api] %s", r.Method)
 | |
| 				http.DefaultServeMux.ServeHTTP(w, r)
 | |
| 			})
 | |
| 		}
 | |
| 
 | |
| 		if err = s.Serve(listener); err != nil {
 | |
| 			log.Fatal().Err(err).Msg("[api] serve")
 | |
| 		}
 | |
| 	}()
 | |
| }
 | |
| 
 | |
| // HandleFunc handle pattern with relative path:
 | |
| // - "api/streams" => "{basepath}/api/streams"
 | |
| // - "/streams"    => "/streams"
 | |
| func HandleFunc(pattern string, handler http.HandlerFunc) {
 | |
| 	if len(pattern) == 0 || pattern[0] != '/' {
 | |
| 		pattern = basePath + "/" + pattern
 | |
| 	}
 | |
| 	log.Trace().Str("path", pattern).Msg("[api] register path")
 | |
| 	http.HandleFunc(pattern, handler)
 | |
| }
 | |
| 
 | |
| func HandleWS(msgType string, handler WSHandler) {
 | |
| 	wsHandlers[msgType] = handler
 | |
| }
 | |
| 
 | |
| var basePath string
 | |
| var log zerolog.Logger
 | |
| var wsHandlers = make(map[string]WSHandler)
 | |
| 
 | |
| func streamsHandler(w http.ResponseWriter, r *http.Request) {
 | |
| 	src := r.URL.Query().Get("src")
 | |
| 
 | |
| 	switch r.Method {
 | |
| 	case "PUT":
 | |
| 		streams.New(src, src)
 | |
| 		return
 | |
| 	case "DELETE":
 | |
| 		streams.Delete(src)
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	var v interface{}
 | |
| 	if src != "" {
 | |
| 		v = streams.Get(src)
 | |
| 	} else {
 | |
| 		v = streams.All()
 | |
| 	}
 | |
| 
 | |
| 	e := json.NewEncoder(w)
 | |
| 	e.SetIndent("", "  ")
 | |
| 	_ = e.Encode(v)
 | |
| }
 | |
| 
 | |
| func apiWS(w http.ResponseWriter, r *http.Request) {
 | |
| 	ctx := new(Context)
 | |
| 	if err := ctx.Upgrade(w, r); err != nil {
 | |
| 		log.Error().Err(err).Msg("[api.ws] upgrade")
 | |
| 		return
 | |
| 	}
 | |
| 	defer ctx.Close()
 | |
| 
 | |
| 	for {
 | |
| 		msg := new(streamer.Message)
 | |
| 		if err := ctx.Conn.ReadJSON(msg); err != nil {
 | |
| 			if websocket.IsUnexpectedCloseError(
 | |
| 				err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure,
 | |
| 			) {
 | |
| 				log.Error().Err(err).Msg("[api.ws] readJSON")
 | |
| 			}
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		handler := wsHandlers[msg.Type]
 | |
| 		if handler != nil {
 | |
| 			handler(ctx, msg)
 | |
| 		}
 | |
| 	}
 | |
| }
 | 
