280 lines
9.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handlers
import (
"encoding/json"
"errors"
"git.insit.tech/psa/rtsp_reader-writer/reader/internal/config"
"github.com/golang-jwt/jwt/v5"
"github.com/sirupsen/logrus"
"log"
"net/http"
"os"
"strconv"
"strings"
"time"
)
// Структура HTTP-запроса на регистрацию пользователя
type registerRequest struct {
Email string `json:"email"`
Name string `json:"name"`
Password string `json:"password"`
}
// Структура 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")
)
// Структура HTTP-ответа с информацией о пользователе
type ProfileResponse struct {
Email string `json:"email"`
Name string `json:"name"`
}
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"`
}
// Обработчик HTTP-запросов на регистрацию пользователя
func Register(w http.ResponseWriter, r *http.Request) {
regReq := registerRequest{}
if err := json.NewDecoder(r.Body).Decode(&regReq); err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
// Проверяем, что пользователь с таким email еще не зарегистрирован
if _, exists := config.Storage.Users[regReq.Email]; exists {
w.WriteHeader(http.StatusBadRequest)
return
}
// Сохраняем в память нового зарегистрированного пользователя
config.Storage.Users[regReq.Email] = config.User{
Email: regReq.Email,
Name: regReq.Name,
Password: regReq.Password,
}
w.WriteHeader(http.StatusCreated)
}
// Обработчик HTTP-запросов на вход в аккаунт
func Login(w http.ResponseWriter, r *http.Request) {
regReq := loginRequest{}
if err := json.NewDecoder(r.Body).Decode(&regReq); err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
// Ищем пользователя в памяти приложения по электронной почте
user, exists := config.Storage.Users[regReq.Email]
// Если пользователь не найден, возвращаем ошибку
if !exists {
w.WriteHeader(http.StatusBadRequest)
return
}
// Если пользователь найден, но у него другой пароль, возвращаем ошибку
if user.Password != regReq.Password {
w.WriteHeader(http.StatusBadRequest)
return
}
// Генерируем JWT-токен для пользователя,
// который он будет использовать в будущих HTTP-запросах
// Генерируем полезные данные, которые будут храниться в токене
payload := jwt.MapClaims{
"sub": user.Email,
"exp": time.Now().Add(time.Hour * 24).Unix(),
}
// Создаем новый JWT-токен и подписываем его по алгоритму HS256
token := jwt.NewWithClaims(jwt.SigningMethodHS256, payload)
t, err := token.SignedString(config.JwtSecretKey)
if err != nil {
logrus.WithError(err).Error("JWT token signing")
w.WriteHeader(http.StatusInternalServerError)
return
}
res, err := json.Marshal(loginResponse{AccessToken: t})
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
if _, err = w.Write(res); err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
//w.WriteHeader(http.StatusOK)
}
// 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
}
// ListVodsHandlerLogic implements main logic of handler ListVodsHandler.
func ListVodsHandlerLogic() (ListVodsResponse, error) {
// Read directory.
entries, err := os.ReadDir(config.DirData)
if err != nil {
return ListVodsResponse{}, err
}
// 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,
}
return VodsRes, nil
}
// 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() http.Handler {
log.Println("before return ListVodsHandler")
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Println("hello fron ListVodsHandler")
// Prepare the Response.
VodsRes, err := ListVodsHandlerLogic()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
// Write header and code response.
w.Header().Set("Content-Type", "application/json")
if err = json.NewEncoder(w).Encode(VodsRes); err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
log.Println("hello fron ListVodsHandlerLogic: StatusOK")
})
}