Added TLS.
This commit is contained in:
parent
1da3ce4075
commit
c432174dca
@ -1,15 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"git.insit.tech/psa/rtsp_reader-writer/reader/internal/config"
|
||||
logger "git.insit.tech/psa/rtsp_reader-writer/reader/internal/log"
|
||||
"git.insit.tech/psa/rtsp_reader-writer/reader/internal/metrics"
|
||||
"git.insit.tech/psa/rtsp_reader-writer/reader/internal/web/handlers"
|
||||
"git.insit.tech/psa/rtsp_reader-writer/reader/internal/web/middlewares"
|
||||
"github.com/quic-go/quic-go/http3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -17,10 +19,7 @@ func main() {
|
||||
logger.StartMainLogger(config.Local, "reader")
|
||||
|
||||
// Check if the data folder in the directory.
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
}
|
||||
config.DirData = fmt.Sprintf("%s/%s/vod", homeDir, config.Local)
|
||||
config.DirData = fmt.Sprintf("%s/%s/vod", config.HomeDir, config.Local)
|
||||
//
|
||||
//err = unpacker.CreateVideo()
|
||||
//if err != nil {
|
||||
@ -47,17 +46,31 @@ func main() {
|
||||
//mux.HandleFunc("GET /vods/:id", handlersQUIC.ConfigVodsHandler)
|
||||
mux.Handle("GET /vods", middlewares.AuthMiddleware(handlers.ListVodsHandler()))
|
||||
|
||||
http.ListenAndServe(":8080", mux)
|
||||
|
||||
// HTTP/1.1 & HTTP/2
|
||||
go func() {
|
||||
//http.ListenAndServeTLS(":8080", certFile, keyFile, mux)
|
||||
http.ListenAndServeTLS(":8080", config.TLSCertFile, config.TLSKeyFile, mux)
|
||||
|
||||
}()
|
||||
|
||||
//server := &http3.Server{
|
||||
// Addr: ":8080",
|
||||
// Handler: mux,
|
||||
// TLSConfig: quic.GetTLSConfig(),
|
||||
//}
|
||||
server := &http3.Server{
|
||||
Addr: ":8080",
|
||||
Handler: mux,
|
||||
TLSConfig: getTLSConfig(),
|
||||
}
|
||||
|
||||
log.Fatal(server.ListenAndServe())
|
||||
}
|
||||
|
||||
func getTLSConfig() *tls.Config {
|
||||
// Загрузка сертификата и ключа
|
||||
cert, err := tls.LoadX509KeyPair(config.TLSCertFile, config.TLSKeyFile)
|
||||
if err != nil {
|
||||
log.Fatal("Ошибка загрузки сертификата и ключа:", err)
|
||||
}
|
||||
|
||||
return &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
NextProtos: []string{"h3", "h2", "http/1.1"},
|
||||
MinVersion: tls.VersionTLS13,
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ require (
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/prometheus/client_golang v1.22.0
|
||||
github.com/quic-go/quic-go v0.51.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
go.uber.org/zap v1.27.0
|
||||
)
|
||||
@ -25,13 +26,16 @@ require (
|
||||
github.com/asticode/go-astits v1.13.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/golang/snappy v1.0.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||
github.com/grafov/m3u8 v0.12.1 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.9.5 // indirect
|
||||
github.com/pion/randutil v0.1.0 // indirect
|
||||
github.com/pion/rtcp v1.2.15 // indirect
|
||||
github.com/pion/rtp v1.8.13 // indirect
|
||||
@ -39,13 +43,20 @@ require (
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.63.0 // indirect
|
||||
github.com/prometheus/procfs v0.16.0 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.51.0 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
go.uber.org/mock v0.5.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/mod v0.18.0 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/sync v0.13.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
golang.org/x/tools v0.22.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
@ -21,26 +21,38 @@ github.com/bluenviron/mediacommon/v2 v2.0.0 h1:JinZ9v2x6QeAOzA0cDA6aFe8vQuCrU8Oy
|
||||
github.com/bluenviron/mediacommon/v2 v2.0.0/go.mod h1:iHEz1SFIet6zBwAQoh1a92vTQ3dV3LpVFbom6/SLz3k=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gen2brain/aac-go v0.0.0-20230119102159-ef1e76509d21 h1:yfrARW/aVlqKORCdKrYdU0PZUKPqQvYEUQBKfVlNa9Q=
|
||||
github.com/gen2brain/aac-go v0.0.0-20230119102159-ef1e76509d21/go.mod h1:HZqGD/LXHB1VCGUGNzuyxSsD12f3KjbJbvImAmoK/mM=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/gofiber/contrib/jwt v1.1.0 h1:ka5WjWsZ2cd0irvfpmH9hIKj+fflvVRzQxJ7Nv1H3tE=
|
||||
github.com/gofiber/contrib/jwt v1.1.0/go.mod h1:CpIwrkUQ3Q6IP8y9n3f0wP9bOnSKx39EDp2fBVgMFVk=
|
||||
github.com/gofiber/fiber/v2 v2.52.6 h1:Rfp+ILPiYSvvVuIPvxrBns+HJp8qGLDnLJawAu27XVI=
|
||||
github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
||||
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grafov/m3u8 v0.12.1 h1:DuP1uA1kvRRmGNAZ0m+ObLv1dvrfNO0TPx0c/enNk0s=
|
||||
github.com/grafov/m3u8 v0.12.1/go.mod h1:nqzOkfBiZJENr52zTVd/Dcl03yzphIMbJqkXGu+u080=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
@ -58,6 +70,10 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
|
||||
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
|
||||
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
||||
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
||||
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
||||
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
|
||||
github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo=
|
||||
@ -78,6 +94,10 @@ github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA
|
||||
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
|
||||
github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM=
|
||||
github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.51.0 h1:K8exxe9zXxeRKxaXxi/GpUqYiTrtdiWP8bo1KFya6Wc=
|
||||
github.com/quic-go/quic-go v0.51.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
@ -86,6 +106,7 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
@ -103,17 +124,30 @@ github.com/zaf/g711 v1.4.0 h1:XZYkjjiAg9QTBnHqEg37m2I9q3IIDv5JRYXs2N8ma7c=
|
||||
github.com/zaf/g711 v1.4.0/go.mod h1:eCDXt3dSp/kYYAoooba7ukD/Q75jvAaS4WOMr0l1Roo=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
|
||||
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
|
||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
@ -2,6 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@ -15,8 +16,10 @@ var (
|
||||
Local = "storage"
|
||||
LogsDirectory string
|
||||
DirData string
|
||||
|
||||
Storage AuthStorage
|
||||
HomeDir, _ = os.UserHomeDir()
|
||||
TLSCertFile = HomeDir + "/GoProjects/certs/certbundle.pem"
|
||||
TLSKeyFile = HomeDir + "/GoProjects/certs/server.key"
|
||||
Storage AuthStorage
|
||||
|
||||
JwtSecretKey = []byte(uuid.NewString())
|
||||
SessionStore sync.Map
|
||||
|
@ -1,549 +0,0 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.insit.tech/psa/rtsp_reader-writer/reader/internal/config"
|
||||
"git.insit.tech/psa/rtsp_reader-writer/reader/internal/processor"
|
||||
"git.insit.tech/psa/rtsp_reader-writer/writer/pkg/storage"
|
||||
jwtware "github.com/gofiber/contrib/jwt"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type VideoRequest struct {
|
||||
Date string `json:"date"`
|
||||
StartTime string `json:"start_time"`
|
||||
EndTime string `json:"end_time"`
|
||||
}
|
||||
|
||||
type ListVodsResponse struct {
|
||||
EstimatedCount int `json:"estimated_count"` // Estimated total number of records for the query.
|
||||
Vods []string `json:"vods"` // List of vods.
|
||||
Files map[string][]string `json:"files"` // List files and folders of a specific VOD location.
|
||||
}
|
||||
|
||||
type ConfigVodsResponse struct {
|
||||
Prefix string `json:"prefix"` // The unique name of VOD location.
|
||||
AutoMbr bool `json:"auto_mbr"` // Turns on automatic creation of a multi-bitrate HLS playlist from several files with different bitrates.
|
||||
Disabled bool `json:"disabled"` // Whether this VOD location is disabled.
|
||||
Protocols struct { // Configuraton of play protocols.
|
||||
Hls bool `json:"hls"` // Whether to allow or deny an HLS stream playback.
|
||||
Cmaf bool `json:"cmaf"` // Whether to allow or deny an LL-HLS stream playback.
|
||||
Dash bool `json:"dash"` // Whether to allow or deny a DASH stream playback.
|
||||
Player bool `json:"player"` // Whether to allow or deny playback in embed.html.
|
||||
Mss bool `json:"mss"` // Whether to allow or deny an MSS stream playback.
|
||||
Rtmp bool `json:"rtmp"` // Whether to allow or deny an RTMP stream playback.
|
||||
Rtsp bool `json:"rtsp"` // Whether to allow or deny an RTSP stream playback.
|
||||
M4F bool `json:"m4f"` // Whether to allow or deny an M4F stream playback.
|
||||
M4S bool `json:"m4s"` // Whether to allow or deny an M4S stream playback.
|
||||
Mseld bool `json:"mseld"` // Whether to allow or deny an MSE-LD stream playback.
|
||||
Tshttp bool `json:"tshttp"` // Whether to allow or deny an MPEG-TS stream playback over HTTP(S).
|
||||
Webrtc bool `json:"webrtc"` // Whether to allow or deny an WebRTC stream playback.
|
||||
Srt bool `json:"srt"` // Whether to allow or deny an SRT stream playback.
|
||||
Shoutcast bool `json:"shoutcast"` // Whether to allow or deny a SHOUTcast/Icecast stream playback.
|
||||
Mp4 bool `json:"mp4"` // Whether to allow or deny an MP4 file download over HTTP(S).
|
||||
Jpeg bool `json:"jpeg"` // Whether to allow or deny delivering JPEG thumbnails over HTTP(S).
|
||||
Api bool `json:"api"` // Whether to allow or deny API requests.
|
||||
} `json:"protocols"`
|
||||
SegmentDuration int `json:"segment_duration"` // The time, in seconds, of the segment duration. Used for the protocols like HLS or DASH.
|
||||
AddAudioOnly bool `json:"add_audio_only"` // Whether to add an audio-only version of an HLS stream. Used to create App Store compliant HLS streams to deliver the content to Apple iOS devices. Add audio-only HLS playlist to variant MBR playlist for iOS compliant streaming.
|
||||
Provider string `json:"provider"` // Human-readable name of the content provider. Applicable to MPEG-TS.
|
||||
}
|
||||
|
||||
type SingleVodsResponse struct {
|
||||
Name string `json:"name"`
|
||||
Prefix string `json:"prefix"`
|
||||
Url string `json:"url"`
|
||||
Folder string `json:"folder"`
|
||||
Bytes int64 `json:"bytes"`
|
||||
MediaInfo MediaSingleVodsResponse `json:"media_info"`
|
||||
}
|
||||
|
||||
type MediaSingleVodsResponse struct {
|
||||
Tracks map[string]string `json:"tracks"`
|
||||
Duration int `json:"duration"`
|
||||
Provider string `json:"provider"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
// Inactive5Minutes checks if a folder has files that was not created or modified for last 5 minutes.
|
||||
func Inactive5Minutes(entries []os.DirEntry) (bool, error) {
|
||||
threshold := time.Now().Add(-5 * time.Minute)
|
||||
|
||||
disabled := true
|
||||
|
||||
for _, entry := range entries {
|
||||
info, err := entry.Info()
|
||||
if err != nil {
|
||||
return true, errors.New("Info error: " + err.Error())
|
||||
}
|
||||
|
||||
if info.ModTime().After(threshold) {
|
||||
disabled = false
|
||||
return disabled, nil
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// recDurationMilliseconds calculates the difference between first existing rec file and the last one in milliseconds.
|
||||
func recDurationMilliseconds(entries []os.DirEntry) (int, error) {
|
||||
// Find last file and first file; get timestamps.
|
||||
lastFile := entries[len(entries)-1].Name()
|
||||
lastTime := strings.Split(lastFile, "_")[0]
|
||||
|
||||
firstFile := entries[0].Name()
|
||||
firstTime := strings.Split(firstFile, "_")[0]
|
||||
|
||||
// Convert string timestamps to int.
|
||||
lastTimeInt, err := strconv.Atoi(lastTime)
|
||||
if err != nil {
|
||||
return 0, errors.New("convert last time error: " + err.Error())
|
||||
}
|
||||
|
||||
firstTimeInt, err := strconv.Atoi(firstTime)
|
||||
if err != nil {
|
||||
return 0, errors.New("convert first time error: " + err.Error())
|
||||
}
|
||||
|
||||
// Calculate the difference.
|
||||
difference := lastTimeInt - firstTimeInt
|
||||
|
||||
return difference * 1000, nil
|
||||
}
|
||||
|
||||
// Download processes Download request.
|
||||
func Download(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("new download request: %+v\n", r)
|
||||
|
||||
downloadRequest := VideoRequest{}
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(&downloadRequest)
|
||||
if err != nil {
|
||||
log.Printf("json decode error: %v\n", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
pathFileNameRes, err := processor.Process(downloadRequest.Date, downloadRequest.StartTime, downloadRequest.EndTime)
|
||||
if err != nil {
|
||||
log.Printf("process error: %v\n", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "video/mp4")
|
||||
// Разрешаем частичную загрузку (поддержка перемотки)
|
||||
w.Header().Set("Accept-Ranges", "bytes")
|
||||
|
||||
http.ServeFile(w, r, pathFileNameRes)
|
||||
}
|
||||
|
||||
// HLS processes Download request.
|
||||
func HLS(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("new hls request: %+v\n", r)
|
||||
|
||||
path := "/home/psa/GoRepository/data/1280x720/"
|
||||
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
http.StripPrefix("/hls", http.FileServer(http.Dir(path))).ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// ListVodsHandler returns the list of VOD locations.
|
||||
//
|
||||
// This method allows to get the list of all VOD locations. VOD location is a virtual filepath used to place files for
|
||||
// VOD (Video on Demand) broadcasting.
|
||||
func ListVodsHandler(c *fiber.Ctx) error {
|
||||
// Read directory.
|
||||
entries, err := os.ReadDir(config.DirData)
|
||||
if err != nil {
|
||||
log.Println("StatusInternalServerError")
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// Filter only folders.
|
||||
var dirs []string
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
dirs = append(dirs, entry.Name())
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the Response.
|
||||
VodsRes := ListVodsResponse{
|
||||
EstimatedCount: len(dirs),
|
||||
Vods: dirs,
|
||||
}
|
||||
|
||||
// Write header and code response.
|
||||
return c.JSON(VodsRes)
|
||||
}
|
||||
|
||||
// ConfigVodsHandler returns configuration of the requested VOD location.
|
||||
//
|
||||
// This method allows to get a single VOD location.
|
||||
func ConfigVodsHandler(c *fiber.Ctx) error {
|
||||
// Read camera id.
|
||||
id := c.Params("id")
|
||||
|
||||
// Get resolutions.
|
||||
resolutions, err := storage.GetResolutions(id)
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
// Calculate response fields.
|
||||
|
||||
// Create path to first resolution.
|
||||
resDir := fmt.Sprintf("%s/%s/%s", config.DirData, id, resolutions[0])
|
||||
|
||||
// Read directory.
|
||||
entries, err := os.ReadDir(resDir)
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// Check if a folder has files that was not created or modified for last 5 minutes.
|
||||
disabled, err := Inactive5Minutes(entries)
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// Calculate the difference between first existing rec file and the last one in milliseconds.
|
||||
segmentDuration, err := recDurationMilliseconds(entries)
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// Prepare the Response.
|
||||
VodsRes := ConfigVodsResponse{
|
||||
Prefix: id,
|
||||
AutoMbr: false, // Always false. Temporary.
|
||||
Disabled: disabled,
|
||||
SegmentDuration: segmentDuration,
|
||||
AddAudioOnly: false, // Always false. Temporary.
|
||||
Provider: "Insit",
|
||||
}
|
||||
|
||||
// Write header and code response.
|
||||
return c.JSON(VodsRes)
|
||||
}
|
||||
|
||||
// DelVodsHandler delete archive of the requested VOD location.
|
||||
//
|
||||
// This method delete a single VOD location by its prefix.
|
||||
func DelVodsHandler(c *fiber.Ctx) error {
|
||||
// Read camera id.
|
||||
id := c.Params("id")
|
||||
|
||||
err := os.Remove(fmt.Sprintf("%s/%s", config.DirData, id))
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
return c.SendStatus(fiber.StatusNoContent)
|
||||
}
|
||||
|
||||
// ListFilesVodsHandler returns the list of all files and folders in archive for a specific VOD location.
|
||||
//
|
||||
// This method allows to get the list of all files and folders for a specific VOD location.
|
||||
func ListFilesVodsHandler(c *fiber.Ctx) error {
|
||||
// Read camera id.
|
||||
id := c.Params("id")
|
||||
|
||||
// Create map for response.
|
||||
files := make(map[string][]string)
|
||||
|
||||
// Get resolutions.
|
||||
resolutions, err := storage.GetResolutions(id)
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
for _, resolution := range resolutions {
|
||||
// Create path to the resolutions.
|
||||
resDir := fmt.Sprintf("%s/%s/%s", config.DirData, id, resolution)
|
||||
|
||||
// Read directory.
|
||||
entries, err := os.ReadDir(resDir)
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// Create slice for files in folders.
|
||||
filesInFolder := make([]string, 0)
|
||||
|
||||
// Add all files to the slice with files.
|
||||
for _, entry := range entries {
|
||||
filesInFolder = append(filesInFolder, entry.Name())
|
||||
}
|
||||
|
||||
// Add resolution and all files to the response map.
|
||||
files[resolution] = filesInFolder
|
||||
}
|
||||
|
||||
// Prepare the Response.
|
||||
vodsRes := ListVodsResponse{
|
||||
EstimatedCount: len(files),
|
||||
Files: files,
|
||||
}
|
||||
|
||||
// Write header and code response.
|
||||
return c.JSON(vodsRes)
|
||||
}
|
||||
|
||||
// SingleVodsHandler returns a specific file in archive for a specific resolution and VOD location.
|
||||
//
|
||||
// This method allows to get a single VOD file.
|
||||
func SingleVodsHandler(c *fiber.Ctx) error {
|
||||
// Read camera id, res, filename.
|
||||
id := c.Params("id")
|
||||
res := c.Params("res")
|
||||
file := c.Params("file")
|
||||
|
||||
// Calculate file size in bytes.
|
||||
FileBytes, err := storage.FileBytes(id, res, file)
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
dur, tracks, err := storage.GetDurAndTracks(id, res, file)
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
media := MediaSingleVodsResponse{
|
||||
Tracks: tracks,
|
||||
Duration: dur,
|
||||
Provider: "Insit",
|
||||
Title: id,
|
||||
}
|
||||
|
||||
// Prepare the Response.
|
||||
vodsRes := SingleVodsResponse{
|
||||
Name: file,
|
||||
Prefix: id,
|
||||
Url: c.OriginalURL(),
|
||||
Folder: res,
|
||||
Bytes: FileBytes,
|
||||
MediaInfo: media,
|
||||
}
|
||||
|
||||
// Write header and code response.
|
||||
return c.JSON(vodsRes)
|
||||
}
|
||||
|
||||
// DelSingleVodsHandler deletes a VOD file by its name.
|
||||
//
|
||||
// This method deletes a VOD file by its name.
|
||||
func DelSingleVodsHandler(c *fiber.Ctx) error {
|
||||
// Read camera id, res, filename.
|
||||
id := c.Params("id")
|
||||
res := c.Params("res")
|
||||
file := c.Params("file")
|
||||
|
||||
if err := os.Remove(fmt.Sprintf("%s/%s/%s/%s", config.DirData, id, res, file)); err != nil {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
||||
return c.SendStatus(fiber.StatusNoContent)
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
const (
|
||||
ContextKeyUser = "user"
|
||||
)
|
||||
|
||||
func Auth() {
|
||||
app := fiber.New()
|
||||
|
||||
authStorage := &AuthStorage{map[string]User{}}
|
||||
authHandler := &AuthHandler{Storage: authStorage}
|
||||
userHandler := &UserHandler{Storage: authStorage}
|
||||
|
||||
// Группа обработчиков, которые доступны неавторизованным пользователям
|
||||
publicGroup := app.Group("")
|
||||
publicGroup.Post("/register", authHandler.Register)
|
||||
publicGroup.Post("/login", authHandler.Login)
|
||||
|
||||
// Группа обработчиков, которые требуют авторизации
|
||||
authorizedGroup := app.Group("")
|
||||
authorizedGroup.Use(jwtware.New(jwtware.Config{
|
||||
SigningKey: jwtware.SigningKey{
|
||||
Key: JwtSecretKey,
|
||||
},
|
||||
ContextKey: ContextKeyUser,
|
||||
}))
|
||||
authorizedGroup.Get("/profile", userHandler.Profile)
|
||||
|
||||
logrus.Fatal(app.Listen(":8100"))
|
||||
}
|
||||
|
||||
type (
|
||||
// Обработчик HTTP-запросов на регистрацию и аутентификацию пользователей
|
||||
AuthHandler struct {
|
||||
Storage *AuthStorage
|
||||
}
|
||||
|
||||
// Хранилище зарегистрированных пользователей
|
||||
// Данные хранятся в оперативной памяти
|
||||
AuthStorage struct {
|
||||
Users map[string]User
|
||||
}
|
||||
|
||||
// Структура данных с информацией о пользователе
|
||||
User struct {
|
||||
Email string
|
||||
Name string
|
||||
password string
|
||||
}
|
||||
)
|
||||
|
||||
// Структура HTTP-запроса на регистрацию пользователя
|
||||
type RegisterRequest struct {
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// Обработчик HTTP-запросов на регистрацию пользователя
|
||||
func (h *AuthHandler) Register(c *fiber.Ctx) error {
|
||||
regReq := RegisterRequest{}
|
||||
if err := c.BodyParser(®Req); err != nil {
|
||||
return fmt.Errorf("body parser: %w", err)
|
||||
}
|
||||
|
||||
// Проверяем, что пользователь с таким email еще не зарегистрирован
|
||||
if _, exists := h.Storage.Users[regReq.Email]; exists {
|
||||
return errors.New("the user already exists")
|
||||
}
|
||||
|
||||
// Сохраняем в память нового зарегистрированного пользователя
|
||||
h.Storage.Users[regReq.Email] = User{
|
||||
Email: regReq.Email,
|
||||
Name: regReq.Name,
|
||||
password: regReq.Password,
|
||||
}
|
||||
|
||||
return c.SendStatus(fiber.StatusCreated)
|
||||
}
|
||||
|
||||
// Структура HTTP-запроса на вход в аккаунт
|
||||
type LoginRequest struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// Структура HTTP-ответа на вход в аккаунт
|
||||
// В ответе содержится JWT-токен авторизованного пользователя
|
||||
type LoginResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
}
|
||||
|
||||
var (
|
||||
errBadCredentials = errors.New("email or password is incorrect")
|
||||
)
|
||||
|
||||
// Секретный ключ для подписи JWT-токена
|
||||
// Необходимо хранить в безопасном месте
|
||||
var JwtSecretKey = []byte("very-secret-key")
|
||||
|
||||
// Обработчик HTTP-запросов на вход в аккаунт
|
||||
func (h *AuthHandler) Login(c *fiber.Ctx) error {
|
||||
regReq := LoginRequest{}
|
||||
if err := c.BodyParser(®Req); err != nil {
|
||||
return fmt.Errorf("body parser: %w", err)
|
||||
}
|
||||
|
||||
// Ищем пользователя в памяти приложения по электронной почте
|
||||
user, exists := h.Storage.Users[regReq.Email]
|
||||
// Если пользователь не найден, возвращаем ошибку
|
||||
if !exists {
|
||||
return errBadCredentials
|
||||
}
|
||||
// Если пользователь найден, но у него другой пароль, возвращаем ошибку
|
||||
if user.password != regReq.Password {
|
||||
return errBadCredentials
|
||||
}
|
||||
|
||||
// Генерируем JWT-токен для пользователя,
|
||||
// который он будет использовать в будущих HTTP-запросах
|
||||
|
||||
// Генерируем полезные данные, которые будут храниться в токене
|
||||
payload := jwt.MapClaims{
|
||||
"sub": user.Email,
|
||||
"exp": time.Now().Add(time.Hour * 72).Unix(),
|
||||
}
|
||||
|
||||
// Создаем новый JWT-токен и подписываем его по алгоритму HS256
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, payload)
|
||||
|
||||
t, err := token.SignedString(JwtSecretKey)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("JWT token signing")
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return c.JSON(LoginResponse{AccessToken: t})
|
||||
}
|
||||
|
||||
// Обработчик HTTP-запросов, которые связаны с пользователем
|
||||
type UserHandler struct {
|
||||
Storage *AuthStorage
|
||||
}
|
||||
|
||||
// Структура HTTP-ответа с информацией о пользователе
|
||||
type ProfileResponse struct {
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func jwtPayloadFromRequest(c *fiber.Ctx) (jwt.MapClaims, bool) {
|
||||
jwtToken, ok := c.Context().Value(ContextKeyUser).(*jwt.Token)
|
||||
if !ok {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"jwt_token_context_value": c.Context().Value(ContextKeyUser),
|
||||
}).Error("wrong type of JWT token in context")
|
||||
return nil, false
|
||||
}
|
||||
|
||||
payload, ok := jwtToken.Claims.(jwt.MapClaims)
|
||||
if !ok {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"jwt_token_claims": jwtToken.Claims,
|
||||
}).Error("wrong type of JWT token claims")
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return payload, true
|
||||
}
|
||||
|
||||
// Обработчик HTTP-запросов на получение информации о пользователе
|
||||
func (h *UserHandler) Profile(c *fiber.Ctx) error {
|
||||
jwtPayload, ok := jwtPayloadFromRequest(c)
|
||||
if !ok {
|
||||
return c.SendStatus(fiber.StatusUnauthorized)
|
||||
}
|
||||
|
||||
userInfo, ok := h.Storage.Users[jwtPayload["sub"].(string)]
|
||||
if !ok {
|
||||
return errors.New("user not found")
|
||||
}
|
||||
|
||||
return c.JSON(ProfileResponse{
|
||||
Email: userInfo.Email,
|
||||
Name: userInfo.Name,
|
||||
})
|
||||
}
|
237
reader/internal/web/https/handlersHTTP/handlers.go
Normal file
237
reader/internal/web/https/handlersHTTP/handlers.go
Normal file
@ -0,0 +1,237 @@
|
||||
package handlersHTTP
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.insit.tech/psa/rtsp_reader-writer/reader/internal/config"
|
||||
"git.insit.tech/psa/rtsp_reader-writer/reader/internal/processor"
|
||||
"git.insit.tech/psa/rtsp_reader-writer/reader/internal/web/handlers"
|
||||
"git.insit.tech/psa/rtsp_reader-writer/writer/pkg/storage"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Download processes Download request.
|
||||
func Download(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("new download request: %+v\n", r)
|
||||
|
||||
downloadRequest := handlers.VideoRequest{}
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(&downloadRequest)
|
||||
if err != nil {
|
||||
log.Printf("json decode error: %v\n", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
pathFileNameRes, err := processor.Process(downloadRequest.Date, downloadRequest.StartTime, downloadRequest.EndTime)
|
||||
if err != nil {
|
||||
log.Printf("process error: %v\n", err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "video/mp4")
|
||||
// Разрешаем частичную загрузку (поддержка перемотки)
|
||||
w.Header().Set("Accept-Ranges", "bytes")
|
||||
|
||||
http.ServeFile(w, r, pathFileNameRes)
|
||||
}
|
||||
|
||||
// HLS processes Download request.
|
||||
func HLS(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("new hls request: %+v\n", r)
|
||||
|
||||
path := "/home/psa/GoRepository/data/1280x720/"
|
||||
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
http.StripPrefix("/hls", http.FileServer(http.Dir(path))).ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// ConfigVodsHandler returns configuration of the requested VOD location.
|
||||
//
|
||||
// This method allows to get a single VOD location.
|
||||
func ConfigVodsHandler(c *fiber.Ctx) error {
|
||||
// Read camera id.
|
||||
id := c.Params("id")
|
||||
|
||||
// Get resolutions.
|
||||
resolutions, err := storage.GetResolutions(id)
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
// Calculate response fields.
|
||||
|
||||
// Create path to first resolution.
|
||||
resDir := fmt.Sprintf("%s/%s/%s", config.DirData, id, resolutions[0])
|
||||
|
||||
// Read directory.
|
||||
entries, err := os.ReadDir(resDir)
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// Check if a folder has files that was not created or modified for last 5 minutes.
|
||||
disabled, err := handlers.Inactive5Minutes(entries)
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// Calculate the difference between first existing rec file and the last one in milliseconds.
|
||||
segmentDuration, err := handlers.RecDurationMilliseconds(entries)
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// Prepare the Response.
|
||||
VodsRes := handlers.ConfigVodsResponse{
|
||||
Prefix: id,
|
||||
AutoMbr: false, // Always false. Temporary.
|
||||
Disabled: disabled,
|
||||
SegmentDuration: segmentDuration,
|
||||
AddAudioOnly: false, // Always false. Temporary.
|
||||
Provider: "Insit",
|
||||
}
|
||||
|
||||
// Write header and code response.
|
||||
return c.JSON(VodsRes)
|
||||
}
|
||||
|
||||
// DelVodsHandler delete archive of the requested VOD location.
|
||||
//
|
||||
// This method delete a single VOD location by its prefix.
|
||||
func DelVodsHandler(c *fiber.Ctx) error {
|
||||
// Read camera id.
|
||||
id := c.Params("id")
|
||||
|
||||
err := os.Remove(fmt.Sprintf("%s/%s", config.DirData, id))
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
return c.SendStatus(fiber.StatusNoContent)
|
||||
}
|
||||
|
||||
// ListFilesVodsHandler returns the list of all files and folders in archive for a specific VOD location.
|
||||
//
|
||||
// This method allows to get the list of all files and folders for a specific VOD location.
|
||||
func ListFilesVodsHandler(c *fiber.Ctx) error {
|
||||
// Read camera id.
|
||||
id := c.Params("id")
|
||||
|
||||
// Create map for response.
|
||||
files := make(map[string][]string)
|
||||
|
||||
// Get resolutions.
|
||||
resolutions, err := storage.GetResolutions(id)
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
for _, resolution := range resolutions {
|
||||
// Create path to the resolutions.
|
||||
resDir := fmt.Sprintf("%s/%s/%s", config.DirData, id, resolution)
|
||||
|
||||
// Read directory.
|
||||
entries, err := os.ReadDir(resDir)
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// Create slice for files in folders.
|
||||
filesInFolder := make([]string, 0)
|
||||
|
||||
// Add all files to the slice with files.
|
||||
for _, entry := range entries {
|
||||
filesInFolder = append(filesInFolder, entry.Name())
|
||||
}
|
||||
|
||||
// Add resolution and all files to the response map.
|
||||
files[resolution] = filesInFolder
|
||||
}
|
||||
|
||||
// Prepare the Response.
|
||||
vodsRes := handlers.ListVodsResponse{
|
||||
EstimatedCount: len(files),
|
||||
Files: files,
|
||||
}
|
||||
|
||||
// Write header and code response.
|
||||
return c.JSON(vodsRes)
|
||||
}
|
||||
|
||||
// SingleVodsHandler returns a specific file in archive for a specific resolution and VOD location.
|
||||
//
|
||||
// This method allows to get a single VOD file.
|
||||
func SingleVodsHandler(c *fiber.Ctx) error {
|
||||
// Read camera id, res, filename.
|
||||
id := c.Params("id")
|
||||
res := c.Params("res")
|
||||
file := c.Params("file")
|
||||
|
||||
// Calculate file size in bytes.
|
||||
FileBytes, err := storage.FileBytes(id, res, file)
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusBadRequest)
|
||||
}
|
||||
|
||||
dur, tracks, err := storage.GetDurAndTracks(id, res, file)
|
||||
if err != nil {
|
||||
return c.SendStatus(fiber.StatusInternalServerError)
|
||||
}
|
||||
|
||||
media := handlers.MediaSingleVodsResponse{
|
||||
Tracks: tracks,
|
||||
Duration: dur,
|
||||
Provider: "Insit",
|
||||
Title: id,
|
||||
}
|
||||
|
||||
// Prepare the Response.
|
||||
vodsRes := handlers.SingleVodsResponse{
|
||||
Name: file,
|
||||
Prefix: id,
|
||||
Url: c.OriginalURL(),
|
||||
Folder: res,
|
||||
Bytes: FileBytes,
|
||||
MediaInfo: media,
|
||||
}
|
||||
|
||||
// Write header and code response.
|
||||
return c.JSON(vodsRes)
|
||||
}
|
||||
|
||||
// DelSingleVodsHandler deletes a VOD file by its name.
|
||||
//
|
||||
// This method deletes a VOD file by its name.
|
||||
func DelSingleVodsHandler(c *fiber.Ctx) error {
|
||||
// Read camera id, res, filename.
|
||||
id := c.Params("id")
|
||||
res := c.Params("res")
|
||||
file := c.Params("file")
|
||||
|
||||
if err := os.Remove(fmt.Sprintf("%s/%s/%s/%s", config.DirData, id, res, file)); err != nil {
|
||||
return c.SendStatus(fiber.StatusNotFound)
|
||||
}
|
||||
|
||||
return c.SendStatus(fiber.StatusNoContent)
|
||||
}
|
||||
|
||||
/*
|
||||
// FileHandler обработчик для работы с файлами
|
||||
func FileHandler(c *fiber.Ctx) error {
|
||||
// Если запрос содержит session_id - получаем файл
|
||||
sessionData := c.Locals(ContextKeySession).(*SessionData)
|
||||
|
||||
// Логика получения файла
|
||||
fileContent, err := getFileContent(sessionData.FileName)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusNotFound).SendString("File not found")
|
||||
}
|
||||
|
||||
return c.Send(fileContent)
|
||||
}
|
||||
*/
|
59
reader/internal/web/quic/quic.go
Normal file
59
reader/internal/web/quic/quic.go
Normal file
@ -0,0 +1,59 @@
|
||||
package quic
|
||||
|
||||
/*
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"git.insit.tech/psa/rtsp_reader-writer/reader/internal/web/quic/handlersQUIC"
|
||||
"github.com/quic-go/quic-go/http3"
|
||||
)
|
||||
|
||||
// SetupQuicServer starts QUIC protocol using HTTP/3.
|
||||
func SetupQuicServer() {
|
||||
mux := http.NewServeMux()
|
||||
|
||||
// Группа обработчиков, которые доступны неавторизованным пользователям
|
||||
mux.HandleFunc("POST /register", handlersQUIC.Register)
|
||||
mux.HandleFunc("POST /login", handlersQUIC.Login)
|
||||
|
||||
// Группа обработчиков, которые требуют авторизации
|
||||
//authorizedGroup := app.Group("")
|
||||
//authorizedGroup.Use(handlersQUIC.CheckJWT, handlersQUIC.CheckSessionID, handlersQUIC.CreateSessionID)
|
||||
//mux.HandleFunc("GET /profile", userHandlerQUIC.Profile)
|
||||
//
|
||||
//// API Flussonic Media Server adapted handlers.
|
||||
//mux.HandleFunc("GET /vods/:id/:res/:file", handlersQUIC.SingleVodsHandler)
|
||||
//mux.HandleFunc("DELETE /vods/:id/:res/:file", handlersQUIC.DelSingleVodsHandler)
|
||||
//mux.HandleFunc("GET /vods/:id/files", handlersQUIC.ListFilesVodsHandler)
|
||||
//mux.HandleFunc("DELETE /vods/:id", handlersQUIC.DelVodsHandler)
|
||||
//mux.HandleFunc("GET /vods/:id", handlersQUIC.ConfigVodsHandler)
|
||||
mux.HandleFunc("GET /vods", handlersQUIC.ListVodsHandler)
|
||||
|
||||
server := &http3.Server{
|
||||
Addr: ":443",
|
||||
Handler: mux,
|
||||
}
|
||||
|
||||
http.ListenAndServe("", mux)
|
||||
|
||||
if err := server.ListenAndServeTLS("fullchain.pem", "privkey.pem"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetTLSConfig
|
||||
func GetTLSConfig() *tls.Config {
|
||||
cert, err := tls.LoadX509KeyPair("fullchain.pem", "privkey.pem")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
NextProtos: []string{"h3", "h2", "http/1.1"},
|
||||
MinVersion: tls.VersionTLS13,
|
||||
}
|
||||
}
|
||||
*/
|
Loading…
x
Reference in New Issue
Block a user