Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only one streaming key for each course #1242

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4e82b30
stream keys are read from course if defined
Mjaethers Nov 2, 2023
7cedbb6
generete course wide stream key when course is created
Mjaethers Nov 2, 2023
6c6d79e
added api routes for regenerating strream keys
Mjaethers Nov 14, 2023
527546d
updated tum live starter db
Mjaethers Nov 15, 2023
2701804
update stream in streamsDao now writes to db
Mjaethers Nov 15, 2023
792d4be
added frontend components to regenerate keys
Mjaethers Nov 16, 2023
ddc403d
stream server and key does not contain stream name
Mjaethers Nov 17, 2023
cd611b9
worker no longer identifies stream by name in ingest url
Mjaethers Nov 17, 2023
26db4c5
added 30 min buffer to finding stream by time
Mjaethers Nov 20, 2023
8a21758
start new runner implementation
joschahenningsen Oct 2, 2023
8beb8dd
stream keys are read from course if defined
Mjaethers Nov 2, 2023
03d10a7
Revert "stream keys are read from course if defined"
Mjaethers Nov 21, 2023
8812ceb
stream keys are read from course if defined
Mjaethers Nov 2, 2023
1369698
generete course wide stream key when course is created
Mjaethers Nov 2, 2023
70f0633
added api routes for regenerating strream keys
Mjaethers Nov 14, 2023
dd8069f
updated tum live starter db
Mjaethers Nov 15, 2023
c6499c4
update stream in streamsDao now writes to db
Mjaethers Nov 15, 2023
670602f
added frontend components to regenerate keys
Mjaethers Nov 16, 2023
8e1f327
stream server and key does not contain stream name
Mjaethers Nov 17, 2023
8f5e2dc
worker no longer identifies stream by name in ingest url
Mjaethers Nov 17, 2023
2fc6088
added 30 min buffer to finding stream by time
Mjaethers Nov 20, 2023
00cd3d1
start new runner implementation
joschahenningsen Oct 2, 2023
8e0edb0
rebased onto current dev branch
Mjaethers Nov 2, 2023
bb5e91c
fixed merge errors
Mjaethers Nov 21, 2023
ea44efc
updated mocks
Mjaethers Nov 28, 2023
02f1ef2
added confirm dialogue to regenerating all stream keys of course
Mjaethers Nov 28, 2023
f449030
added button to restore stream key
Mjaethers Nov 29, 2023
459af5a
Merge branch 'TUM-Dev:dev' into 124-require-only-one-streaming-key-fo…
Mjaethers Dec 12, 2023
5f6410a
linted JS
Mjaethers Dec 12, 2023
b0aba26
fixed ci
Mjaethers Dec 14, 2023
9dc1563
ci bypass autobuild
Mjaethers Dec 14, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ jobs:

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
#- name: Autobuild
# uses: github/codeql-action/autobuild@v2

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
Expand All @@ -54,7 +54,7 @@ jobs:
# and modify them (or add more) to build your code if your project
# uses a compiled language

#- run: |
- run: make all
# make bootstrap
# make release

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/go-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
test:
strategy:
matrix:
go-version: [ 1.20.x ]
go-version: [ 1.21.x ]
os: [ ubuntu-latest ]
runs-on: ${{ matrix.os }}
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/setup-go@v4
with:
go-version: 1.19
go-version: 1.21
- uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
Expand Down
4 changes: 2 additions & 2 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ linters:
fast: false

run:
go: '1.19'
go: '1.21'
timeout: 10m
skip-dirs:
- node_modules
Expand Down Expand Up @@ -67,7 +67,7 @@ linters-settings:
- name: modifies-value-receiver
gofumpt:
extra-rules: false
lang-version: "1.19"
lang-version: "1.21"

issues:
max-issues-per-linter: 0
Expand Down
4 changes: 3 additions & 1 deletion .idea/TUM-Live-Backend.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 11 additions & 1 deletion api/courseimport.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ func (r lectureHallRoutes) postSchedule(c *gin.Context) {
Streams: nil,
Users: nil,
Token: token,
StreamKey: strings.ReplaceAll(uuid.NewV4().String(), "-", "")[:15],
}

var streams []model.Stream
Expand All @@ -98,12 +99,21 @@ func (r lectureHallRoutes) postSchedule(c *gin.Context) {
if err == nil {
eventID = uint(eventIDInt)
}

// When defined use course wide stream key
var streamKey string
if course.StreamKey == "" {
streamKey = strings.ReplaceAll(uuid.NewV4().String(), "-", "")[:15]
} else {
streamKey = course.StreamKey
}

streams = append(streams, model.Stream{
Start: event.Start,
End: event.End,
RoomName: event.RoomName,
LectureHallID: lectureHall.ID,
StreamKey: strings.ReplaceAll(uuid.NewV4().String(), "-", "")[:15],
StreamKey: streamKey,
TUMOnlineEventID: eventID,
})
}
Expand Down
36 changes: 33 additions & 3 deletions api/courses.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ func configGinCourseRouter(router *gin.Engine, daoWrapper dao.DaoWrapper) {
courses.PUT("/updateDescription/:streamID", routes.updateDescription)
courses.DELETE("/deleteLectureSeries/:streamID", routes.deleteLectureSeries)
courses.POST("/submitCut", routes.submitCut)
courses.POST("/regenerateKey", routes.regenerateCourseKey)

courses.POST("/addUnit", routes.addUnit)
courses.POST("/deleteUnit/:unitID", routes.deleteUnit)
Expand Down Expand Up @@ -1234,8 +1235,13 @@ func (r coursesRoutes) createLecture(c *gin.Context) {
for _, date := range req.DateSeries {
endTime := date.Add(time.Minute * time.Duration(req.Duration))

streamKey := uuid.NewV4().String()
streamKey = strings.ReplaceAll(streamKey, "-", "")
// When defined use course wide stream key
var streamKey string
if tumLiveContext.Course.StreamKey == "" {
streamKey = strings.ReplaceAll(uuid.NewV4().String(), "-", "")
} else {
streamKey = tumLiveContext.Course.StreamKey
}

lecture := model.Stream{
Name: req.Title,
Expand Down Expand Up @@ -1391,6 +1397,7 @@ func (r coursesRoutes) createCourse(c *gin.Context) {
ChatEnabled: req.EnChat,
Visibility: req.Access,
Streams: []model.Stream{},
StreamKey: strings.ReplaceAll(uuid.NewV4().String(), "-", ""),
}
if tumLiveContext.User.Role != model.AdminType {
course.Admins = []model.User{*tumLiveContext.User}
Expand Down Expand Up @@ -1484,8 +1491,31 @@ func (r coursesRoutes) deleteCourse(c *gin.Context) {
dao.Cache.Clear()
}

// regenerateCourseKey updates the stream key of the course and updates the key of all the streams
func (r coursesRoutes) regenerateCourseKey(c *gin.Context) {
ctx := c.MustGet("TUMLiveContext").(tools.TUMLiveContext)
course := *ctx.Course

course.StreamKey = strings.ReplaceAll(uuid.NewV4().String(), "-", "")
err := r.DaoWrapper.CoursesDao.UpdateCourse(c, course)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, "could not update course")
return
}

for _, s := range course.Streams {
s.StreamKey = course.StreamKey

err := r.DaoWrapper.StreamsDao.UpdateStream(s)
// Log error but continue on remaining streams
if err != nil {
log.Error("could not modify stream key ", err)
}
}
}

type createCourseRequest struct {
Access string //enrolled, public, hidden or loggedin
Access string //enrolled, public, hidden or logged in
CourseID string
EnChat bool
EnDL bool
Expand Down
73 changes: 73 additions & 0 deletions api/runner_grpc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package api

import (
"context"
"database/sql"
"github.com/TUM-Dev/gocast/dao"
"github.com/TUM-Dev/gocast/model"
log "github.com/sirupsen/logrus"
"github.com/tum-dev/gocast/runner/protobuf"
"google.golang.org/grpc"
"google.golang.org/grpc/keepalive"
"google.golang.org/grpc/reflection"
"net"
"time"
)

var _ protobuf.FromRunnerServer = (*GrpcRunnerServer)(nil)

type GrpcRunnerServer struct {
protobuf.UnimplementedFromRunnerServer

dao.DaoWrapper
}

func (g GrpcRunnerServer) Register(ctx context.Context, request *protobuf.RegisterRequest) (*protobuf.RegisterResponse, error) {
runner := model.Runner{
Hostname: request.Hostname,
Port: int(request.Port),
LastSeen: sql.NullTime{Valid: true, Time: time.Now()},
}
err := g.RunnerDao.Create(ctx, &runner)
if err != nil {
return nil, err
}
return &protobuf.RegisterResponse{}, nil
}

func (g GrpcRunnerServer) Heartbeat(ctx context.Context, request *protobuf.HeartbeatRequest) (*protobuf.HeartbeatResponse, error) {
//TODO implement me
panic("implement me")
}

func (g GrpcRunnerServer) RequestSelfStream(ctx context.Context, request *protobuf.SelfStreamRequest) (*protobuf.SelfStreamResponse, error) {
//TODO implement me
panic("implement me")
}

func (g GrpcRunnerServer) mustEmbedUnimplementedFromRunnerServer() {
//TODO implement me
panic("implement me")
}

func StartGrpcRunnerServer() {
lis, err := net.Listen("tcp", ":50056")
if err != nil {
log.WithError(err).Error("Failed to init grpc server")
return
}
grpcServer := grpc.NewServer(grpc.KeepaliveParams(keepalive.ServerParameters{
MaxConnectionIdle: time.Minute,
MaxConnectionAge: time.Minute * 5,
MaxConnectionAgeGrace: time.Second * 5,
Time: time.Minute * 10,
Timeout: time.Second * 20,
}))
protobuf.RegisterFromRunnerServer(grpcServer, &GrpcRunnerServer{DaoWrapper: dao.NewDaoWrapper()})
reflection.Register(grpcServer)
go func() {
if err = grpcServer.Serve(lis); err != nil {
log.WithError(err).Errorf("Can't serve grpc")
}
}()
}
29 changes: 29 additions & 0 deletions api/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ func configGinStreamRestRouter(router *gin.Engine, daoWrapper dao.DaoWrapper) {
streamById.GET("/subtitles/:lang", routes.getSubtitles)

streamById.GET("/playlist", routes.getStreamPlaylist)
streamById.POST("/regenerateKey", routes.regenerateKey)
streamById.POST("/restoreKey", routes.restoreKey)

thumbs := streamById.Group("/thumbs")
{
Expand Down Expand Up @@ -839,6 +841,33 @@ func (r streamRoutes) updateStreamVisibility(c *gin.Context) {
}
}

// regenerateKey regenerates the key for a stream.
func (r streamRoutes) regenerateKey(c *gin.Context) {
ctx := c.MustGet("TUMLiveContext").(tools.TUMLiveContext)
stream := *ctx.Stream

stream.StreamKey = strings.ReplaceAll(uuid.NewV4().String(), "-", "")
err := r.DaoWrapper.StreamsDao.UpdateStream(stream)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, "could not update stream")
return
}
}

// restoreKey restores the key for a stream to the course key
func (r streamRoutes) restoreKey(c *gin.Context) {
ctx := c.MustGet("TUMLiveContext").(tools.TUMLiveContext)
stream := *ctx.Stream
course := *ctx.Course

stream.StreamKey = course.StreamKey
err := r.DaoWrapper.StreamsDao.UpdateStream(stream)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, "could not update stream")
return
}
}

func (r streamRoutes) updateChatEnabled(c *gin.Context) {
stream, err := r.StreamsDao.GetStreamByID(context.Background(), c.Param("streamID"))
if err != nil {
Expand Down
14 changes: 5 additions & 9 deletions api/worker_grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ import (
"time"

go_anel_pwrctrl "github.com/RBG-TUM/go-anel-pwrctrl"
"github.com/getsentry/sentry-go"
"github.com/TUM-Dev/gocast/dao"
"github.com/TUM-Dev/gocast/model"
"github.com/TUM-Dev/gocast/tools"
"github.com/TUM-Dev/gocast/tools/camera"
"github.com/TUM-Dev/gocast/worker/pb"
"github.com/getsentry/sentry-go"
uuid "github.com/satori/go.uuid"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
Expand Down Expand Up @@ -128,22 +128,18 @@ func (s server) SendSelfStreamRequest(ctx context.Context, request *pb.SelfStrea
if request.StreamKey == "" {
return nil, errors.New("stream key empty")
}
stream, err := s.StreamsDao.GetStreamByKey(ctx, request.StreamKey)
stream, err := s.StreamsDao.GetStreamByKeyAndTime(ctx, request.StreamKey, time.Now())
if err != nil {
return nil, err
}
course, err := s.DaoWrapper.CoursesDao.GetCourseById(ctx, stream.CourseID)
if err != nil {
return nil, err
}
if request.CourseSlug != fmt.Sprintf("%s-%d", course.Slug, stream.ID) {
return nil, fmt.Errorf("bad stream name, should: %s, is: %s", fmt.Sprintf("%s-%d", course.Slug, stream.ID), request.CourseSlug)
}
// reject streams that are more than 30 minutes in the future or more than 30 minutes past
if !(time.Now().After(stream.Start.Add(time.Minute*-30)) && time.Now().Before(stream.End.Add(time.Minute*30))) {
log.WithFields(log.Fields{"streamId": stream.ID}).Warn("Stream rejected, time out of bounds")
return nil, errors.New("stream rejected")
if request.CourseSlug != fmt.Sprintf("%s", course.Slug) {
return nil, fmt.Errorf("bad stream name, should: %s, is: %s", fmt.Sprintf("%s", course.Slug), request.CourseSlug)
}

ingestServer, err := s.DaoWrapper.IngestServerDao.GetBestIngestServer()
if err != nil {
return nil, err
Expand Down
12 changes: 7 additions & 5 deletions cmd/tumlive/tumlive.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ package main

import (
"fmt"
"github.com/dgraph-io/ristretto"
"github.com/getsentry/sentry-go"
sentrygin "github.com/getsentry/sentry-go/gin"
"github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin"
"github.com/TUM-Dev/gocast/api"
"github.com/TUM-Dev/gocast/dao"
"github.com/TUM-Dev/gocast/model"
"github.com/TUM-Dev/gocast/tools"
"github.com/TUM-Dev/gocast/tools/tum"
"github.com/TUM-Dev/gocast/web"
"github.com/dgraph-io/ristretto"
"github.com/getsentry/sentry-go"
sentrygin "github.com/getsentry/sentry-go/gin"
"github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin"
"github.com/pkg/profile"
log "github.com/sirupsen/logrus"
"gorm.io/driver/mysql"
Expand All @@ -32,6 +32,7 @@ type initializer func()
var initializers = []initializer{
tools.LoadConfig,
api.ServeWorkerGRPC,
api.StartGrpcRunnerServer,
tools.InitBranding,
}

Expand Down Expand Up @@ -168,6 +169,7 @@ func main() {
&model.Subtitles{},
&model.TranscodingFailure{},
&model.Email{},
&model.Runner{},
)
if err != nil {
sentry.CaptureException(err)
Expand Down
2 changes: 2 additions & 0 deletions dao/dao_base.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type DaoWrapper struct {
SubtitlesDao
TranscodingFailureDao
EmailDao
RunnerDao RunnerDao
}

func NewDaoWrapper() DaoWrapper {
Expand Down Expand Up @@ -63,5 +64,6 @@ func NewDaoWrapper() DaoWrapper {
SubtitlesDao: NewSubtitlesDao(),
TranscodingFailureDao: NewTranscodingFailureDao(),
EmailDao: NewEmailDao(),
RunnerDao: NewRunnerDao(),
}
}
Loading
Loading