From 07cf3de268a4468a487adfce6c4127a57f72fc43 Mon Sep 17 00:00:00 2001 From: Joscha Henningsen Date: Mon, 2 Oct 2023 07:38:58 +0200 Subject: [PATCH 01/31] start new runner implementation --- .idea/TUM-Live-Backend.iml | 4 +- .idea/vcs.xml | 1 + api/runner_grpc.go | 73 +++ cmd/tumlive/tumlive.go | 12 +- dao/dao_base.go | 2 + dao/runner.go | 47 ++ go.work | 3 +- go.work.sum | 748 +++++++++++++++++++++----- mock_dao/runner.go | 79 +++ model/runner.go | 25 + runner/.gitignore | 1 + runner/Dockerfile | 27 + runner/Makefile | 36 ++ runner/actions/actions.go | 57 ++ runner/actions/prepare.go | 43 ++ runner/actions/stream.go | 97 ++++ runner/actions/transcode.go | 36 ++ runner/actions/upload.go | 15 + runner/cmd/runner/main.go | 49 ++ runner/entrypoint.sh | 4 + runner/go.mod | 19 + runner/go.sum | 33 ++ runner/handlers.go | 39 ++ runner/hls.go | 28 + runner/mediamtx.yml | 104 ++++ runner/pkg/logging/grpc.go | 19 + runner/pkg/logging/logging.go | 43 ++ runner/pkg/netutil/netutil.go | 16 + runner/protobuf/runner.pb.go | 850 ++++++++++++++++++++++++++++++ runner/protobuf/runner_grpc.pb.go | 303 +++++++++++ runner/runner.go | 244 +++++++++ runner/runner.proto | 70 +++ tools/stream-signing.go | 4 +- 33 files changed, 2980 insertions(+), 151 deletions(-) create mode 100644 api/runner_grpc.go create mode 100644 dao/runner.go create mode 100644 mock_dao/runner.go create mode 100644 model/runner.go create mode 100644 runner/.gitignore create mode 100644 runner/Dockerfile create mode 100644 runner/Makefile create mode 100644 runner/actions/actions.go create mode 100644 runner/actions/prepare.go create mode 100644 runner/actions/stream.go create mode 100644 runner/actions/transcode.go create mode 100644 runner/actions/upload.go create mode 100644 runner/cmd/runner/main.go create mode 100644 runner/entrypoint.sh create mode 100644 runner/go.mod create mode 100644 runner/go.sum create mode 100644 runner/handlers.go create mode 100644 runner/hls.go create mode 100644 runner/mediamtx.yml create mode 100644 runner/pkg/logging/grpc.go create mode 100644 runner/pkg/logging/logging.go create mode 100644 runner/pkg/netutil/netutil.go create mode 100644 runner/protobuf/runner.pb.go create mode 100644 runner/protobuf/runner_grpc.pb.go create mode 100644 runner/runner.go create mode 100644 runner/runner.proto diff --git a/.idea/TUM-Live-Backend.iml b/.idea/TUM-Live-Backend.iml index 8f9c84fa8..fa6749226 100644 --- a/.idea/TUM-Live-Backend.iml +++ b/.idea/TUM-Live-Backend.iml @@ -10,7 +10,9 @@ - + + + diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7f4..da8735dd0 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/api/runner_grpc.go b/api/runner_grpc.go new file mode 100644 index 000000000..68373cbe1 --- /dev/null +++ b/api/runner_grpc.go @@ -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") + } + }() +} diff --git a/cmd/tumlive/tumlive.go b/cmd/tumlive/tumlive.go index 9fa949cc0..533f428c7 100755 --- a/cmd/tumlive/tumlive.go +++ b/cmd/tumlive/tumlive.go @@ -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" @@ -32,6 +32,7 @@ type initializer func() var initializers = []initializer{ tools.LoadConfig, api.ServeWorkerGRPC, + api.StartGrpcRunnerServer, tools.InitBranding, } @@ -168,6 +169,7 @@ func main() { &model.Subtitles{}, &model.TranscodingFailure{}, &model.Email{}, + &model.Runner{}, ) if err != nil { sentry.CaptureException(err) diff --git a/dao/dao_base.go b/dao/dao_base.go index fc831d9d0..6f1888853 100644 --- a/dao/dao_base.go +++ b/dao/dao_base.go @@ -36,6 +36,7 @@ type DaoWrapper struct { SubtitlesDao TranscodingFailureDao EmailDao + RunnerDao RunnerDao } func NewDaoWrapper() DaoWrapper { @@ -63,5 +64,6 @@ func NewDaoWrapper() DaoWrapper { SubtitlesDao: NewSubtitlesDao(), TranscodingFailureDao: NewTranscodingFailureDao(), EmailDao: NewEmailDao(), + RunnerDao: NewRunnerDao(), } } diff --git a/dao/runner.go b/dao/runner.go new file mode 100644 index 000000000..682aa1944 --- /dev/null +++ b/dao/runner.go @@ -0,0 +1,47 @@ +package dao + +import ( + "context" + "github.com/TUM-Dev/gocast/model" + "gorm.io/gorm" + "gorm.io/gorm/clause" +) + +//go:generate mockgen -source=runner.go -destination ../mock_dao/runner.go + +type RunnerDao interface { + // Get Runner by hostname + Get(context.Context, string) (model.Runner, error) + + // Create a new Runner for the database + Create(context.Context, *model.Runner) error + + // Delete a Runner by hostname. + Delete(context.Context, string) error +} + +type runnerDao struct { + db *gorm.DB +} + +func NewRunnerDao() RunnerDao { + return runnerDao{db: DB} +} + +// Get a Runner by id. +func (d runnerDao) Get(c context.Context, hostname string) (res model.Runner, err error) { + return res, DB.WithContext(c).First(&res, "hostname = ?", hostname).Error +} + +// Create a Runner. +func (d runnerDao) Create(c context.Context, it *model.Runner) error { + return DB.WithContext(c).Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "hostname"}}, + UpdateAll: true, + }).Create(&it).Error +} + +// Delete a Runner by hostname. +func (d runnerDao) Delete(c context.Context, hostname string) error { + return DB.WithContext(c).Delete(&model.Runner{}, hostname).Error +} diff --git a/go.work b/go.work index 61b4b2a9a..74bb747de 100644 --- a/go.work +++ b/go.work @@ -1,8 +1,9 @@ -go 1.19 +go 1.21.1 use ( . ./worker ./worker/edge + runner vod-service ) diff --git a/go.work.sum b/go.work.sum index 20e0d67ff..b3668fae9 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,156 +1,620 @@ -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= -github.com/RBG-TUM/CAMPUSOnline v0.0.0-20230412070523-8db58ed5c0b4/go.mod h1:pcWaw3hQOKmvRfldxtPlYBGAFbWQXUU44+KcDYwqduc= -github.com/RBG-TUM/commons v0.0.0-20220406105618-030c095f6a1b/go.mod h1:Nw30dUekEb8ZrJwoGck0lILeVDCIX9dqJsEAPSOxBs0= -github.com/RBG-TUM/go-anel-pwrctrl v1.0.0/go.mod h1:6c2j1rcryE6BWphhJtGb+yXFIGRzmIXi+31TjE9Cft4= -github.com/TUM-Dev/CampusProxy/client v0.0.0-20230226120508-3e8bb2411921/go.mod h1:UuXuuqgljQbgtLAw5NY+VcThXAwO6UISn6U3s4TJx8k= -github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/antchfx/xmlquery v1.3.17/go.mod h1:Afkq4JIeXut75taLSuI31ISJ/zeq+3jG7TunF7noreA= -github.com/antchfx/xpath v1.2.4/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= -github.com/asticode/go-astikit v0.20.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0= -github.com/asticode/go-astikit v0.30.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0= -github.com/asticode/go-astikit v0.40.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0= -github.com/asticode/go-astisub v0.26.0/go.mod h1:WTkuSzFB+Bp7wezuSf2Oxulj5A8zu2zLRVFf6bIFQK8= -github.com/asticode/go-astits v1.8.0/go.mod h1:DkOWmBNQpnr9mv24KfZjq4JawCFX1FCqjLVGvO0DygQ= -github.com/asticode/go-astits v1.13.0/go.mod h1:QSHmknZ51pf6KJdHKZHJTLlMegIrhega3LPWz3ND/iI= -github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= -github.com/beevik/etree v1.2.0/go.mod h1:aiPf89g/1k3AShMVAzriilpcE4R/Vuor90y83zVZWFc= -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= -github.com/bytedance/sonic v1.10.0/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= +cloud.google.com/go v0.110.6 h1:8uYAkj3YHTP/1iwReuHPxLSbdcyc+dSBbzFMrVwDR6Q= +cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go/accessapproval v1.7.1 h1:/5YjNhR6lzCvmJZAnByYkfEgWjfAKwYP6nkuTk6nKFE= +cloud.google.com/go/accessapproval v1.7.1/go.mod h1:JYczztsHRMK7NTXb6Xw+dwbs/WnOJxbo/2mTI+Kgg68= +cloud.google.com/go/accesscontextmanager v1.8.1 h1:WIAt9lW9AXtqw/bnvrEUaE8VG/7bAAeMzRCBGMkc4+w= +cloud.google.com/go/accesscontextmanager v1.8.1/go.mod h1:JFJHfvuaTC+++1iL1coPiG1eu5D24db2wXCDWDjIrxo= +cloud.google.com/go/aiplatform v1.48.0 h1:M5davZWCTzE043rJCn+ZLW6hSxfG1KAx4vJTtas2/ec= +cloud.google.com/go/aiplatform v1.48.0/go.mod h1:Iu2Q7sC7QGhXUeOhAj/oCK9a+ULz1O4AotZiqjQ8MYA= +cloud.google.com/go/analytics v0.21.3 h1:TFBC1ZAqX9/jL56GEXdLrVe5vT3I22bDVWyDwZX4IEg= +cloud.google.com/go/analytics v0.21.3/go.mod h1:U8dcUtmDmjrmUTnnnRnI4m6zKn/yaA5N9RlEkYFHpQo= +cloud.google.com/go/apigateway v1.6.1 h1:aBSwCQPcp9rZ0zVEUeJbR623palnqtvxJlUyvzsKGQc= +cloud.google.com/go/apigateway v1.6.1/go.mod h1:ufAS3wpbRjqfZrzpvLC2oh0MFlpRJm2E/ts25yyqmXA= +cloud.google.com/go/apigeeconnect v1.6.1 h1:6u/jj0P2c3Mcm+H9qLsXI7gYcTiG9ueyQL3n6vCmFJM= +cloud.google.com/go/apigeeconnect v1.6.1/go.mod h1:C4awq7x0JpLtrlQCr8AzVIzAaYgngRqWf9S5Uhg+wWs= +cloud.google.com/go/apigeeregistry v0.7.1 h1:hgq0ANLDx7t2FDZDJQrCMtCtddR/pjCqVuvQWGrQbXw= +cloud.google.com/go/apigeeregistry v0.7.1/go.mod h1:1XgyjZye4Mqtw7T9TsY4NW10U7BojBvG4RMD+vRDrIw= +cloud.google.com/go/appengine v1.8.1 h1:J+aaUZ6IbTpBegXbmEsh8qZZy864ZVnOoWyfa1XSNbI= +cloud.google.com/go/appengine v1.8.1/go.mod h1:6NJXGLVhZCN9aQ/AEDvmfzKEfoYBlfB80/BHiKVputY= +cloud.google.com/go/area120 v0.8.1 h1:wiOq3KDpdqXmaHzvZwKdpoM+3lDcqsI2Lwhyac7stss= +cloud.google.com/go/area120 v0.8.1/go.mod h1:BVfZpGpB7KFVNxPiQBuHkX6Ed0rS51xIgmGyjrAfzsg= +cloud.google.com/go/artifactregistry v1.14.1 h1:k6hNqab2CubhWlGcSzunJ7kfxC7UzpAfQ1UPb9PDCKI= +cloud.google.com/go/artifactregistry v1.14.1/go.mod h1:nxVdG19jTaSTu7yA7+VbWL346r3rIdkZ142BSQqhn5E= +cloud.google.com/go/asset v1.14.1 h1:vlHdznX70eYW4V1y1PxocvF6tEwxJTTarwIGwOhFF3U= +cloud.google.com/go/asset v1.14.1/go.mod h1:4bEJ3dnHCqWCDbWJ/6Vn7GVI9LerSi7Rfdi03hd+WTQ= +cloud.google.com/go/assuredworkloads v1.11.1 h1:yaO0kwS+SnhVSTF7BqTyVGt3DTocI6Jqo+S3hHmCwNk= +cloud.google.com/go/assuredworkloads v1.11.1/go.mod h1:+F04I52Pgn5nmPG36CWFtxmav6+7Q+c5QyJoL18Lry0= +cloud.google.com/go/automl v1.13.1 h1:iP9iQurb0qbz+YOOMfKSEjhONA/WcoOIjt6/m+6pIgo= +cloud.google.com/go/automl v1.13.1/go.mod h1:1aowgAHWYZU27MybSCFiukPO7xnyawv7pt3zK4bheQE= +cloud.google.com/go/baremetalsolution v1.1.1 h1:0Ge9PQAy6cZ1tRrkc44UVgYV15nw2TVnzJzYsMHXF+E= +cloud.google.com/go/baremetalsolution v1.1.1/go.mod h1:D1AV6xwOksJMV4OSlWHtWuFNZZYujJknMAP4Qa27QIA= +cloud.google.com/go/batch v1.3.1 h1:uE0Q//W7FOGPjf7nuPiP0zoE8wOT3ngoIO2HIet0ilY= +cloud.google.com/go/batch v1.3.1/go.mod h1:VguXeQKXIYaeeIYbuozUmBR13AfL4SJP7IltNPS+A4A= +cloud.google.com/go/beyondcorp v1.0.0 h1:VPg+fZXULQjs8LiMeWdLaB5oe8G9sEoZ0I0j6IMiG1Q= +cloud.google.com/go/beyondcorp v1.0.0/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= +cloud.google.com/go/bigquery v1.53.0 h1:K3wLbjbnSlxhuG5q4pntHv5AEbQM1QqHKGYgwFIqOTg= +cloud.google.com/go/bigquery v1.53.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= +cloud.google.com/go/billing v1.16.0 h1:1iktEAIZ2uA6KpebC235zi/rCXDdDYQ0bTXTNetSL80= +cloud.google.com/go/billing v1.16.0/go.mod h1:y8vx09JSSJG02k5QxbycNRrN7FGZB6F3CAcgum7jvGA= +cloud.google.com/go/binaryauthorization v1.6.1 h1:cAkOhf1ic92zEN4U1zRoSupTmwmxHfklcp1X7CCBKvE= +cloud.google.com/go/binaryauthorization v1.6.1/go.mod h1:TKt4pa8xhowwffiBmbrbcxijJRZED4zrqnwZ1lKH51U= +cloud.google.com/go/certificatemanager v1.7.1 h1:uKsohpE0hiobx1Eak9jNcPCznwfB6gvyQCcS28Ah9E8= +cloud.google.com/go/certificatemanager v1.7.1/go.mod h1:iW8J3nG6SaRYImIa+wXQ0g8IgoofDFRp5UMzaNk1UqI= +cloud.google.com/go/channel v1.16.0 h1:dqRkK2k7Ll/HHeYGxv18RrfhozNxuTJRkspW0iaFZoY= +cloud.google.com/go/channel v1.16.0/go.mod h1:eN/q1PFSl5gyu0dYdmxNXscY/4Fi7ABmeHCJNf/oHmc= +cloud.google.com/go/cloudbuild v1.13.0 h1:YBbAWcvE4x6xPWTyS+OU4eiUpz5rCS3VCM/aqmfddPA= +cloud.google.com/go/cloudbuild v1.13.0/go.mod h1:lyJg7v97SUIPq4RC2sGsz/9tNczhyv2AjML/ci4ulzU= +cloud.google.com/go/clouddms v1.6.1 h1:rjR1nV6oVf2aNNB7B5uz1PDIlBjlOiBgR+q5n7bbB7M= +cloud.google.com/go/clouddms v1.6.1/go.mod h1:Ygo1vL52Ov4TBZQquhz5fiw2CQ58gvu+PlS6PVXCpZI= +cloud.google.com/go/cloudtasks v1.12.1 h1:cMh9Q6dkvh+Ry5LAPbD/U2aw6KAqdiU6FttwhbTo69w= +cloud.google.com/go/cloudtasks v1.12.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= +cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= +cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.10.0 h1:YR2aPedGVQPpFBZXJnPkqRj8M//8veIZZH5ZvICoXnI= +cloud.google.com/go/contactcenterinsights v1.10.0/go.mod h1:bsg/R7zGLYMVxFFzfh9ooLTruLRCG9fnzhH9KznHhbM= +cloud.google.com/go/container v1.24.0 h1:N51t/cgQJFqDD/W7Mb+IvmAPHrf8AbPx7Bb7aF4lROE= +cloud.google.com/go/container v1.24.0/go.mod h1:lTNExE2R7f+DLbAN+rJiKTisauFCaoDq6NURZ83eVH4= +cloud.google.com/go/containeranalysis v0.10.1 h1:SM/ibWHWp4TYyJMwrILtcBtYKObyupwOVeceI9pNblw= +cloud.google.com/go/containeranalysis v0.10.1/go.mod h1:Ya2jiILITMY68ZLPaogjmOMNkwsDrWBSTyBubGXO7j0= +cloud.google.com/go/datacatalog v1.16.0 h1:qVeQcw1Cz93/cGu2E7TYUPh8Lz5dn5Ws2siIuQ17Vng= +cloud.google.com/go/datacatalog v1.16.0/go.mod h1:d2CevwTG4yedZilwe+v3E3ZBDRMobQfSG/a6cCCN5R4= +cloud.google.com/go/dataflow v0.9.1 h1:VzG2tqsk/HbmOtq/XSfdF4cBvUWRK+S+oL9k4eWkENQ= +cloud.google.com/go/dataflow v0.9.1/go.mod h1:Wp7s32QjYuQDWqJPFFlnBKhkAtiFpMTdg00qGbnIHVw= +cloud.google.com/go/dataform v0.8.1 h1:xcWso0hKOoxeW72AjBSIp/UfkvpqHNzzS0/oygHlcqY= +cloud.google.com/go/dataform v0.8.1/go.mod h1:3BhPSiw8xmppbgzeBbmDvmSWlwouuJkXsXsb8UBih9M= +cloud.google.com/go/datafusion v1.7.1 h1:eX9CZoyhKQW6g1Xj7+RONeDj1mV8KQDKEB9KLELX9/8= +cloud.google.com/go/datafusion v1.7.1/go.mod h1:KpoTBbFmoToDExJUso/fcCiguGDk7MEzOWXUsJo0wsI= +cloud.google.com/go/datalabeling v0.8.1 h1:zxsCD/BLKXhNuRssen8lVXChUj8VxF3ofN06JfdWOXw= +cloud.google.com/go/datalabeling v0.8.1/go.mod h1:XS62LBSVPbYR54GfYQsPXZjTW8UxCK2fkDciSrpRFdY= +cloud.google.com/go/dataplex v1.9.0 h1:yoBWuuUZklYp7nx26evIhzq8+i/nvKYuZr1jka9EqLs= +cloud.google.com/go/dataplex v1.9.0/go.mod h1:7TyrDT6BCdI8/38Uvp0/ZxBslOslP2X2MPDucliyvSE= +cloud.google.com/go/dataproc v1.12.0 h1:W47qHL3W4BPkAIbk4SWmIERwsWBaNnWm0P2sdx3YgGU= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataproc/v2 v2.0.1 h1:4OpSiPMMGV3XmtPqskBU/RwYpj3yMFjtMLj/exi425Q= +cloud.google.com/go/dataproc/v2 v2.0.1/go.mod h1:7Ez3KRHdFGcfY7GcevBbvozX+zyWGcwLJvvAMwCaoZ4= +cloud.google.com/go/dataqna v0.8.1 h1:ITpUJep04hC9V7C+gcK390HO++xesQFSUJ7S4nSnF3U= +cloud.google.com/go/dataqna v0.8.1/go.mod h1:zxZM0Bl6liMePWsHA8RMGAfmTG34vJMapbHAxQ5+WA8= +cloud.google.com/go/datastore v1.13.0 h1:ktbC66bOQB3HJPQe8qNI1/aiQ77PMu7hD4mzE6uxe3w= +cloud.google.com/go/datastore v1.13.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= +cloud.google.com/go/datastream v1.10.0 h1:ra/+jMv36zTAGPfi8TRne1hXme+UsKtdcK4j6bnqQiw= +cloud.google.com/go/datastream v1.10.0/go.mod h1:hqnmr8kdUBmrnk65k5wNRoHSCYksvpdZIcZIEl8h43Q= +cloud.google.com/go/deploy v1.13.0 h1:A+w/xpWgz99EYzB6e31gMGAI/P5jTZ2UO7veQK5jQ8o= +cloud.google.com/go/deploy v1.13.0/go.mod h1:tKuSUV5pXbn67KiubiUNUejqLs4f5cxxiCNCeyl0F2g= +cloud.google.com/go/dialogflow v1.40.0 h1:sCJbaXt6ogSbxWQnERKAzos57f02PP6WkGbOZvXUdwc= +cloud.google.com/go/dialogflow v1.40.0/go.mod h1:L7jnH+JL2mtmdChzAIcXQHXMvQkE3U4hTaNltEuxXn4= +cloud.google.com/go/dlp v1.10.1 h1:tF3wsJ2QulRhRLWPzWVkeDz3FkOGVoMl6cmDUHtfYxw= +cloud.google.com/go/dlp v1.10.1/go.mod h1:IM8BWz1iJd8njcNcG0+Kyd9OPnqnRNkDV8j42VT5KOI= +cloud.google.com/go/documentai v1.22.0 h1:dW8ex9yb3oT9s1yD2+yLcU8Zq15AquRZ+wd0U+TkxFw= +cloud.google.com/go/documentai v1.22.0/go.mod h1:yJkInoMcK0qNAEdRnqY/D5asy73tnPe88I1YTZT+a8E= +cloud.google.com/go/domains v0.9.1 h1:rqz6KY7mEg7Zs/69U6m6LMbB7PxFDWmT3QWNXIqhHm0= +cloud.google.com/go/domains v0.9.1/go.mod h1:aOp1c0MbejQQ2Pjf1iJvnVyT+z6R6s8pX66KaCSDYfE= +cloud.google.com/go/edgecontainer v1.1.1 h1:zhHWnLzg6AqzE+I3gzJqiIwHfjEBhWctNQEzqb+FaRo= +cloud.google.com/go/edgecontainer v1.1.1/go.mod h1:O5bYcS//7MELQZs3+7mabRqoWQhXCzenBu0R8bz2rwk= +cloud.google.com/go/errorreporting v0.3.0 h1:kj1XEWMu8P0qlLhm3FwcaFsUvXChV/OraZwA70trRR0= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.6.2 h1:OEJ0MLXXCW/tX1fkxzEZOsv/wRfyFsvDVNaHWBAvoV0= +cloud.google.com/go/essentialcontacts v1.6.2/go.mod h1:T2tB6tX+TRak7i88Fb2N9Ok3PvY3UNbUsMag9/BARh4= +cloud.google.com/go/eventarc v1.13.0 h1:xIP3XZi0Xawx8DEfh++mE2lrIi5kQmCr/KcWhJ1q0J4= +cloud.google.com/go/eventarc v1.13.0/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= +cloud.google.com/go/filestore v1.7.1 h1:Eiz8xZzMJc5ppBWkuaod/PUdUZGCFR8ku0uS+Ah2fRw= +cloud.google.com/go/filestore v1.7.1/go.mod h1:y10jsorq40JJnjR/lQ8AfFbbcGlw3g+Dp8oN7i7FjV4= +cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= +cloud.google.com/go/firestore v1.11.0 h1:PPgtwcYUOXV2jFe1bV3nda3RCrOa8cvBjTOn2MQVfW8= +cloud.google.com/go/firestore v1.11.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= +cloud.google.com/go/functions v1.15.1 h1:LtAyqvO1TFmNLcROzHZhV0agEJfBi+zfMZsF4RT/a7U= +cloud.google.com/go/functions v1.15.1/go.mod h1:P5yNWUTkyU+LvW/S9O6V+V423VZooALQlqoXdoPz5AE= +cloud.google.com/go/gaming v1.10.1 h1:5qZmZEWzMf8GEFgm9NeC3bjFRpt7x4S6U7oLbxaf7N8= +cloud.google.com/go/gaming v1.10.1/go.mod h1:XQQvtfP8Rb9Rxnxm5wFVpAp9zCQkJi2bLIb7iHGwB3s= +cloud.google.com/go/gkebackup v1.3.0 h1:lgyrpdhtJKV7l1GM15YFt+OCyHMxsQZuSydyNmS0Pxo= +cloud.google.com/go/gkebackup v1.3.0/go.mod h1:vUDOu++N0U5qs4IhG1pcOnD1Mac79xWy6GoBFlWCWBU= +cloud.google.com/go/gkeconnect v0.8.1 h1:a1ckRvVznnuvDWESM2zZDzSVFvggeBaVY5+BVB8tbT0= +cloud.google.com/go/gkeconnect v0.8.1/go.mod h1:KWiK1g9sDLZqhxB2xEuPV8V9NYzrqTUmQR9shJHpOZw= +cloud.google.com/go/gkehub v0.14.1 h1:2BLSb8i+Co1P05IYCKATXy5yaaIw/ZqGvVSBTLdzCQo= +cloud.google.com/go/gkehub v0.14.1/go.mod h1:VEXKIJZ2avzrbd7u+zeMtW00Y8ddk/4V9511C9CQGTY= +cloud.google.com/go/gkemulticloud v1.0.0 h1:MluqhtPVZReoriP5+adGIw+ij/RIeRik8KApCW2WMTw= +cloud.google.com/go/gkemulticloud v1.0.0/go.mod h1:kbZ3HKyTsiwqKX7Yw56+wUGwwNZViRnxWK2DVknXWfw= +cloud.google.com/go/grafeas v0.3.0 h1:oyTL/KjiUeBs9eYLw/40cpSZglUC+0F7X4iu/8t7NWs= +cloud.google.com/go/grafeas v0.3.0/go.mod h1:P7hgN24EyONOTMyeJH6DxG4zD7fwiYa5Q6GUgyFSOU8= +cloud.google.com/go/gsuiteaddons v1.6.1 h1:mi9jxZpzVjLQibTS/XfPZvl+Jr6D5Bs8pGqUjllRb00= +cloud.google.com/go/gsuiteaddons v1.6.1/go.mod h1:CodrdOqRZcLp5WOwejHWYBjZvfY0kOphkAKpF/3qdZY= +cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= +cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/iap v1.8.1 h1:X1tcp+EoJ/LGX6cUPt3W2D4H2Kbqq0pLAsldnsCjLlE= +cloud.google.com/go/iap v1.8.1/go.mod h1:sJCbeqg3mvWLqjZNsI6dfAtbbV1DL2Rl7e1mTyXYREQ= +cloud.google.com/go/ids v1.4.1 h1:khXYmSoDDhWGEVxHl4c4IgbwSRR+qE/L4hzP3vaU9Hc= +cloud.google.com/go/ids v1.4.1/go.mod h1:np41ed8YMU8zOgv53MMMoCntLTn2lF+SUzlM+O3u/jw= +cloud.google.com/go/iot v1.7.1 h1:yrH0OSmicD5bqGBoMlWG8UltzdLkYzNUwNVUVz7OT54= +cloud.google.com/go/iot v1.7.1/go.mod h1:46Mgw7ev1k9KqK1ao0ayW9h0lI+3hxeanz+L1zmbbbk= +cloud.google.com/go/kms v1.15.0 h1:xYl5WEaSekKYN5gGRyhjvZKM22GVBBCzegGNVPy+aIs= +cloud.google.com/go/kms v1.15.0/go.mod h1:c9J991h5DTl+kg7gi3MYomh12YEENGrf48ee/N/2CDM= +cloud.google.com/go/language v1.10.1 h1:3MXeGEv8AlX+O2LyV4pO4NGpodanc26AmXwOuipEym0= +cloud.google.com/go/language v1.10.1/go.mod h1:CPp94nsdVNiQEt1CNjF5WkTcisLiHPyIbMhvR8H2AW0= +cloud.google.com/go/lifesciences v0.9.1 h1:axkANGx1wiBXHiPcJZAE+TDjjYoJRIDzbHC/WYllCBU= +cloud.google.com/go/lifesciences v0.9.1/go.mod h1:hACAOd1fFbCGLr/+weUKRAJas82Y4vrL3O5326N//Wc= +cloud.google.com/go/logging v1.7.0 h1:CJYxlNNNNAMkHp9em/YEXcfJg+rPDg7YfwoRpMU+t5I= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc= +cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tErFDWI= +cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc= +cloud.google.com/go/managedidentities v1.6.1 h1:2/qZuOeLgUHorSdxSQGtnOu9xQkBn37+j+oZQv/KHJY= +cloud.google.com/go/managedidentities v1.6.1/go.mod h1:h/irGhTN2SkZ64F43tfGPMbHnypMbu4RB3yl8YcuEak= +cloud.google.com/go/maps v1.4.0 h1:PdfgpBLhAoSzZrQXP+/zBc78fIPLZSJp5y8+qSMn2UU= +cloud.google.com/go/maps v1.4.0/go.mod h1:6mWTUv+WhnOwAgjVsSW2QPPECmW+s3PcRyOa9vgG/5s= +cloud.google.com/go/mediatranslation v0.8.1 h1:50cF7c1l3BanfKrpnTCaTvhf+Fo6kdF21DG0byG7gYU= +cloud.google.com/go/mediatranslation v0.8.1/go.mod h1:L/7hBdEYbYHQJhX2sldtTO5SZZ1C1vkapubj0T2aGig= +cloud.google.com/go/memcache v1.10.1 h1:7lkLsF0QF+Mre0O/NvkD9Q5utUNwtzvIYjrOLOs0HO0= +cloud.google.com/go/memcache v1.10.1/go.mod h1:47YRQIarv4I3QS5+hoETgKO40InqzLP6kpNLvyXuyaA= +cloud.google.com/go/metastore v1.12.0 h1:+9DsxUOHvsqvC0ylrRc/JwzbXJaaBpfIK3tX0Lx8Tcc= +cloud.google.com/go/metastore v1.12.0/go.mod h1:uZuSo80U3Wd4zi6C22ZZliOUJ3XeM/MlYi/z5OAOWRA= +cloud.google.com/go/monitoring v1.15.1 h1:65JhLMd+JiYnXr6j5Z63dUYCuOg770p8a/VC+gil/58= +cloud.google.com/go/monitoring v1.15.1/go.mod h1:lADlSAlFdbqQuwwpaImhsJXu1QSdd3ojypXrFSMr2rM= +cloud.google.com/go/networkconnectivity v1.12.1 h1:LnrYM6lBEeTq+9f2lR4DjBhv31EROSAQi/P5W4Q0AEc= +cloud.google.com/go/networkconnectivity v1.12.1/go.mod h1:PelxSWYM7Sh9/guf8CFhi6vIqf19Ir/sbfZRUwXh92E= +cloud.google.com/go/networkmanagement v1.8.0 h1:/3xP37eMxnyvkfLrsm1nv1b2FbMMSAEAOlECTvoeCq4= +cloud.google.com/go/networkmanagement v1.8.0/go.mod h1:Ho/BUGmtyEqrttTgWEe7m+8vDdK74ibQc+Be0q7Fof0= +cloud.google.com/go/networksecurity v0.9.1 h1:TBLEkMp3AE+6IV/wbIGRNTxnqLXHCTEQWoxRVC18TzY= +cloud.google.com/go/networksecurity v0.9.1/go.mod h1:MCMdxOKQ30wsBI1eI659f9kEp4wuuAueoC9AJKSPWZQ= +cloud.google.com/go/notebooks v1.9.1 h1:CUqMNEtv4EHFnbogV+yGHQH5iAQLmijOx191innpOcs= +cloud.google.com/go/notebooks v1.9.1/go.mod h1:zqG9/gk05JrzgBt4ghLzEepPHNwE5jgPcHZRKhlC1A8= +cloud.google.com/go/optimization v1.4.1 h1:pEwOAmO00mxdbesCRSsfj8Sd4rKY9kBrYW7Vd3Pq7cA= +cloud.google.com/go/optimization v1.4.1/go.mod h1:j64vZQP7h9bO49m2rVaTVoNM0vEBEN5eKPUPbZyXOrk= +cloud.google.com/go/orchestration v1.8.1 h1:KmN18kE/xa1n91cM5jhCh7s1/UfIguSCisw7nTMUzgE= +cloud.google.com/go/orchestration v1.8.1/go.mod h1:4sluRF3wgbYVRqz7zJ1/EUNc90TTprliq9477fGobD8= +cloud.google.com/go/orgpolicy v1.11.1 h1:I/7dHICQkNwym9erHqmlb50LRU588NPCvkfIY0Bx9jI= +cloud.google.com/go/orgpolicy v1.11.1/go.mod h1:8+E3jQcpZJQliP+zaFfayC2Pg5bmhuLK755wKhIIUCE= +cloud.google.com/go/osconfig v1.12.1 h1:dgyEHdfqML6cUW6/MkihNdTVc0INQst0qSE8Ou1ub9c= +cloud.google.com/go/osconfig v1.12.1/go.mod h1:4CjBxND0gswz2gfYRCUoUzCm9zCABp91EeTtWXyz0tE= +cloud.google.com/go/oslogin v1.10.1 h1:LdSuG3xBYu2Sgr3jTUULL1XCl5QBx6xwzGqzoDUw1j0= +cloud.google.com/go/oslogin v1.10.1/go.mod h1:x692z7yAue5nE7CsSnoG0aaMbNoRJRXO4sn73R+ZqAs= +cloud.google.com/go/phishingprotection v0.8.1 h1:aK/lNmSd1vtbft/vLe2g7edXK72sIQbqr2QyrZN/iME= +cloud.google.com/go/phishingprotection v0.8.1/go.mod h1:AxonW7GovcA8qdEk13NfHq9hNx5KPtfxXNeUxTDxB6I= +cloud.google.com/go/policytroubleshooter v1.8.0 h1:XTMHy31yFmXgQg57CB3w9YQX8US7irxDX0Fl0VwlZyY= +cloud.google.com/go/policytroubleshooter v1.8.0/go.mod h1:tmn5Ir5EToWe384EuboTcVQT7nTag2+DuH3uHmKd1HU= +cloud.google.com/go/privatecatalog v0.9.1 h1:B/18xGo+E0EMS9LOEQ0zXz7F2asMgmVgTYGSI89MHOA= +cloud.google.com/go/privatecatalog v0.9.1/go.mod h1:0XlDXW2unJXdf9zFz968Hp35gl/bhF4twwpXZAW50JA= +cloud.google.com/go/pubsub v1.33.0 h1:6SPCPvWav64tj0sVX/+npCBKhUi/UjJehy9op/V3p2g= +cloud.google.com/go/pubsub v1.33.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= +cloud.google.com/go/pubsublite v1.8.1 h1:pX+idpWMIH30/K7c0epN6V703xpIcMXWRjKJsz0tYGY= +cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0= +cloud.google.com/go/recaptchaenterprise/v2 v2.7.2 h1:IGkbudobsTXAwmkEYOzPCQPApUCsN4Gbq3ndGVhHQpI= +cloud.google.com/go/recaptchaenterprise/v2 v2.7.2/go.mod h1:kR0KjsJS7Jt1YSyWFkseQ756D45kaYNTlDPPaRAvDBU= +cloud.google.com/go/recommendationengine v0.8.1 h1:nMr1OEVHuDambRn+/y4RmNAmnR/pXCuHtH0Y4tCgGRQ= +cloud.google.com/go/recommendationengine v0.8.1/go.mod h1:MrZihWwtFYWDzE6Hz5nKcNz3gLizXVIDI/o3G1DLcrE= +cloud.google.com/go/recommender v1.10.1 h1:UKp94UH5/Lv2WXSQe9+FttqV07x/2p1hFTMMYVFtilg= +cloud.google.com/go/recommender v1.10.1/go.mod h1:XFvrE4Suqn5Cq0Lf+mCP6oBHD/yRMA8XxP5sb7Q7gpA= +cloud.google.com/go/redis v1.13.1 h1:YrjQnCC7ydk+k30op7DSjSHw1yAYhqYXFcOq1bSXRYA= +cloud.google.com/go/redis v1.13.1/go.mod h1:VP7DGLpE91M6bcsDdMuyCm2hIpB6Vp2hI090Mfd1tcg= +cloud.google.com/go/resourcemanager v1.9.1 h1:QIAMfndPOHR6yTmMUB0ZN+HSeRmPjR/21Smq5/xwghI= +cloud.google.com/go/resourcemanager v1.9.1/go.mod h1:dVCuosgrh1tINZ/RwBufr8lULmWGOkPS8gL5gqyjdT8= +cloud.google.com/go/resourcesettings v1.6.1 h1:Fdyq418U69LhvNPFdlEO29w+DRRjwDA4/pFamm4ksAg= +cloud.google.com/go/resourcesettings v1.6.1/go.mod h1:M7mk9PIZrC5Fgsu1kZJci6mpgN8o0IUzVx3eJU3y4Jw= +cloud.google.com/go/retail v1.14.1 h1:gYBrb9u/Hc5s5lUTFXX1Vsbc/9BEvgtioY6ZKaK0DK8= +cloud.google.com/go/retail v1.14.1/go.mod h1:y3Wv3Vr2k54dLNIrCzenyKG8g8dhvhncT2NcNjb/6gE= +cloud.google.com/go/run v1.2.0 h1:kHeIG8q+N6Zv0nDkBjSOYfK2eWqa5FnaiDPH/7/HirE= +cloud.google.com/go/run v1.2.0/go.mod h1:36V1IlDzQ0XxbQjUx6IYbw8H3TJnWvhii963WW3B/bo= +cloud.google.com/go/scheduler v1.10.1 h1:yoZbZR8880KgPGLmACOMCiY2tPk+iX4V/dkxqTirlz8= +cloud.google.com/go/scheduler v1.10.1/go.mod h1:R63Ldltd47Bs4gnhQkmNDse5w8gBRrhObZ54PxgR2Oo= +cloud.google.com/go/secretmanager v1.11.1 h1:cLTCwAjFh9fKvU6F13Y4L9vPcx9yiWPyWXE4+zkuEQs= +cloud.google.com/go/secretmanager v1.11.1/go.mod h1:znq9JlXgTNdBeQk9TBW/FnR/W4uChEKGeqQWAJ8SXFw= +cloud.google.com/go/security v1.15.1 h1:jR3itwycg/TgGA0uIgTItcVhA55hKWiNJxaNNpQJaZE= +cloud.google.com/go/security v1.15.1/go.mod h1:MvTnnbsWnehoizHi09zoiZob0iCHVcL4AUBj76h9fXA= +cloud.google.com/go/securitycenter v1.23.0 h1:XOGJ9OpnDtqg8izd7gYk/XUhj8ytjIalyjjsR6oyG0M= +cloud.google.com/go/securitycenter v1.23.0/go.mod h1:8pwQ4n+Y9WCWM278R8W3nF65QtY172h4S8aXyI9/hsQ= +cloud.google.com/go/servicedirectory v1.11.0 h1:pBWpjCFVGWkzVTkqN3TBBIqNSoSHY86/6RL0soSQ4z8= +cloud.google.com/go/servicedirectory v1.11.0/go.mod h1:Xv0YVH8s4pVOwfM/1eMTl0XJ6bzIOSLDt8f8eLaGOxQ= +cloud.google.com/go/shell v1.7.1 h1:aHbwH9LSqs4r2rbay9f6fKEls61TAjT63jSyglsw7sI= +cloud.google.com/go/shell v1.7.1/go.mod h1:u1RaM+huXFaTojTbW4g9P5emOrrmLE69KrxqQahKn4g= +cloud.google.com/go/spanner v1.47.0 h1:aqiMP8dhsEXgn9K5EZBWxPG7dxIiyM2VaikqeU4iteg= +cloud.google.com/go/spanner v1.47.0/go.mod h1:IXsJwVW2j4UKs0eYDqodab6HgGuA1bViSqW4uH9lfUI= +cloud.google.com/go/speech v1.19.0 h1:MCagaq8ObV2tr1kZJcJYgXYbIn8Ai5rp42tyGYw9rls= +cloud.google.com/go/speech v1.19.0/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= +cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM= +cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= +cloud.google.com/go/storagetransfer v1.10.0 h1:+ZLkeXx0K0Pk5XdDmG0MnUVqIR18lllsihU/yq39I8Q= +cloud.google.com/go/storagetransfer v1.10.0/go.mod h1:DM4sTlSmGiNczmV6iZyceIh2dbs+7z2Ayg6YAiQlYfA= +cloud.google.com/go/talent v1.6.2 h1:j46ZgD6N2YdpFPux9mc7OAf4YK3tiBCsbLKc8rQx+bU= +cloud.google.com/go/talent v1.6.2/go.mod h1:CbGvmKCG61mkdjcqTcLOkb2ZN1SrQI8MDyma2l7VD24= +cloud.google.com/go/texttospeech v1.7.1 h1:S/pR/GZT9p15R7Y2dk2OXD/3AufTct/NSxT4a7nxByw= +cloud.google.com/go/texttospeech v1.7.1/go.mod h1:m7QfG5IXxeneGqTapXNxv2ItxP/FS0hCZBwXYqucgSk= +cloud.google.com/go/tpu v1.6.1 h1:kQf1jgPY04UJBYYjNUO+3GrZtIb57MfGAW2bwgLbR3A= +cloud.google.com/go/tpu v1.6.1/go.mod h1:sOdcHVIgDEEOKuqUoi6Fq53MKHJAtOwtz0GuKsWSH3E= +cloud.google.com/go/trace v1.10.1 h1:EwGdOLCNfYOOPtgqo+D2sDLZmRCEO1AagRTJCU6ztdg= +cloud.google.com/go/trace v1.10.1/go.mod h1:gbtL94KE5AJLH3y+WVpfWILmqgc6dXcqgNXdOPAQTYk= +cloud.google.com/go/translate v1.8.2 h1:PQHamiOzlehqLBJMnM72lXk/OsMQewZB12BKJ8zXrU0= +cloud.google.com/go/translate v1.8.2/go.mod h1:d1ZH5aaOA0CNhWeXeC8ujd4tdCFw8XoNWRljklu5RHs= +cloud.google.com/go/video v1.19.0 h1:BRyyS+wU+Do6VOXnb8WfPr42ZXti9hzmLKLUCkggeK4= +cloud.google.com/go/video v1.19.0/go.mod h1:9qmqPqw/Ib2tLqaeHgtakU+l5TcJxCJbhFXM7UJjVzU= +cloud.google.com/go/videointelligence v1.11.1 h1:MBMWnkQ78GQnRz5lfdTAbBq/8QMCF3wahgtHh3s/J+k= +cloud.google.com/go/videointelligence v1.11.1/go.mod h1:76xn/8InyQHarjTWsBR058SmlPCwQjgcvoW0aZykOvo= +cloud.google.com/go/vision/v2 v2.7.2 h1:ccK6/YgPfGHR/CyESz1mvIbsht5Y2xRsWCPqmTNydEw= +cloud.google.com/go/vision/v2 v2.7.2/go.mod h1:jKa8oSYBWhYiXarHPvP4USxYANYUEdEsQrloLjrSwJU= +cloud.google.com/go/vmmigration v1.7.1 h1:gnjIclgqbEMc+cF5IJuPxp53wjBIlqZ8h9hE8Rkwp7A= +cloud.google.com/go/vmmigration v1.7.1/go.mod h1:WD+5z7a/IpZ5bKK//YmT9E047AD+rjycCAvyMxGJbro= +cloud.google.com/go/vmwareengine v1.0.0 h1:qsJ0CPlOQu/3MFBGklu752v3AkD+Pdu091UmXJ+EjTA= +cloud.google.com/go/vmwareengine v1.0.0/go.mod h1:Px64x+BvjPZwWuc4HdmVhoygcXqEkGHXoa7uyfTgSI0= +cloud.google.com/go/vpcaccess v1.7.1 h1:ram0GzjNWElmbxXMIzeOZUkQ9J8ZAahD6V8ilPGqX0Y= +cloud.google.com/go/vpcaccess v1.7.1/go.mod h1:FogoD46/ZU+JUBX9D606X21EnxiszYi2tArQwLY4SXs= +cloud.google.com/go/webrisk v1.9.1 h1:Ssy3MkOMOnyRV5H2bkMQ13Umv7CwB/kugo3qkAX83Fk= +cloud.google.com/go/webrisk v1.9.1/go.mod h1:4GCmXKcOa2BZcZPn6DCEvE7HypmEJcJkr4mtM+sqYPc= +cloud.google.com/go/websecurityscanner v1.6.1 h1:CfEF/vZ+xXyAR3zC9iaC/QRdf1MEgS20r5UR17Q4gOg= +cloud.google.com/go/websecurityscanner v1.6.1/go.mod h1:Njgaw3rttgRHXzwCB8kgCYqv5/rGpFCsBOvPbYgszpg= +cloud.google.com/go/workflows v1.11.1 h1:2akeQ/PgtRhrNuD/n1WvJd5zb7YyuDZrlOanBj2ihPg= +cloud.google.com/go/workflows v1.11.1/go.mod h1:Z+t10G1wF7h8LgdY/EmRcQY8ptBD/nvofaL6FqlET6g= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY= +github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= +github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c= +github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME= +github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= +github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc= +github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk= +github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0= +github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= +github.com/alecthomas/kingpin/v2 v2.3.2 h1:H0aULhgmSzN8xQ3nX1uxtdlTHYoPLu5AhHxWrKI6ocU= +github.com/alecthomas/kingpin/v2 v2.3.2/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= +github.com/apache/arrow/go/v12 v12.0.0 h1:xtZE63VWl7qLdB0JObIXvvhGjoVNrQ9ciIHG2OK5cmc= +github.com/apache/arrow/go/v12 v12.0.0/go.mod h1:d+tV/eHZZ7Dz7RPrFKtPK02tpr+c9/PEd/zm8mDS9Vg= +github.com/apache/thrift v0.16.0 h1:qEy6UW60iVOlUy+b9ZR0d5WzUWYGOo4HfopoyBaNmoY= +github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA= +github.com/armon/go-metrics v0.4.0 h1:yCQqn7dwca4ITXb+CbubHmedzaQYHhNhrEXLYUeEe8Q= +github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= +github.com/bketelsen/crypt v0.0.4 h1:w/jqZtC9YD4DS/Vp9GhWfWcCpuAL58oTnLoI8vE9YHU= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= -github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= -github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4= -github.com/crewjam/saml v0.4.13/go.mod h1:igEejV+fihTIlHXYP8zOec3V5A8y3lws5bQBFsTm4gA= -github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY= -github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= -github.com/gabstv/melody v1.0.2/go.mod h1:fvJW9enOHGIN1E4nCuBZ3lIZxHiPbnMIIYEXcSKQq9o= -github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= -github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-gormigrate/gormigrate/v2 v2.1.0/go.mod h1:gpA97koYGyjqaiLDTmLE5W7nyYTmI26AYIf2a/earuo= -github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.15.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764= +github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= +github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= +github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q= +github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= +github.com/coreos/go-etcd v2.0.0+incompatible h1:bXhRBIXoTm9BYHS3gE0TtQuyNZyeEMux2sDi4oo5YOo= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= +github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= +github.com/dchest/uniuri v1.2.0 h1:koIcOUdrTIivZgSLhHQvKgqdWZq5d7KdMEWF1Ud6+5g= +github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/djherbis/atime v1.1.0 h1:rgwVbP/5by8BvvjBNrbh64Qz33idKT3pSnMSJsxhi0g= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= +github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM= +github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= +github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I= +github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= +github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA= +github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/icholy/digest v0.1.22/go.mod h1:uLAeDdWKIWNFMH0wqbwchbTQOmJWhzSnL7zmqSPqEEc= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= -github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= -github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= -github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To= -github.com/matthiasreumann/gomino v0.0.2/go.mod h1:bmKxa4ZOGY6RSFH4NnfYf7hk7FbMu2nkSpoAF5TD6fY= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/meilisearch/meilisearch-go v0.25.0/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0= -github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/olahol/melody v0.0.0-20180227134253-7bd65910e5ab/go.mod h1:3lo03f1jM3KFUG/rsujuLB1rBmlvIzVM3SCqbuHqsBU= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= +github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM= +github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= +github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= +github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4= +github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= +github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 h1:tlyzajkF3030q6M8SvmJSemC9DTHL/xaMa18b65+JM4= +github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 h1:lLT7ZLSzGLI08vc9cpd+tYmNWjdKDqyr/2L+f6U12Fk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +github.com/hashicorp/consul/api v1.20.0 h1:9IHTjNVSZ7MIwjlW3N3a7iGiykCMDpxZu8jsxFJh0yc= +github.com/hashicorp/consul/api v1.20.0/go.mod h1:nR64eD44KQ59Of/ECwt2vUmIK2DKsDzAwTmwmLl8Wpo= +github.com/hashicorp/consul/sdk v0.1.1 h1:LnuDWGNsoajlhGyHJvuWW6FVqRl8JOTPqS6CPTsYjhY= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= +github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= +github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= +github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= +github.com/hashicorp/go.net v0.0.1 h1:sNCoNyDEvN1xa+X0baata4RdcpKwcMS6DH+xwfqPgjw= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= +github.com/hashicorp/mdns v1.0.0 h1:WhIgCr5a7AaVH6jPUwjtRuuE7/RDufnUvzIr48smyxs= +github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M= +github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= +github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= +github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab h1:BA4a7pe6ZTd9F8kXETBoijjFJ/ntaa//1wiH9BZu4zU= +github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw= +github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/iris-contrib/httpexpect/v2 v2.3.1 h1:A69ilxKGW1jDRKK5UAhjTL4uJYh3RjD4qzt9vNZ7fpY= +github.com/iris-contrib/jade v1.1.4 h1:WoYdfyJFfZIUgqNAeOyRfTNQZOksSlZ6+FnXR3AEpX0= +github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kataras/blocks v0.0.7 h1:cF3RDY/vxnSRezc7vLFlQFTYXG/yAr1o7WImJuZbzC4= +github.com/kataras/golog v0.1.8 h1:isP8th4PJH2SrbkciKnylaND9xoTtfxv++NB+DF0l9g= +github.com/kataras/golog v0.1.8/go.mod h1:rGPAin4hYROfk1qT9wZP6VY2rsb4zzc37QpdPjdkqVw= +github.com/kataras/iris/v12 v12.2.0 h1:WzDY5nGuW/LgVaFS5BtTkW3crdSKJ/FEgWnxPnIVVLI= +github.com/kataras/iris/v12 v12.2.0/go.mod h1:BLzBpEunc41GbE68OUaQlqX4jzi791mx5HU04uPb90Y= +github.com/kataras/jwt v0.1.8 h1:u71baOsYD22HWeSOg32tCHbczPjdCk7V4MMeJqTtmGk= +github.com/kataras/neffos v0.0.20 h1:swTzKZ3Mo2sIQ8ATKSKf0xDG1tuhr6w4tZmmRsvCYlg= +github.com/kataras/pio v0.0.11 h1:kqreJ5KOEXGMwHAWHDwIl+mjfNCPhAwZPa8gK7MKlyw= +github.com/kataras/sitemap v0.0.6 h1:w71CRMMKYMJh6LR2wTgnk5hSgjVNB9KL60n5e2KHvLY= +github.com/kataras/tunnel v0.0.4 h1:sCAqWuJV7nPzGrlb0os3j49lk2JhILT0rID38NHNLpA= +github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= +github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= +github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK4= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= +github.com/knz/go-libedit v1.10.1 h1:0pHpWtx9vcvC0xGZqEQlQdfSQs7WRlAjuPvk3fOZDCo= +github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= +github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= +github.com/labstack/echo/v4 v4.10.0 h1:5CiyngihEO4HXsz3vVsJn7f8xAlWwRr3aY6Ih280ZKA= +github.com/labstack/echo/v4 v4.10.0/go.mod h1:S/T/5fy/GigaXnHTkh0ZGe4LpkkQysvRjFMSUTkDRNQ= +github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= +github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= +github.com/lyft/protoc-gen-star/v2 v2.0.3 h1:/3+/2sWyXeMLzKd1bX+ixWKgEMsULrIivpDsuaF441o= +github.com/lyft/protoc-gen-star/v2 v2.0.3/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= +github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw= +github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= +github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2 h1:JAEbJn3j/FrhdWA9jW8B5ajsLIjeuEHLi8xE4fk997o= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mediocregopher/radix/v3 v3.8.0 h1:HI8EgkaM7WzsrFpYAkOXIgUKbjNonb2Ne7K6Le61Pmg= +github.com/microsoft/go-mssqldb v0.21.0/go.mod h1:+4wZTUnz/SV6nffv+RRRB/ss8jPng5Sho2SmM1l2ts4= +github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs= +github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8DFdX7uMikMLXX4oubIzJF4kv/wI= +github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= +github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= +github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= +github.com/mitchellh/gox v0.4.0 h1:lfGJxY7ToLJQjHHwi0EX6uYBdK78egf954SQl13PQJc= +github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nats-io/jwt/v2 v2.3.0 h1:z2mA1a7tIf5ShggOFlR1oBPgd6hGqcDYsISxZByUzdI= +github.com/nats-io/nats-server/v2 v2.8.4 h1:0jQzze1T9mECg8YZEl8+WYUXb9JKluJfCBriPUtluB4= +github.com/nats-io/nats.go v1.16.0 h1:zvLE7fGBQYW6MWaFaRdsgm9qT39PJDQoju+DS8KsO1g= +github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86 h1:D6paGObi5Wud7xg83MaEFyjxQB1W5bz5d0IFppr+ymk= +github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c h1:bY6ktFuJkt+ZXkX0RChQch2FtHpWQLVS8Qo1YasiIVk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/olahol/melody v0.0.0-20180227134253-7bd65910e5ab h1:2fsluM+sAZRIQtvloPaokkWWjV8strYfmXsDCtZMqt0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ= +github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= +github.com/panjf2000/ants/v2 v2.4.2 h1:kesjjo8JipN3vNNg1XaiXaeSs6xJweBTgenkBtsrHf8= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= -github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= -github.com/pkg/profile v1.4.0/go.mod h1:NWz/XGvpEW1FyYQ7fCx4dqYBLlfTcE+A9FLAkNKqjFE= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= +github.com/pkg/sftp v1.13.1 h1:I2qBYMChEhIjOgazfJmV3/mZM256btk6wkCDRmW7JYs= +github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w= +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/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= +github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/russellhaering/goxmldsig v1.2.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= -github.com/russellhaering/goxmldsig v1.4.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= -github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= -github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f h1:UFr9zpz4xgTnIE5yIMtWAMngCdZ9p/+q6lTbgelo80M= +github.com/sagikazarmark/crypt v0.10.0 h1:96E1qrToLBU6fGzo+PRRz7KGOc9FkYFiPnR3/zf8Smg= +github.com/sagikazarmark/crypt v0.10.0/go.mod h1:gwTNHQVoOS3xp9Xvz5LLR+1AauC5M6880z5NWzdhOyQ= +github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk= +github.com/schollz/progressbar/v3 v3.8.6 h1:QruMUdzZ1TbEP++S1m73OqRJk20ON11m6Wqv4EoGg8c= +github.com/schollz/progressbar/v3 v3.8.6/go.mod h1:W5IEwbJecncFGBvuEh4A7HT1nZZ6WNIL2i3qbnI0WKY= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636 h1:aSISeOcal5irEhJd1M+IrApc0PdcN7e7Aj4yuEnOrfQ= +github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU= +github.com/smartystreets/assertions v1.13.0 h1:Dx1kYM01xsSqKPno3aqLnrwac2LetPvN23diwyr69Qs= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/tdewolff/minify/v2 v2.12.4 h1:kejsHQMM17n6/gwdw53qsi6lg0TGddZADVyQOz1KMdE= +github.com/tdewolff/parse/v2 v2.6.4 h1:KCkDvNUMof10e3QExio9OPZJT8SbdKojLBumw8YZycQ= +github.com/tdewolff/test v1.0.7 h1:8Vs0142DmPFW/bQeHRP3MV19m1gvndjUb1sn8yy74LM= github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/valyala/fasthttp v1.37.1-0.20220607072126-8a320890c08d/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= -github.com/valyala/fasthttp v1.48.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= -github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= +github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= +github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= +github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= +github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= +github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +github.com/zenazn/goji v1.0.1 h1:4lbD8Mx2h7IvloP7r2C0D6ltZP6Ufip8Hn0wmSK5LR8= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= +go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= +go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE= +go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= +go.etcd.io/etcd/client/v2 v2.305.7 h1:AELPkjNR3/igjbO7CjyF1fPuVPjrblliiKj+Y6xSGOU= +go.etcd.io/etcd/client/v2 v2.305.7/go.mod h1:GQGT5Z3TBuAQGvgPfhR7VPySu/SudxmEkRq9BgzFU6s= +go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E= +go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/otel v1.17.0 h1:MW+phZ6WZ5/uk2nd93ANk/6yJ+dVrvNWUjGhnnFU5jM= +go.opentelemetry.io/otel v1.17.0/go.mod h1:I2vmBGtFaODIVMBSTPVDlJSzBDNf93k60E6Ft0nyjo0= +go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYOdSKWQ= +go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= +go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= +golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= +google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o= +google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= +google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= +google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51iE/nOGvQaDUuadVYqovW56s5emA88lQnj6Y= +google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= -gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= +google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= +google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e h1:z3vDksarJxsAKM5dmEGv0GHwE2hKJ096wZra71Vs4sw= +google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc h1:g3hIDl0jRNd9PPTs2uBzYuaD5mQuwOkZY0vSc0LR32o= +google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230731190214-cbb8c96f2d6d/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= +gorm.io/driver/sqlite v1.5.1/go.mod h1:7MZZ2Z8bqyfSQA1gYEV6MagQWj3cpUkJj9Z+d1HEMEQ= +gorm.io/driver/sqlserver v1.5.0/go.mod h1:tBAqioK34BHl0Iiez+BFfG5/K9nDAlhLxRkgc2qy3+4= gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64= -gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -gorm.io/gorm v1.25.3/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -mvdan.cc/xurls/v2 v2.5.0/go.mod h1:yQgaGQ1rFtJUzkmKiHYSSfuQxqfYmd//X6PxvholpeE= -nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= +moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8= +nullprogram.com/x/optparse v1.0.0 h1:xGFgVi5ZaWOnYdac2foDT3vg0ZZC9ErXFV57mr4OHrI= +rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= +rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= +rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= +rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= diff --git a/mock_dao/runner.go b/mock_dao/runner.go new file mode 100644 index 000000000..b8d947a68 --- /dev/null +++ b/mock_dao/runner.go @@ -0,0 +1,79 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: runner.go + +// Package mock_dao is a generated GoMock package. +package mock_dao + +import ( + context "context" + reflect "reflect" + + model "github.com/TUM-Dev/gocast/model" + gomock "github.com/golang/mock/gomock" +) + +// MockRunnerDao is a mock of RunnerDao interface. +type MockRunnerDao struct { + ctrl *gomock.Controller + recorder *MockRunnerDaoMockRecorder +} + +// MockRunnerDaoMockRecorder is the mock recorder for MockRunnerDao. +type MockRunnerDaoMockRecorder struct { + mock *MockRunnerDao +} + +// NewMockRunnerDao creates a new mock instance. +func NewMockRunnerDao(ctrl *gomock.Controller) *MockRunnerDao { + mock := &MockRunnerDao{ctrl: ctrl} + mock.recorder = &MockRunnerDaoMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockRunnerDao) EXPECT() *MockRunnerDaoMockRecorder { + return m.recorder +} + +// Create mocks base method. +func (m *MockRunnerDao) Create(arg0 context.Context, arg1 *model.Runner) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Create indicates an expected call of Create. +func (mr *MockRunnerDaoMockRecorder) Create(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockRunnerDao)(nil).Create), arg0, arg1) +} + +// Delete mocks base method. +func (m *MockRunnerDao) Delete(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete. +func (mr *MockRunnerDaoMockRecorder) Delete(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockRunnerDao)(nil).Delete), arg0, arg1) +} + +// Get mocks base method. +func (m *MockRunnerDao) Get(arg0 context.Context, arg1 string) (model.Runner, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Get", arg0, arg1) + ret0, _ := ret[0].(model.Runner) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Get indicates an expected call of Get. +func (mr *MockRunnerDaoMockRecorder) Get(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockRunnerDao)(nil).Get), arg0, arg1) +} diff --git a/model/runner.go b/model/runner.go new file mode 100644 index 000000000..710a96348 --- /dev/null +++ b/model/runner.go @@ -0,0 +1,25 @@ +package model + +import ( + "database/sql" + "errors" + "gorm.io/gorm" +) + +// Runner represents a runner that creates, converts and postprocesses streams and does other heavy lifting. +type Runner struct { + Hostname string `gorm:"primaryKey"` + Port int + LastSeen sql.NullTime +} + +// BeforeCreate returns errors if hostnames and ports of workers are invalid. +func (r *Runner) BeforeCreate(tx *gorm.DB) (err error) { + if r.Hostname == "" { + return errors.New("missing hostname") + } + if r.Port < 0 || r.Port > 65535 { + return errors.New("port out of range") + } + return nil +} diff --git a/runner/.gitignore b/runner/.gitignore new file mode 100644 index 000000000..31eb45db6 --- /dev/null +++ b/runner/.gitignore @@ -0,0 +1 @@ +mediamtx diff --git a/runner/Dockerfile b/runner/Dockerfile new file mode 100644 index 000000000..309827373 --- /dev/null +++ b/runner/Dockerfile @@ -0,0 +1,27 @@ +FROM amd64/golang:1.21-alpine3.18 as builder + +WORKDIR /go/src/github.com/TUM-Dev/gocast/runner +COPY . . + +RUN GO111MODULE=on go mod download +# bundle version into binary if specified in build-args, dev otherwise. +ARG version=dev +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -ldflags "-w -extldflags '-static' -X main.V=${version}" -o /runner cmd/runner/main.go + +FROM bluenviron/mediamtx:1.1.0 as mediamtx + +FROM alpine:3.18 +ADD entrypoint.sh /entrypoint.sh +ADD mediamtx.yml /mediamtx.yml +RUN chmod +x /entrypoint.sh + +RUN apk add --no-cache \ + ffmpeg \ + tzdata + +COPY --from=builder /runner /runner +RUN chmod +x /runner +COPY --from=mediamtx /mediamtx /mediamtx +RUN chmod +x /mediamtx + +CMD ["/entrypoint.sh"] \ No newline at end of file diff --git a/runner/Makefile b/runner/Makefile new file mode 100644 index 000000000..541ff27f2 --- /dev/null +++ b/runner/Makefile @@ -0,0 +1,36 @@ +.PHONY: all +all: build + +VERSION := $(shell git rev-parse --short origin/HEAD) + +.PHONY: protoGen +protoGen: + protoc ./runner.proto --go-grpc_out=.. --go_out=.. + +.PHONY: build +build: deps + go build -o main -ldflags="-X 'main.VersionTag=$(VERSION)'" cmd/runner/main.go + +.PHONY: deps +deps: + go get ./... + +.PHONY: install +install: + mv main /bin/runner + +.PHONY: clean +clean: + rm -f main + +.PHONY: test +test: + go test -race ./... + +.PHONY: run +run: + go run cmd/runner/main.go + +.PHONY: lint +lint: + golangci-lint run diff --git a/runner/actions/actions.go b/runner/actions/actions.go new file mode 100644 index 000000000..f8ff7ae68 --- /dev/null +++ b/runner/actions/actions.go @@ -0,0 +1,57 @@ +package actions + +import ( + "context" + "errors" + "fmt" + "log/slog" + "path" +) + +var ( + ErrActionInputWrongType = errors.New("action input has wrong type") + ErrRequiredContextValNotFound = errors.New("required context value not found") +) + +type ActionProvider struct { + Log *slog.Logger + + SegmentDir string // for storing live hls segments locally. This should be fast storage (e.g. ssd). + RecDir string // for storing recordings locally. + MassDir string // for storing final files like Thumbnails, mp4s, ... Mass storage like Ceph. +} + +func (a *ActionProvider) GetRecDir(courseID, streamID uint64, version string) string { + return path.Join(a.RecDir, fmt.Sprintf("%d", courseID), fmt.Sprintf("%d", streamID), version) +} + +func (a *ActionProvider) GetLiveDir(courseID, streamID uint64, version string) string { + return path.Join(a.SegmentDir, fmt.Sprintf("%d", courseID), fmt.Sprintf("%d", streamID), version) +} + +func (a *ActionProvider) GetMassDir(courseID, streamID uint64, version string) string { + return path.Join(a.MassDir, fmt.Sprintf("%d", courseID), fmt.Sprintf("%d", streamID), version) +} + +type ActionType string + +const ( + PrepareAction ActionType = "prepare" + StreamAction = "stream" + TranscodeAction = "transcode" + UploadAction = "upload" +) + +type Action struct { + Type ActionType + Cancel context.CancelCauseFunc + Canceled bool + + ActionFn ActionFn +} + +type ActionFn func(ctx context.Context, log *slog.Logger) (context.Context, error) + +func set(ctx context.Context, key string, val interface{}) context.Context { + return context.WithValue(ctx, key, val) +} diff --git a/runner/actions/prepare.go b/runner/actions/prepare.go new file mode 100644 index 000000000..db77411f3 --- /dev/null +++ b/runner/actions/prepare.go @@ -0,0 +1,43 @@ +package actions + +import ( + "context" + "fmt" + "log/slog" + "os" +) + +// PrepareAction prepares the directory structure for the stream and vod. +func (a *ActionProvider) PrepareAction() *Action { + return &Action{ + Type: PrepareAction, + ActionFn: func(ctx context.Context, log *slog.Logger) (context.Context, error) { + streamID, ok := ctx.Value("stream").(uint64) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain stream", ErrRequiredContextValNotFound) + } + courseID, ok := ctx.Value("course").(uint64) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain course", ErrRequiredContextValNotFound) + } + version, ok := ctx.Value("version").(string) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain version", ErrRequiredContextValNotFound) + } + + dirs := []string{ + a.GetRecDir(courseID, streamID, version), + a.GetLiveDir(courseID, streamID, version), + a.GetMassDir(courseID, streamID, version), + } + for _, dir := range dirs { + log.Info("creating directory", "path", dir) + err := os.MkdirAll(dir, 0755) + if err != nil { + return ctx, fmt.Errorf("create directory: %w", err) + } + } + return ctx, nil + }, + } +} diff --git a/runner/actions/stream.go b/runner/actions/stream.go new file mode 100644 index 000000000..412c08858 --- /dev/null +++ b/runner/actions/stream.go @@ -0,0 +1,97 @@ +package actions + +import ( + "context" + "fmt" + "log/slog" + "os" + "os/exec" + "path/filepath" + "strings" + "time" +) + +var edgeTemplate = "%s://%s/live/%s/%d-%s/playlist.m3u8" // e.g. "https://stream.domain.com/workerhostname123/1-COMB/playlist.m3u8" + +// StreamAction streams a video. in is ignored. out is a []string containing the filenames of the recorded stream. +// ctx must contain the following values: +// - streamID (uint64) // e.g. 1 +// - courseID (uint64) // e.g. 1 +// - version (string) // e.g. "PRES", "CAM", "COMB" +// - source (string) // e.g. "rtmp://localhost:1935/live/abc123" for selfstreams or "rtsp://1.2.3.4/extron1" for auditoriums +// - end (time.Time) // the end of the stream for auditoriums or an end date far in the future for selfstreams. +// after StreamAction is done, the following values are set in ctx: +// - files ([]string) // a list of files that were created during the stream +func (a *ActionProvider) StreamAction() *Action { + return &Action{ + Type: StreamAction, + ActionFn: func(ctx context.Context, log *slog.Logger) (context.Context, error) { + // files will contain all files that were created during the stream + var files []string + + streamID, ok := ctx.Value("stream").(uint64) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain stream", ErrRequiredContextValNotFound) + } + courseID, ok := ctx.Value("course").(uint64) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain courseID", ErrRequiredContextValNotFound) + } + version, ok := ctx.Value("version").(string) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain version", ErrRequiredContextValNotFound) + } + source, ok := ctx.Value("source").(string) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain source", ErrRequiredContextValNotFound) + } + end, ok := ctx.Value("end").(time.Time) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain end", ErrRequiredContextValNotFound) + } + log.Info("streaming", "source", source, "end", end) + + streamAttempt := 0 + for time.Now().Before(end) && ctx.Err() == nil { + streamAttempt++ + filename := filepath.Join(a.GetRecDir(courseID, streamID, version), fmt.Sprintf("%d.ts", streamAttempt)) + files = append(files, filename) + livePlaylist := filepath.Join(a.GetLiveDir(courseID, streamID, version), "playlist.m3u8") + + cmd := "-y -hide_banner -nostats" + if strings.HasPrefix(source, "rtsp") { + cmd += " -rtsp_transport tcp" + } else if strings.HasPrefix(source, "rtmp") { + cmd += " -rw_timeout 5000000" // timeout selfstream s after 5 seconds of no data + } else { + cmd += " -re" // read input at native framerate, e.g. when streaming a file in realtime + } + + cmd += fmt.Sprintf(" -t %.0f", time.Until(end).Seconds()) + cmd += fmt.Sprintf(" -i %s", source) + cmd += " -c:v copy -c:a copy -f mpegts " + filename // write original stream to file for later processing + cmd += " -c:v libx264 -preset veryfast -tune zerolatency -maxrate 2500k -bufsize 3000k -g 60 -r 30 -x264-params keyint=60:scenecut=0 -c:a aac -ar 44100 -b:a 128k -f hls" + // todo optional stream target + cmd += " -hls_time 2 -hls_list_size 3600 -hls_playlist_type event -hls_flags append_list -hls_segment_filename " + filepath.Join(a.GetLiveDir(courseID, streamID, version), "/%05d.ts") + cmd += " " + livePlaylist + + c := exec.CommandContext(ctx, "ffmpeg", strings.Split(cmd, " ")...) + c.Stderr = os.Stderr + log.Info("constructed stream command", "cmd", c.String()) + err := c.Start() + if err != nil { + log.Warn("streamAction: ", err) + time.Sleep(5 * time.Second) // little backoff to prevent dossing source + continue + } + err = c.Wait() + if err != nil { + log.Warn("stream command exited", "err", err) + time.Sleep(5 * time.Second) // little backoff to prevent dossing source + continue + } + } + return set(ctx, "files", files), nil + }, + } +} diff --git a/runner/actions/transcode.go b/runner/actions/transcode.go new file mode 100644 index 000000000..a1059d9e2 --- /dev/null +++ b/runner/actions/transcode.go @@ -0,0 +1,36 @@ +package actions + +import ( + "context" + "log/slog" + "os/exec" + "time" +) + +func (a *ActionProvider) TranscodeAction() *Action { + return &Action{ + Type: TranscodeAction, + ActionFn: func(ctx context.Context, log *slog.Logger) (context.Context, error) { + files, ok := ctx.Value("files").([]string) + if !ok { + return ctx, ErrActionInputWrongType + } + log.Info("transcoding", "files", files) + time.Sleep(time.Second) + return ctx, nil + // parse output from previous streamAction + fileName, ok := ctx.Value("files").([]string) + if !ok { + return ctx, ErrActionInputWrongType + } + _ = "/mass/" + ctx.Value("streamID").(string) + ".mp4" + c := exec.CommandContext(ctx, "ffmpeg", fileName...) //, "...", output) + err := c.Start() + if err != nil { + return ctx, err + } + err = c.Wait() + return ctx, err + }, + } +} diff --git a/runner/actions/upload.go b/runner/actions/upload.go new file mode 100644 index 000000000..27dae23cc --- /dev/null +++ b/runner/actions/upload.go @@ -0,0 +1,15 @@ +package actions + +import ( + "context" + "log/slog" +) + +func (a *ActionProvider) UploadAction() *Action { + return &Action{ + Type: UploadAction, + ActionFn: func(ctx context.Context, log *slog.Logger) (context.Context, error) { + return ctx, nil + }, + } +} diff --git a/runner/cmd/runner/main.go b/runner/cmd/runner/main.go new file mode 100644 index 000000000..9addd6d70 --- /dev/null +++ b/runner/cmd/runner/main.go @@ -0,0 +1,49 @@ +package main + +import ( + "github.com/tum-dev/gocast/runner" + + "log/slog" + "os" + "os/signal" + "syscall" +) + +// V (Version) is bundled into binary with -ldflags "-X ..." +var V = "dev" + +func main() { + // ... + r := runner.NewRunner(V) + go r.Run() + + shouldShutdown := false // set to true once we receive a shutdown signal + + currentCount := 0 + go func() { + for { + currentCount = <-r.JobCount // wait for a job to finish + slog.Info("current job count", "count", currentCount) + if shouldShutdown && currentCount == 0 { // if we should shut down and no jobs are running, exit. + slog.Info("No jobs left, shutting down") + os.Exit(0) + } + } + }() + + osSignal := make(chan os.Signal, 1) + signal.Notify(osSignal, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1) + s := <-osSignal + slog.Info("Received signal", "signal", s) + shouldShutdown = true + r.Drain() + + if currentCount == 0 { + slog.Info("No jobs left, shutting down") + os.Exit(0) + } + + blocking := make(chan struct{}) + _ = <-blocking + +} diff --git a/runner/entrypoint.sh b/runner/entrypoint.sh new file mode 100644 index 000000000..913b534ee --- /dev/null +++ b/runner/entrypoint.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +exec /mediamtx & +exec /runner diff --git a/runner/go.mod b/runner/go.mod new file mode 100644 index 000000000..52e71a8ec --- /dev/null +++ b/runner/go.mod @@ -0,0 +1,19 @@ +module github.com/tum-dev/gocast/runner + +go 1.21.0 + +require ( + github.com/caarlos0/env v3.5.0+incompatible + github.com/dusted-go/logging v1.1.1 + github.com/golang/protobuf v1.5.3 + google.golang.org/grpc v1.58.2 + google.golang.org/protobuf v1.31.0 +) + +require ( + github.com/stretchr/testify v1.8.4 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect +) diff --git a/runner/go.sum b/runner/go.sum new file mode 100644 index 000000000..6a3f15052 --- /dev/null +++ b/runner/go.sum @@ -0,0 +1,33 @@ +github.com/caarlos0/env v3.5.0+incompatible h1:Yy0UN8o9Wtr/jGHZDpCBLpNrzcFLLM2yixi/rBrKyJs= +github.com/caarlos0/env v3.5.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dusted-go/logging v1.1.1 h1:x1aSyarDh2iq7MIhCZkjbepsZD9FmAURK93jRFm2Oco= +github.com/dusted-go/logging v1.1.1/go.mod h1:Lim3Rk6x2MYwpvPZ6XzPk6ZeX4Wgz9lVOptrL7ngr5w= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +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/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I= +google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/runner/handlers.go b/runner/handlers.go new file mode 100644 index 000000000..eec5a4387 --- /dev/null +++ b/runner/handlers.go @@ -0,0 +1,39 @@ +package runner + +import ( + "context" + "errors" + "github.com/tum-dev/gocast/runner/actions" + "github.com/tum-dev/gocast/runner/protobuf" +) + +func contextFromStreamReq(req *protobuf.StreamRequest, ctx context.Context) context.Context { + ctx = context.WithValue(ctx, "stream", req.GetStream()) + ctx = context.WithValue(ctx, "course", req.GetCourse()) + ctx = context.WithValue(ctx, "version", req.GetVersion()) + ctx = context.WithValue(ctx, "source", req.GetSource()) + return context.WithValue(ctx, "end", req.GetEnd().AsTime()) +} + +func (r *Runner) RequestStream(ctx context.Context, req *protobuf.StreamRequest) (*protobuf.StreamResponse, error) { + // don't reuse context from grpc, it will be canceled when the request is done. + ctx = context.Background() + ctx = contextFromStreamReq(req, ctx) + a := []*actions.Action{ + r.actions.PrepareAction(), + r.actions.StreamAction(), + r.actions.TranscodeAction(), + r.actions.UploadAction(), + } + jobID := r.AddJob(ctx, a) + + return &protobuf.StreamResponse{Job: jobID}, nil +} + +func (r *Runner) RequestStreamEnd(ctx context.Context, request *protobuf.StreamEndRequest) (*protobuf.StreamEndResponse, error) { + if job, ok := r.jobs[request.GetJobID()]; ok { + job.Cancel(errors.New("canceled by user request"), actions.StreamAction, actions.UploadAction) + return &protobuf.StreamEndResponse{}, nil + } + return nil, errors.New("job not found") +} diff --git a/runner/hls.go b/runner/hls.go new file mode 100644 index 000000000..ddb9ef584 --- /dev/null +++ b/runner/hls.go @@ -0,0 +1,28 @@ +package runner + +import ( + "log/slog" + "net/http" +) + +type HLSServer struct { + log *slog.Logger + fs http.Handler +} + +func NewHLSServer(LiveDir string, log *slog.Logger) *HLSServer { + return &HLSServer{fs: http.FileServer(http.Dir(LiveDir)), log: log} +} + +func (h *HLSServer) Start() error { + http.Handle("/", h) + h.log.Info("starting hls server", "port", 8187) + return http.ListenAndServe(":8187", nil) +} + +func (h *HLSServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + + h.log.Info("serving request", "path", r.URL.Path, "method", r.Method) + h.fs.ServeHTTP(w, r) +} diff --git a/runner/mediamtx.yml b/runner/mediamtx.yml new file mode 100644 index 000000000..122b6ce51 --- /dev/null +++ b/runner/mediamtx.yml @@ -0,0 +1,104 @@ + +############################################### +# General parameters + +# Sets the verbosity of the program; available values are "error", "warn", "info", "debug". +logLevel: debug +# Destinations of log messages; available values are "stdout", "file" and "syslog". +logDestinations: [stdout] + +# Timeout of read operations. +readTimeout: 10s +# Timeout of write operations. +writeTimeout: 10s +# Number of read buffers. +# A higher value allows a wider throughput, a lower value allows to save RAM. +readBufferCount: 512 +# Maximum size of payload of outgoing UDP packets. +# This can be decreased to avoid fragmentation on networks with a low UDP MTU. +udpMaxPayloadSize: 1472 + +# HTTP URL to perform external authentication. +# Every time a user wants to authenticate, the server calls this URL +# with the POST method and a body containing: +# { +# "ip": "ip", +# "user": "user", +# "password": "password", +# "path": "path", +# "protocol": "rtsp|rtmp|hls|webrtc", +# "id": "id", +# "action": "read|publish", +# "query": "query" +# } +# If the response code is 20x, authentication is accepted, otherwise +# it is discarded. +externalAuthenticationURL: http://localhost:8060/on_publish + +# Enable the HTTP API. +api: no +# Address of the API listener. +apiAddress: 127.0.0.1:9997 + +# Enable Prometheus-compatible metrics. +metrics: no +# Address of the metrics listener. +metricsAddress: 127.0.0.1:9998 + + +############################################### +# RTSP parameters + +# Disable support for the RTSP protocol. +rtspDisable: yes + +############################################### +# RTMP parameters + +# Disable support for the RTMP protocol. +rtmpDisable: no +# Address of the RTMP listener. This is needed only when encryption is "no" or "optional". +rtmpAddress: :1935 +# Encrypt connections with TLS (RTMPS). +# Available values are "no", "strict", "optional". +rtmpEncryption: "no" + +############################################### +# HLS parameters + +# Disable support for the HLS protocol. +hlsDisable: yes + +############################################### +# WebRTC parameters + +# Disable support for the WebRTC protocol. +webrtcDisable: yes + +############################################### +# Path parameters + +# These settings are path-dependent, and the map key is the name of the path. +# It's possible to use regular expressions by using a tilde as prefix. +# For example, "~^(test1|test2)$" will match both "test1" and "test2". +# For example, "~^prefix" will match all paths that start with "prefix". +# The settings under the path "all" are applied to all paths that do not match +# another entry. +paths: + all: + # Source of the stream. This can be: + # * publisher -> the stream is published by a RTSP or RTMP client + # * rtsp://existing-url -> the stream is pulled from another RTSP server / camera + # * rtsps://existing-url -> the stream is pulled from another RTSP server / camera with RTSPS + # * rtmp://existing-url -> the stream is pulled from another RTMP server / camera + # * rtmps://existing-url -> the stream is pulled from another RTMP server / camera with RTMPS + # * http://existing-url/stream.m3u8 -> the stream is pulled from another HLS server + # * https://existing-url/stream.m3u8 -> the stream is pulled from another HLS server with HTTPS + # * udp://ip:port -> the stream is pulled from UDP, by listening on the specified IP and port + # * redirect -> the stream is provided by another path or server + # * rpiCamera -> the stream is provided by a Raspberry Pi Camera + source: publisher + + # If the source is an RTSP or RTSPS URL, this is the protocol that will be used to + # pull the stream. available values are "automatic", "udp", "multicast", "tcp". + sourceProtocol: automatic diff --git a/runner/pkg/logging/grpc.go b/runner/pkg/logging/grpc.go new file mode 100644 index 000000000..8e95905a3 --- /dev/null +++ b/runner/pkg/logging/grpc.go @@ -0,0 +1,19 @@ +package logging + +import ( + "context" + "google.golang.org/grpc" + "log/slog" +) + +// GetGrpcLogInterceptor returns a grpc.ServerOption that logs all requests +func GetGrpcLogInterceptor(logger *slog.Logger) grpc.ServerOption { + return grpc.ChainUnaryInterceptor(grpcLogger(logger)) +} + +func grpcLogger(l *slog.Logger) grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + l.Info("gRPC call", "method", info.FullMethod, "request", req) + return handler(ctx, req) + } +} diff --git a/runner/pkg/logging/logging.go b/runner/pkg/logging/logging.go new file mode 100644 index 000000000..51e6d13d9 --- /dev/null +++ b/runner/pkg/logging/logging.go @@ -0,0 +1,43 @@ +package logging + +import ( + "log/slog" + "os" + "strings" + + "github.com/dusted-go/logging/prettylog" +) + +// GetLogger creates a *slog.Logger based on the environment, sets it as the default logger and returns it. +func GetLogger(v string) *slog.Logger { + lvlStr := os.Getenv("LOG_LEVEL") + var level slog.Level + switch strings.ToLower(lvlStr) { + case "debug": + level = slog.LevelDebug + case "info": + level = slog.LevelInfo + case "warn": + level = slog.LevelWarn + case "error": + level = slog.LevelError + default: + level = slog.LevelDebug + } + var logger *slog.Logger + if os.Getenv("LOG_FMT") == "json" { + logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + AddSource: true, + Level: level, + })) + } else { + logger = slog.New(prettylog.NewHandler(&slog.HandlerOptions{ + Level: level, + ReplaceAttr: func(_ []string, a slog.Attr) slog.Attr { + return a // don't replace any attributes + }, + })) + } + slog.SetDefault(logger) + return logger +} diff --git a/runner/pkg/netutil/netutil.go b/runner/pkg/netutil/netutil.go new file mode 100644 index 000000000..f3ae319ed --- /dev/null +++ b/runner/pkg/netutil/netutil.go @@ -0,0 +1,16 @@ +package netutil + +import "net" + +// GetFreePort returns a free port for tcp use. +func GetFreePort() (port int, err error) { + var a *net.TCPAddr + if a, err = net.ResolveTCPAddr("tcp", "localhost:0"); err == nil { + var l *net.TCPListener + if l, err = net.ListenTCP("tcp", a); err == nil { + defer l.Close() + return l.Addr().(*net.TCPAddr).Port, nil + } + } + return port, err +} diff --git a/runner/protobuf/runner.pb.go b/runner/protobuf/runner.pb.go new file mode 100644 index 000000000..15441a1f8 --- /dev/null +++ b/runner/protobuf/runner.pb.go @@ -0,0 +1,850 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.12.4 +// source: runner.proto + +package protobuf + +import ( + timestamp "github.com/golang/protobuf/ptypes/timestamp" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type StreamRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Stream uint64 `protobuf:"varint,1,opt,name=stream,proto3" json:"stream,omitempty"` + Course uint64 `protobuf:"varint,2,opt,name=course,proto3" json:"course,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + End *timestamp.Timestamp `protobuf:"bytes,4,opt,name=end,proto3" json:"end,omitempty"` + Source string `protobuf:"bytes,5,opt,name=source,proto3" json:"source,omitempty"` +} + +func (x *StreamRequest) Reset() { + *x = StreamRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamRequest) ProtoMessage() {} + +func (x *StreamRequest) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamRequest.ProtoReflect.Descriptor instead. +func (*StreamRequest) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{0} +} + +func (x *StreamRequest) GetStream() uint64 { + if x != nil { + return x.Stream + } + return 0 +} + +func (x *StreamRequest) GetCourse() uint64 { + if x != nil { + return x.Course + } + return 0 +} + +func (x *StreamRequest) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *StreamRequest) GetEnd() *timestamp.Timestamp { + if x != nil { + return x.End + } + return nil +} + +func (x *StreamRequest) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +type StreamResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Job string `protobuf:"bytes,1,opt,name=job,proto3" json:"job,omitempty"` +} + +func (x *StreamResponse) Reset() { + *x = StreamResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamResponse) ProtoMessage() {} + +func (x *StreamResponse) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamResponse.ProtoReflect.Descriptor instead. +func (*StreamResponse) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{1} +} + +func (x *StreamResponse) GetJob() string { + if x != nil { + return x.Job + } + return "" +} + +type StreamEndRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + JobID string `protobuf:"bytes,1,opt,name=jobID,proto3" json:"jobID,omitempty"` + KeepVod bool `protobuf:"varint,2,opt,name=keepVod,proto3" json:"keepVod,omitempty"` +} + +func (x *StreamEndRequest) Reset() { + *x = StreamEndRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamEndRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamEndRequest) ProtoMessage() {} + +func (x *StreamEndRequest) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamEndRequest.ProtoReflect.Descriptor instead. +func (*StreamEndRequest) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{2} +} + +func (x *StreamEndRequest) GetJobID() string { + if x != nil { + return x.JobID + } + return "" +} + +func (x *StreamEndRequest) GetKeepVod() bool { + if x != nil { + return x.KeepVod + } + return false +} + +type StreamEndResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *StreamEndResponse) Reset() { + *x = StreamEndResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamEndResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamEndResponse) ProtoMessage() {} + +func (x *StreamEndResponse) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamEndResponse.ProtoReflect.Descriptor instead. +func (*StreamEndResponse) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{3} +} + +type RegisterRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hostname string `protobuf:"bytes,1,opt,name=hostname,proto3" json:"hostname,omitempty"` + Port int32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"` +} + +func (x *RegisterRequest) Reset() { + *x = RegisterRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RegisterRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterRequest) ProtoMessage() {} + +func (x *RegisterRequest) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterRequest.ProtoReflect.Descriptor instead. +func (*RegisterRequest) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{4} +} + +func (x *RegisterRequest) GetHostname() string { + if x != nil { + return x.Hostname + } + return "" +} + +func (x *RegisterRequest) GetPort() int32 { + if x != nil { + return x.Port + } + return 0 +} + +type RegisterResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RegisterResponse) Reset() { + *x = RegisterResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RegisterResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RegisterResponse) ProtoMessage() {} + +func (x *RegisterResponse) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RegisterResponse.ProtoReflect.Descriptor instead. +func (*RegisterResponse) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{5} +} + +type HeartbeatRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ID uint64 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"` + Workload uint32 `protobuf:"varint,2,opt,name=Workload,proto3" json:"Workload,omitempty"` + Version string `protobuf:"bytes,3,opt,name=Version,proto3" json:"Version,omitempty"` + CPU string `protobuf:"bytes,4,opt,name=CPU,proto3" json:"CPU,omitempty"` + Memory string `protobuf:"bytes,5,opt,name=Memory,proto3" json:"Memory,omitempty"` + Disk string `protobuf:"bytes,6,opt,name=Disk,proto3" json:"Disk,omitempty"` + Uptime string `protobuf:"bytes,7,opt,name=Uptime,proto3" json:"Uptime,omitempty"` +} + +func (x *HeartbeatRequest) Reset() { + *x = HeartbeatRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HeartbeatRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HeartbeatRequest) ProtoMessage() {} + +func (x *HeartbeatRequest) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HeartbeatRequest.ProtoReflect.Descriptor instead. +func (*HeartbeatRequest) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{6} +} + +func (x *HeartbeatRequest) GetID() uint64 { + if x != nil { + return x.ID + } + return 0 +} + +func (x *HeartbeatRequest) GetWorkload() uint32 { + if x != nil { + return x.Workload + } + return 0 +} + +func (x *HeartbeatRequest) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *HeartbeatRequest) GetCPU() string { + if x != nil { + return x.CPU + } + return "" +} + +func (x *HeartbeatRequest) GetMemory() string { + if x != nil { + return x.Memory + } + return "" +} + +func (x *HeartbeatRequest) GetDisk() string { + if x != nil { + return x.Disk + } + return "" +} + +func (x *HeartbeatRequest) GetUptime() string { + if x != nil { + return x.Uptime + } + return "" +} + +type HeartbeatResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *HeartbeatResponse) Reset() { + *x = HeartbeatResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *HeartbeatResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*HeartbeatResponse) ProtoMessage() {} + +func (x *HeartbeatResponse) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use HeartbeatResponse.ProtoReflect.Descriptor instead. +func (*HeartbeatResponse) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{7} +} + +type SelfStreamRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StreamKey string `protobuf:"bytes,1,opt,name=streamKey,proto3" json:"streamKey,omitempty"` +} + +func (x *SelfStreamRequest) Reset() { + *x = SelfStreamRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SelfStreamRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SelfStreamRequest) ProtoMessage() {} + +func (x *SelfStreamRequest) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SelfStreamRequest.ProtoReflect.Descriptor instead. +func (*SelfStreamRequest) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{8} +} + +func (x *SelfStreamRequest) GetStreamKey() string { + if x != nil { + return x.StreamKey + } + return "" +} + +type SelfStreamResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Stream uint64 `protobuf:"varint,1,opt,name=stream,proto3" json:"stream,omitempty"` + Course uint64 `protobuf:"varint,2,opt,name=course,proto3" json:"course,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` +} + +func (x *SelfStreamResponse) Reset() { + *x = SelfStreamResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SelfStreamResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SelfStreamResponse) ProtoMessage() {} + +func (x *SelfStreamResponse) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SelfStreamResponse.ProtoReflect.Descriptor instead. +func (*SelfStreamResponse) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{9} +} + +func (x *SelfStreamResponse) GetStream() uint64 { + if x != nil { + return x.Stream + } + return 0 +} + +func (x *SelfStreamResponse) GetCourse() uint64 { + if x != nil { + return x.Course + } + return 0 +} + +func (x *SelfStreamResponse) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +var File_runner_proto protoreflect.FileDescriptor + +var file_runner_proto_rawDesc = []byte{ + 0x0a, 0x0c, 0x72, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9f, 0x01, 0x0a, 0x0d, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x75, 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x06, 0x63, 0x6f, 0x75, 0x72, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, + 0x65, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x22, 0x0a, 0x0e, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, + 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x22, + 0x42, 0x0a, 0x10, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x65, + 0x70, 0x56, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x6b, 0x65, 0x65, 0x70, + 0x56, 0x6f, 0x64, 0x22, 0x13, 0x0a, 0x11, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x68, + 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, + 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x12, 0x0a, 0x10, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0xae, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x02, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, + 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x43, 0x50, + 0x55, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x43, 0x50, 0x55, 0x12, 0x16, 0x0a, 0x06, + 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4d, 0x65, + 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x69, 0x73, 0x6b, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x44, 0x69, 0x73, 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x55, 0x70, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, + 0x22, 0x13, 0x0a, 0x11, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x0a, 0x11, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4b, 0x65, 0x79, 0x22, 0x5e, 0x0a, 0x12, 0x53, 0x65, 0x6c, 0x66, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, + 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x75, 0x72, 0x73, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x63, 0x6f, 0x75, 0x72, 0x73, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x32, 0x9f, 0x01, 0x0a, 0x08, 0x54, 0x6f, 0x52, + 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x44, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x10, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x12, + 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x45, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x32, 0xeb, 0x01, 0x0a, 0x0a, 0x46, + 0x72, 0x6f, 0x6d, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x43, 0x0a, 0x08, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, + 0x0a, 0x09, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x1a, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x11, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1b, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x11, 0x5a, 0x0f, 0x72, 0x75, 0x6e, 0x6e, + 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_runner_proto_rawDescOnce sync.Once + file_runner_proto_rawDescData = file_runner_proto_rawDesc +) + +func file_runner_proto_rawDescGZIP() []byte { + file_runner_proto_rawDescOnce.Do(func() { + file_runner_proto_rawDescData = protoimpl.X.CompressGZIP(file_runner_proto_rawDescData) + }) + return file_runner_proto_rawDescData +} + +var file_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_runner_proto_goTypes = []interface{}{ + (*StreamRequest)(nil), // 0: protobuf.StreamRequest + (*StreamResponse)(nil), // 1: protobuf.StreamResponse + (*StreamEndRequest)(nil), // 2: protobuf.StreamEndRequest + (*StreamEndResponse)(nil), // 3: protobuf.StreamEndResponse + (*RegisterRequest)(nil), // 4: protobuf.RegisterRequest + (*RegisterResponse)(nil), // 5: protobuf.RegisterResponse + (*HeartbeatRequest)(nil), // 6: protobuf.HeartbeatRequest + (*HeartbeatResponse)(nil), // 7: protobuf.HeartbeatResponse + (*SelfStreamRequest)(nil), // 8: protobuf.SelfStreamRequest + (*SelfStreamResponse)(nil), // 9: protobuf.SelfStreamResponse + (*timestamp.Timestamp)(nil), // 10: google.protobuf.Timestamp +} +var file_runner_proto_depIdxs = []int32{ + 10, // 0: protobuf.StreamRequest.end:type_name -> google.protobuf.Timestamp + 0, // 1: protobuf.ToRunner.RequestStream:input_type -> protobuf.StreamRequest + 2, // 2: protobuf.ToRunner.RequestStreamEnd:input_type -> protobuf.StreamEndRequest + 4, // 3: protobuf.FromRunner.Register:input_type -> protobuf.RegisterRequest + 6, // 4: protobuf.FromRunner.Heartbeat:input_type -> protobuf.HeartbeatRequest + 8, // 5: protobuf.FromRunner.RequestSelfStream:input_type -> protobuf.SelfStreamRequest + 1, // 6: protobuf.ToRunner.RequestStream:output_type -> protobuf.StreamResponse + 3, // 7: protobuf.ToRunner.RequestStreamEnd:output_type -> protobuf.StreamEndResponse + 5, // 8: protobuf.FromRunner.Register:output_type -> protobuf.RegisterResponse + 7, // 9: protobuf.FromRunner.Heartbeat:output_type -> protobuf.HeartbeatResponse + 9, // 10: protobuf.FromRunner.RequestSelfStream:output_type -> protobuf.SelfStreamResponse + 6, // [6:11] is the sub-list for method output_type + 1, // [1:6] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_runner_proto_init() } +func file_runner_proto_init() { + if File_runner_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_runner_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StreamRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StreamResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StreamEndRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StreamEndResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HeartbeatRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HeartbeatResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SelfStreamRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SelfStreamResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_runner_proto_rawDesc, + NumEnums: 0, + NumMessages: 10, + NumExtensions: 0, + NumServices: 2, + }, + GoTypes: file_runner_proto_goTypes, + DependencyIndexes: file_runner_proto_depIdxs, + MessageInfos: file_runner_proto_msgTypes, + }.Build() + File_runner_proto = out.File + file_runner_proto_rawDesc = nil + file_runner_proto_goTypes = nil + file_runner_proto_depIdxs = nil +} diff --git a/runner/protobuf/runner_grpc.pb.go b/runner/protobuf/runner_grpc.pb.go new file mode 100644 index 000000000..33a656cf9 --- /dev/null +++ b/runner/protobuf/runner_grpc.pb.go @@ -0,0 +1,303 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.2.0 +// - protoc v3.12.4 +// source: runner.proto + +package protobuf + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// ToRunnerClient is the client API for ToRunner service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type ToRunnerClient interface { + // Requests a stream from a lecture hall + RequestStream(ctx context.Context, in *StreamRequest, opts ...grpc.CallOption) (*StreamResponse, error) + RequestStreamEnd(ctx context.Context, in *StreamEndRequest, opts ...grpc.CallOption) (*StreamEndResponse, error) +} + +type toRunnerClient struct { + cc grpc.ClientConnInterface +} + +func NewToRunnerClient(cc grpc.ClientConnInterface) ToRunnerClient { + return &toRunnerClient{cc} +} + +func (c *toRunnerClient) RequestStream(ctx context.Context, in *StreamRequest, opts ...grpc.CallOption) (*StreamResponse, error) { + out := new(StreamResponse) + err := c.cc.Invoke(ctx, "/protobuf.ToRunner/RequestStream", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *toRunnerClient) RequestStreamEnd(ctx context.Context, in *StreamEndRequest, opts ...grpc.CallOption) (*StreamEndResponse, error) { + out := new(StreamEndResponse) + err := c.cc.Invoke(ctx, "/protobuf.ToRunner/RequestStreamEnd", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ToRunnerServer is the server API for ToRunner service. +// All implementations must embed UnimplementedToRunnerServer +// for forward compatibility +type ToRunnerServer interface { + // Requests a stream from a lecture hall + RequestStream(context.Context, *StreamRequest) (*StreamResponse, error) + RequestStreamEnd(context.Context, *StreamEndRequest) (*StreamEndResponse, error) + mustEmbedUnimplementedToRunnerServer() +} + +// UnimplementedToRunnerServer must be embedded to have forward compatible implementations. +type UnimplementedToRunnerServer struct { +} + +func (UnimplementedToRunnerServer) RequestStream(context.Context, *StreamRequest) (*StreamResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RequestStream not implemented") +} +func (UnimplementedToRunnerServer) RequestStreamEnd(context.Context, *StreamEndRequest) (*StreamEndResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RequestStreamEnd not implemented") +} +func (UnimplementedToRunnerServer) mustEmbedUnimplementedToRunnerServer() {} + +// UnsafeToRunnerServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to ToRunnerServer will +// result in compilation errors. +type UnsafeToRunnerServer interface { + mustEmbedUnimplementedToRunnerServer() +} + +func RegisterToRunnerServer(s grpc.ServiceRegistrar, srv ToRunnerServer) { + s.RegisterService(&ToRunner_ServiceDesc, srv) +} + +func _ToRunner_RequestStream_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StreamRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ToRunnerServer).RequestStream(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.ToRunner/RequestStream", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ToRunnerServer).RequestStream(ctx, req.(*StreamRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ToRunner_RequestStreamEnd_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StreamEndRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ToRunnerServer).RequestStreamEnd(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.ToRunner/RequestStreamEnd", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ToRunnerServer).RequestStreamEnd(ctx, req.(*StreamEndRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// ToRunner_ServiceDesc is the grpc.ServiceDesc for ToRunner service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var ToRunner_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "protobuf.ToRunner", + HandlerType: (*ToRunnerServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "RequestStream", + Handler: _ToRunner_RequestStream_Handler, + }, + { + MethodName: "RequestStreamEnd", + Handler: _ToRunner_RequestStreamEnd_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "runner.proto", +} + +// FromRunnerClient is the client API for FromRunner service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type FromRunnerClient interface { + // Register is a request to the server to join the runners pool. + Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) + Heartbeat(ctx context.Context, in *HeartbeatRequest, opts ...grpc.CallOption) (*HeartbeatResponse, error) + RequestSelfStream(ctx context.Context, in *SelfStreamRequest, opts ...grpc.CallOption) (*SelfStreamResponse, error) +} + +type fromRunnerClient struct { + cc grpc.ClientConnInterface +} + +func NewFromRunnerClient(cc grpc.ClientConnInterface) FromRunnerClient { + return &fromRunnerClient{cc} +} + +func (c *fromRunnerClient) Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) { + out := new(RegisterResponse) + err := c.cc.Invoke(ctx, "/protobuf.FromRunner/Register", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *fromRunnerClient) Heartbeat(ctx context.Context, in *HeartbeatRequest, opts ...grpc.CallOption) (*HeartbeatResponse, error) { + out := new(HeartbeatResponse) + err := c.cc.Invoke(ctx, "/protobuf.FromRunner/Heartbeat", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *fromRunnerClient) RequestSelfStream(ctx context.Context, in *SelfStreamRequest, opts ...grpc.CallOption) (*SelfStreamResponse, error) { + out := new(SelfStreamResponse) + err := c.cc.Invoke(ctx, "/protobuf.FromRunner/RequestSelfStream", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// FromRunnerServer is the server API for FromRunner service. +// All implementations must embed UnimplementedFromRunnerServer +// for forward compatibility +type FromRunnerServer interface { + // Register is a request to the server to join the runners pool. + Register(context.Context, *RegisterRequest) (*RegisterResponse, error) + Heartbeat(context.Context, *HeartbeatRequest) (*HeartbeatResponse, error) + RequestSelfStream(context.Context, *SelfStreamRequest) (*SelfStreamResponse, error) + mustEmbedUnimplementedFromRunnerServer() +} + +// UnimplementedFromRunnerServer must be embedded to have forward compatible implementations. +type UnimplementedFromRunnerServer struct { +} + +func (UnimplementedFromRunnerServer) Register(context.Context, *RegisterRequest) (*RegisterResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Register not implemented") +} +func (UnimplementedFromRunnerServer) Heartbeat(context.Context, *HeartbeatRequest) (*HeartbeatResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Heartbeat not implemented") +} +func (UnimplementedFromRunnerServer) RequestSelfStream(context.Context, *SelfStreamRequest) (*SelfStreamResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RequestSelfStream not implemented") +} +func (UnimplementedFromRunnerServer) mustEmbedUnimplementedFromRunnerServer() {} + +// UnsafeFromRunnerServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to FromRunnerServer will +// result in compilation errors. +type UnsafeFromRunnerServer interface { + mustEmbedUnimplementedFromRunnerServer() +} + +func RegisterFromRunnerServer(s grpc.ServiceRegistrar, srv FromRunnerServer) { + s.RegisterService(&FromRunner_ServiceDesc, srv) +} + +func _FromRunner_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RegisterRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FromRunnerServer).Register(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.FromRunner/Register", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FromRunnerServer).Register(ctx, req.(*RegisterRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _FromRunner_Heartbeat_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HeartbeatRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FromRunnerServer).Heartbeat(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.FromRunner/Heartbeat", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FromRunnerServer).Heartbeat(ctx, req.(*HeartbeatRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _FromRunner_RequestSelfStream_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SelfStreamRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FromRunnerServer).RequestSelfStream(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.FromRunner/RequestSelfStream", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FromRunnerServer).RequestSelfStream(ctx, req.(*SelfStreamRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// FromRunner_ServiceDesc is the grpc.ServiceDesc for FromRunner service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var FromRunner_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "protobuf.FromRunner", + HandlerType: (*FromRunnerServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Register", + Handler: _FromRunner_Register_Handler, + }, + { + MethodName: "Heartbeat", + Handler: _FromRunner_Heartbeat_Handler, + }, + { + MethodName: "RequestSelfStream", + Handler: _FromRunner_RequestSelfStream_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "runner.proto", +} diff --git a/runner/runner.go b/runner/runner.go new file mode 100644 index 000000000..44473ff3b --- /dev/null +++ b/runner/runner.go @@ -0,0 +1,244 @@ +package runner + +import ( + "context" + "github.com/caarlos0/env" + "github.com/google/uuid" + "github.com/tum-dev/gocast/runner/actions" + "github.com/tum-dev/gocast/runner/pkg/logging" + "github.com/tum-dev/gocast/runner/pkg/netutil" + "github.com/tum-dev/gocast/runner/protobuf" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/keepalive" + "google.golang.org/grpc/reflection" + + "fmt" + "log/slog" + "net" + "os" + "time" +) + +type config struct { + LogFmt string `env:"LOG_FMT" envDefault:"txt"` + LogLevel string `env:"LOG_LEVEL" envDefault:"debug"` + Port int `env:"PORT" envDefault:"0"` + StoragePath string `env:"STORAGE_PATH" envDefault:"storage/mass"` + SegmentPath string `env:"SEGMENT_PATH" envDefault:"storage/live"` + RecPath string `env:"REC_PATH" envDefault:"storage/rec"` + GocastServer string `env:"GOCAST_SERVER" envDefault:"localhost:50056"` + Hostname string `env:"REALHOST" envDefault:"localhost"` +} + +type Runner struct { + cfg config + log *slog.Logger + + JobCount chan int + draining bool + jobs map[string]*Job + + actions actions.ActionProvider + hlsServer *HLSServer + + protobuf.UnimplementedToRunnerServer +} + +func NewRunner(v string) *Runner { + log := logging.GetLogger(v) + var cfg config + if err := env.Parse(&cfg); err != nil { + log.Error("error parsing config", "error", err) + } + log.Info("config loaded", "config", cfg) + + return &Runner{ + log: log, + JobCount: make(chan int, 1), + draining: false, + cfg: cfg, + jobs: make(map[string]*Job), + actions: actions.ActionProvider{ + Log: log, + SegmentDir: cfg.SegmentPath, + RecDir: cfg.RecPath, + MassDir: cfg.StoragePath, + }, + hlsServer: NewHLSServer(cfg.SegmentPath, log.WithGroup("HLSServer")), + } +} + +func (r *Runner) Run() { + r.log.Info("Running!") + if r.cfg.Port == 0 { + r.log.Info("Getting free port") + p, err := netutil.GetFreePort() + if err != nil { + r.log.Error("Failed to get free port", "error", err) + os.Exit(1) + } + r.cfg.Port = p + } + r.log.Info("using port", "port", r.cfg.Port) + + go r.InitApiGrpc() + go r.hlsServer.Start() + + r.RegisterWithGocast(5) + r.log.Info("successfully connected to gocast") +} + +func (r *Runner) Drain() { + r.log.Info("Runner set to drain.") + r.draining = true +} + +func (r *Runner) InitApiGrpc() { + r.log.Info("Starting gRPC server", "port", r.cfg.Port) + lis, err := net.Listen("tcp", fmt.Sprintf(":%d", r.cfg.Port)) + if err != nil { + r.log.Error("failed to listen", "error", err) + os.Exit(1) + } + grpcServer := grpc.NewServer(grpc.KeepaliveParams(keepalive.ServerParameters{ + MaxConnectionIdle: time.Minute, + MaxConnectionAge: time.Minute, + MaxConnectionAgeGrace: time.Second * 5, + Time: time.Minute * 10, + Timeout: time.Second * 20, + }), logging.GetGrpcLogInterceptor(r.log)) + protobuf.RegisterToRunnerServer(grpcServer, r) + + reflection.Register(grpcServer) + if err := grpcServer.Serve(lis); err != nil { + r.log.Error("failed to serve", "error", err) + os.Exit(1) + } + +} + +const registerRetries = 5 + +func (r *Runner) RegisterWithGocast(retries int) { + r.log.Debug("connecting with gocast", slog.Group("conn", "host", r.cfg.GocastServer, "retriesLeft", retries)) + if retries == 0 { + r.log.Error("no more retries left, can't connect to gocast") + os.Exit(1) + } + con, err := r.dialIn() + if err != nil { + r.log.Warn("error connecting to gocast", "error", err, "sleeping(s)", registerRetries-retries) + time.Sleep(time.Second * time.Duration(registerRetries-retries)) + r.RegisterWithGocast(retries - 1) + return + } + _, err = con.Register(context.Background(), &protobuf.RegisterRequest{Hostname: r.cfg.Hostname, Port: int32(r.cfg.Port)}) + if err != nil { + r.log.Warn("error registering with gocast", "error", err, "sleeping(s)", registerRetries-retries) + time.Sleep(time.Second * time.Duration(registerRetries-retries)) + r.RegisterWithGocast(retries - 1) + return + } +} + +// dialIn connects to manager instance and returns a client +func (r *Runner) dialIn() (protobuf.FromRunnerClient, error) { + credentials := insecure.NewCredentials() + conn, err := grpc.Dial(r.cfg.GocastServer, grpc.WithTransportCredentials(credentials)) + if err != nil { + return nil, err + } + return protobuf.NewFromRunnerClient(conn), nil +} + +type Job struct { + ID string + Actions []*actions.Action + + Log *slog.Logger +} + +// Run triggers all actions in the job sequentially. +func (j *Job) Run(ctx context.Context) { + for i := range j.Actions { + if j.Actions[i].Canceled { + j.Log.Info("skipping action because it was canceled", "action", j.Actions[i].Type) + continue + } + // create new context to make each action cancelable individually + actionContext, cancel := context.WithCancelCause(ctx) + j.Actions[i].Cancel = cancel + j.Log.Info("running action", "action", j.Actions[i].Type) + c, err := j.Actions[i].ActionFn(actionContext, j.Log.With("action", j.Actions[i].Type)) + if err != nil { + // ensure context is canceled even on error + j.Log.Error("action failed", "error", err, "action", j.Actions[i].Type) + j.Actions[i].Cancel(err) + return + } + // pass context to next action without cancel + ctx = context.WithoutCancel(c) + + j.Actions[i].Cancel(nil) + } +} + +func (j *Job) Cancel(reason error, actionTypes ...actions.ActionType) { + for i := len(j.Actions) - 1; i >= 0; i-- { // cancel actions in reverse order to ensure all actions are canceled when they run + for _, actionType := range actionTypes { + if j.Actions[i].Type == actionType { + if j.Actions[i].Cancel != nil { + // action already running -> cancel context + j.Actions[i].Cancel(reason) + } + // set canceled flag -> stop action from being started + j.Actions[i].Canceled = true + } + } + } + j.Log.Info("job canceled", "reason", reason) +} + +// AddJob adds a job to the runner and starts it. +func (r *Runner) AddJob(ctx context.Context, a []*actions.Action) string { + jobID := uuid.New().String() + r.jobs[jobID] = &Job{ + ID: jobID, + Actions: a, + + Log: enrichLogger(r.log, ctx).With("jobID", jobID), + } + // notify main loop about current job count + r.JobCount <- len(r.jobs) + done := make(chan struct{}) + + go func() { + defer func() { done <- struct{}{} }() + r.jobs[jobID].Run(ctx) + }() + go func() { + select { + case d := <-done: + // update job count and remove job from map after it's done + r.log.Info("job cancelled", "jobID", jobID, "reason", ctx.Err(), "cancelReason", d) + delete(r.jobs, jobID) + r.JobCount <- len(r.jobs) + } + }() + return jobID +} + +// enrichLogger adds StreamID, CourseID, Version to the logger if present in the context +func enrichLogger(log *slog.Logger, ctx context.Context) *slog.Logger { + if streamID, ok := ctx.Value("stream").(uint64); ok { + log = log.With("streamID", streamID) + } + if courseID, ok := ctx.Value("course").(uint64); ok { + log = log.With("courseID", courseID) + } + if version, ok := ctx.Value("version").(string); ok { + log = log.With("version", version) + } + return log +} diff --git a/runner/runner.proto b/runner/runner.proto new file mode 100644 index 000000000..0cad3659a --- /dev/null +++ b/runner/runner.proto @@ -0,0 +1,70 @@ +syntax = "proto3"; +package protobuf; +option go_package = "runner/protobuf"; + +import "google/protobuf/timestamp.proto"; + +service ToRunner { + // Requests a stream from a lecture hall + rpc RequestStream (StreamRequest) returns (StreamResponse) {} + rpc RequestStreamEnd (StreamEndRequest) returns (StreamEndResponse) {} +} + +message StreamRequest { + uint64 stream = 1; + uint64 course = 2; + string version = 3; + google.protobuf.Timestamp end = 4; + string source = 5; +} + + +message StreamResponse { + string job = 1; +} + +message StreamEndRequest { + string jobID = 1; + bool keepVod = 2; +} + +message StreamEndResponse {} + +// FromRunner service defines communication from runners to gocast +service FromRunner { + // Register is a request to the server to join the runners pool. + rpc Register (RegisterRequest) returns (RegisterResponse) {} + rpc Heartbeat (HeartbeatRequest) returns (HeartbeatResponse) {} + rpc RequestSelfStream (SelfStreamRequest) returns (SelfStreamResponse) {} +} + +message RegisterRequest { + string hostname = 1; + int32 port = 2; +} + +message RegisterResponse { +} + +message HeartbeatRequest { + uint64 ID = 1; + uint32 Workload = 2; + string Version = 3; + string CPU = 4; + string Memory = 5; + string Disk = 6; + string Uptime = 7; +} + +message HeartbeatResponse {} + +message SelfStreamRequest { + string streamKey = 1; +} + +message SelfStreamResponse { + uint64 stream = 1; + uint64 course = 2; + string version = 3; +} + diff --git a/tools/stream-signing.go b/tools/stream-signing.go index 60ff1af01..0c61f034c 100644 --- a/tools/stream-signing.go +++ b/tools/stream-signing.go @@ -2,8 +2,8 @@ package tools import ( "fmt" - "github.com/golang-jwt/jwt/v4" "github.com/TUM-Dev/gocast/model" + "github.com/golang-jwt/jwt/v4" "strings" "time" ) @@ -33,7 +33,7 @@ func SetSignedPlaylists(s *model.Stream, user *model.User, allowDownloading bool } for _, playlist := range playlists { - if strings.Contains(playlist.Playlist, "lrz.de") { // todo: remove after migration from lrz services + if strings.Contains(playlist.Playlist, "localhost") || strings.Contains(playlist.Playlist, "lrz.de") { // todo: remove after migration from lrz services continue } From 7ed30f7035435e6b37b34f36dc6bf2f76605aa08 Mon Sep 17 00:00:00 2001 From: Dawin Yurtseven Date: Fri, 1 Dec 2023 16:32:17 +0100 Subject: [PATCH 02/31] First Push of the Runner: - Actions refined and now with postman, working selfstream requests - A site page development has begun with the needed functionality of heartbeats still in development for the response - the model/runner.go and dao/runner.go have been edited to work better with existing functionalities TODO: - Thumbnail.go still needs tweaking - rest implementations need to be done - having the runners be displayed onto the webpage please text me over element or github if there is anything I forgot to mention in this push --- .idea/vcs.xml | 1 - api/runner_grpc.go | 25 +- dao/runner.go | 8 + model/runner.go | 31 + runner/actions/actions.go | 6 +- runner/actions/stream.go | 36 +- runner/actions/thumbnail.go | 95 + runner/actions/transcode.go | 52 +- runner/cmd.yaml | 4 + runner/cmd/runner/main.go | 1 - runner/config/cmd.go | 29 + runner/go.mod | 8 + runner/go.sum | 48 + runner/handlers.go | 10 + runner/protobuf/runner.pb.go | 1813 ++++++++++++++++--- runner/protobuf/runner_grpc.pb.go | 362 +++- runner/runner.go | 20 +- runner/runner.proto | 126 +- web/admin.go | 17 +- web/router.go | 3 +- web/template/admin/admin.gohtml | 16 + web/template/admin/admin_tabs/runner.gohtml | 54 + 22 files changed, 2513 insertions(+), 252 deletions(-) create mode 100644 runner/actions/thumbnail.go create mode 100644 runner/cmd.yaml create mode 100644 runner/config/cmd.go create mode 100644 web/template/admin/admin_tabs/runner.gohtml diff --git a/.idea/vcs.xml b/.idea/vcs.xml index da8735dd0..94a25f7f4 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,6 +2,5 @@ - \ No newline at end of file diff --git a/api/runner_grpc.go b/api/runner_grpc.go index 68373cbe1..d286d435a 100644 --- a/api/runner_grpc.go +++ b/api/runner_grpc.go @@ -27,6 +27,8 @@ func (g GrpcRunnerServer) Register(ctx context.Context, request *protobuf.Regist Hostname: request.Hostname, Port: int(request.Port), LastSeen: sql.NullTime{Valid: true, Time: time.Now()}, + Status: "Alive", + Workload: 0, } err := g.RunnerDao.Create(ctx, &runner) if err != nil { @@ -36,8 +38,27 @@ func (g GrpcRunnerServer) Register(ctx context.Context, request *protobuf.Regist } func (g GrpcRunnerServer) Heartbeat(ctx context.Context, request *protobuf.HeartbeatRequest) (*protobuf.HeartbeatResponse, error) { - //TODO implement me - panic("implement me") + runner := model.Runner{ + Hostname: request.Hostname, + Port: int(request.Port), + LastSeen: sql.NullTime{Valid: true, Time: time.Now()}, + Status: "Alive", + Workload: uint(request.Workload), + CPU: request.CPU, + Memory: request.Memory, + Disk: request.Disk, + Uptime: request.Uptime, + Version: request.Version, + } + + r, err := g.RunnerDao.Get(ctx, runner.Hostname) + if err != nil { + log.WithError(err).Error("Failed to get runner") + return &protobuf.HeartbeatResponse{Ok: false}, err + } + + p, err := r.UpdateStats(dao.DB, ctx) + return &protobuf.HeartbeatResponse{Ok: p}, err } func (g GrpcRunnerServer) RequestSelfStream(ctx context.Context, request *protobuf.SelfStreamRequest) (*protobuf.SelfStreamResponse, error) { diff --git a/dao/runner.go b/dao/runner.go index 682aa1944..d5ee21176 100644 --- a/dao/runner.go +++ b/dao/runner.go @@ -13,6 +13,9 @@ type RunnerDao interface { // Get Runner by hostname Get(context.Context, string) (model.Runner, error) + // Get all Runners in an array + GetAll(context.Context) ([]model.Runner, error) + // Create a new Runner for the database Create(context.Context, *model.Runner) error @@ -33,6 +36,11 @@ func (d runnerDao) Get(c context.Context, hostname string) (res model.Runner, er return res, DB.WithContext(c).First(&res, "hostname = ?", hostname).Error } +// Get all Runners in an array +func (d runnerDao) GetAll(c context.Context) (res []model.Runner, err error) { + return res, d.db.WithContext(c).Model(&model.Runner{}).Find(&res).Error +} + // Create a Runner. func (d runnerDao) Create(c context.Context, it *model.Runner) error { return DB.WithContext(c).Clauses(clause.OnConflict{ diff --git a/model/runner.go b/model/runner.go index 710a96348..71552b136 100644 --- a/model/runner.go +++ b/model/runner.go @@ -1,9 +1,11 @@ package model import ( + "context" "database/sql" "errors" "gorm.io/gorm" + "time" ) // Runner represents a runner that creates, converts and postprocesses streams and does other heavy lifting. @@ -11,6 +13,14 @@ type Runner struct { Hostname string `gorm:"primaryKey"` Port int LastSeen sql.NullTime + + Status string + Workload uint + CPU string + Memory string + Disk string + Uptime string + Version string } // BeforeCreate returns errors if hostnames and ports of workers are invalid. @@ -23,3 +33,24 @@ func (r *Runner) BeforeCreate(tx *gorm.DB) (err error) { } return nil } + +// SendHeartbeat updates the last seen time of the runner and gives runner stats +func (r *Runner) UpdateStats(tx *gorm.DB, context context.Context) (bool, error) { + + tx.Model(&r).Updates(Runner{ + LastSeen: sql.NullTime{Time: tx.NowFunc(), Valid: true}, + Status: r.Status, + Workload: r.Workload, + CPU: r.CPU, + Memory: r.Memory, + Disk: r.Disk, + Uptime: r.Uptime, + Version: r.Version, + }) + + return true, nil +} + +func (r *Runner) isAlive() bool { + return r.LastSeen.Time.After(time.Now().Add(time.Minute * -6)) +} diff --git a/runner/actions/actions.go b/runner/actions/actions.go index f8ff7ae68..333da8a4e 100644 --- a/runner/actions/actions.go +++ b/runner/actions/actions.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "github.com/tum-dev/gocast/runner/config" "log/slog" "path" ) @@ -14,8 +15,8 @@ var ( ) type ActionProvider struct { - Log *slog.Logger - + Log *slog.Logger + Cmd config.CmdList SegmentDir string // for storing live hls segments locally. This should be fast storage (e.g. ssd). RecDir string // for storing recordings locally. MassDir string // for storing final files like Thumbnails, mp4s, ... Mass storage like Ceph. @@ -40,6 +41,7 @@ const ( StreamAction = "stream" TranscodeAction = "transcode" UploadAction = "upload" + ThumbnailAction = "thumbnail" ) type Action struct { diff --git a/runner/actions/stream.go b/runner/actions/stream.go index 412c08858..4874b33bd 100644 --- a/runner/actions/stream.go +++ b/runner/actions/stream.go @@ -11,7 +11,7 @@ import ( "time" ) -var edgeTemplate = "%s://%s/live/%s/%d-%s/playlist.m3u8" // e.g. "https://stream.domain.com/workerhostname123/1-COMB/playlist.m3u8" +//var edgeTemplate = "%s://%s/live/%s/%d-%s/playlist.m3u8" // e.g. "https://stream.domain.com/workerhostname123/1-COMB/playlist.m3u8" // StreamAction streams a video. in is ignored. out is a []string containing the filenames of the recorded stream. // ctx must contain the following values: @@ -49,36 +49,40 @@ func (a *ActionProvider) StreamAction() *Action { if !ok { return ctx, fmt.Errorf("%w: context doesn't contain end", ErrRequiredContextValNotFound) } - log.Info("streaming", "source", source, "end", end) + log.Info("streaming", "source", source, "end", time.Now().Second()+end.Second()) + + endingTime := time.Now().Add(time.Second * time.Duration(end.Second())) + log.Info("streaming until", "end", endingTime) streamAttempt := 0 - for time.Now().Before(end) && ctx.Err() == nil { + for time.Now().Before(endingTime) && ctx.Err() == nil { streamAttempt++ filename := filepath.Join(a.GetRecDir(courseID, streamID, version), fmt.Sprintf("%d.ts", streamAttempt)) files = append(files, filename) - livePlaylist := filepath.Join(a.GetLiveDir(courseID, streamID, version), "playlist.m3u8") + livePlaylist := filepath.Join(a.GetLiveDir(courseID, streamID, version), endingTime.Format("15-04-05"), "playlist.m3u8") + err := os.Mkdir(a.GetLiveDir(courseID, streamID, version)+"/"+endingTime.Format("15-04-05"), 0700) + if err != nil { + log.Warn("streamAction: stream folder couldn't be created", err) + time.Sleep(5 * time.Second) // little backoff to prevent dossing source + continue + } - cmd := "-y -hide_banner -nostats" + src := "" if strings.HasPrefix(source, "rtsp") { - cmd += " -rtsp_transport tcp" + src += "-rtsp_transport tcp" } else if strings.HasPrefix(source, "rtmp") { - cmd += " -rw_timeout 5000000" // timeout selfstream s after 5 seconds of no data + src += "-rw_timeout 5000000" // timeout selfstream s after 5 seconds of no data } else { - cmd += " -re" // read input at native framerate, e.g. when streaming a file in realtime + src += "-re" // read input at native framerate, e.g. when streaming a file in realtime } - cmd += fmt.Sprintf(" -t %.0f", time.Until(end).Seconds()) - cmd += fmt.Sprintf(" -i %s", source) - cmd += " -c:v copy -c:a copy -f mpegts " + filename // write original stream to file for later processing - cmd += " -c:v libx264 -preset veryfast -tune zerolatency -maxrate 2500k -bufsize 3000k -g 60 -r 30 -x264-params keyint=60:scenecut=0 -c:a aac -ar 44100 -b:a 128k -f hls" - // todo optional stream target - cmd += " -hls_time 2 -hls_list_size 3600 -hls_playlist_type event -hls_flags append_list -hls_segment_filename " + filepath.Join(a.GetLiveDir(courseID, streamID, version), "/%05d.ts") - cmd += " " + livePlaylist + //changing the end variable from a date to a duration and adding the duration to the current time + cmd := fmt.Sprintf(a.Cmd.Stream, src, time.Until(endingTime).Seconds(), source, filename, filepath.Join(a.GetLiveDir(courseID, streamID, version), endingTime.Format("15-04-05")), livePlaylist) c := exec.CommandContext(ctx, "ffmpeg", strings.Split(cmd, " ")...) c.Stderr = os.Stderr log.Info("constructed stream command", "cmd", c.String()) - err := c.Start() + err = c.Start() if err != nil { log.Warn("streamAction: ", err) time.Sleep(5 * time.Second) // little backoff to prevent dossing source diff --git a/runner/actions/thumbnail.go b/runner/actions/thumbnail.go new file mode 100644 index 000000000..43ccf404e --- /dev/null +++ b/runner/actions/thumbnail.go @@ -0,0 +1,95 @@ +package actions + +import ( + "context" + "fmt" + "github.com/joschahenningsen/thumbgen" + "io" + "log/slog" + "os" +) + +const ( + //ThumbWidth = 160 + LargeThumbWidth = 720 + Compression = 90 +) + +// GenerateVideoThumbnail generate a Thumbnail from the stream the runner just run. +// it will also check if it was the first to generate a thumbnail for the stream. if it wasn't, +// it will combine the two generated thumbnails into one/* +func (a *ActionProvider) GenerateVideoThumbnail() *Action { + return &Action{ + Type: ThumbnailAction, + ActionFn: func(ctx context.Context, log *slog.Logger) (context.Context, error) { + pathForThumb := a.MassDir + pathForRec := a.RecDir + nameOfFile := fmt.Sprintf("%x-thumb-1", ctx.Value("")) + g, err := thumbgen.New(pathForRec, LargeThumbWidth, 1, "", thumbgen.WithJpegCompression(Compression)) + if err != nil { + log.Error("couldn't generate new thumbnail generator") + return ctx, err + } + file, err := g.GenerateOne() + if err != nil { + log.Error("couldn't create a Thumbnail in the middle of the Stream") + return ctx, err + } + thumb, err := os.Open(file) + if err != nil { + log.Error("couldn't open the Thumbnail") + return ctx, err + } + if _, err := os.Stat(fmt.Sprintf("%x", pathForThumb)); os.IsNotExist(err) { + openFile, err := os.OpenFile(fmt.Sprintf("%x/%x", pathForThumb, nameOfFile), os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + log.Error("couldn't open the file for the Thumbnail") + return ctx, err + } + defer openFile.Close() + _, err = io.Copy(openFile, thumb) + if err != nil { + log.Error("couldn't copy the Thumbnail to the file") + return ctx, err + } + err = os.Remove(file) + if err != nil { + log.Error("couldn't remove the Thumbnail") + } + } else { + thumpOne := fmt.Sprintf("%x/%x", pathForThumb, nameOfFile) + nameOfFile := fmt.Sprintf("%x-2", nameOfFile) + openFile, err := os.OpenFile(fmt.Sprintf("%x/%x", pathForThumb, nameOfFile), os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + log.Error("couldn't open the file for the Thumbnail") + return ctx, err + } + defer openFile.Close() + _, err = io.Copy(openFile, thumb) + if err != nil { + log.Error("couldn't copy the Thumbnail to the file") + return ctx, err + } + err = os.Remove(file) + if err != nil { + log.Error("couldn't remove the Thumbnail") + } + err = thumbgen.CombineThumbs(thumpOne, nameOfFile, pathForThumb) + if err != nil { + log.Error("couldn't combine the Thumbnails") + } + } + + return ctx, nil + }, + } +} + +func (a *ActionProvider) GenerateThumbnailSprite() *Action { + return &Action{ + Type: ThumbnailAction, + ActionFn: func(ctx context.Context, log *slog.Logger) (context.Context, error) { + return ctx, nil + }, + } +} diff --git a/runner/actions/transcode.go b/runner/actions/transcode.go index a1059d9e2..dbe0eb031 100644 --- a/runner/actions/transcode.go +++ b/runner/actions/transcode.go @@ -2,8 +2,12 @@ package actions import ( "context" + "errors" + "fmt" "log/slog" + "os" "os/exec" + "strings" "time" ) @@ -15,17 +19,57 @@ func (a *ActionProvider) TranscodeAction() *Action { if !ok { return ctx, ErrActionInputWrongType } + if files == nil { + log.Error("no files to transcode", "files", files) + return ctx, ErrRequiredContextValNotFound + } + streamID, ok := ctx.Value("stream").(uint64) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain stream", ErrRequiredContextValNotFound) + } + courseID, ok := ctx.Value("course").(uint64) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain course", ErrRequiredContextValNotFound) + } + version, ok := ctx.Value("version").(string) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain version", ErrRequiredContextValNotFound) + } + log.Info("transcoding", "files", files) time.Sleep(time.Second) - return ctx, nil // parse output from previous streamAction fileName, ok := ctx.Value("files").([]string) if !ok { return ctx, ErrActionInputWrongType } - _ = "/mass/" + ctx.Value("streamID").(string) + ".mp4" - c := exec.CommandContext(ctx, "ffmpeg", fileName...) //, "...", output) - err := c.Start() + filenames := "" + if len(fileName) == 1 { + filenames = fileName[0] + } else { + filenames := `"concat:` + fileName[0] + for i := 1; i < len(fileName); i++ { + filenames += "|" + fileName[i] + } + filenames += `"` + } + + outputName := a.GetMassDir(courseID, streamID, version) + "/" + time.Now().Format("2006-01-02") + ".mp4" + i := 1 + _, err := os.Stat(outputName) + for err == nil { + if errors.Is(err, os.ErrNotExist) { + break + } + outputName = fmt.Sprintf(a.GetMassDir(courseID, streamID, version)+"/"+time.Now().Format("2006-01-02")+"_%d"+".mp4", i) + _, err = os.Stat(outputName) + i++ + } + + cmd := fmt.Sprintf(a.Cmd.Transcoding, filenames, outputName) + c := exec.CommandContext(ctx, "ffmpeg", strings.Split(cmd, " ")...) + c.Stderr = os.Stderr + err = c.Start() if err != nil { return ctx, err } diff --git a/runner/cmd.yaml b/runner/cmd.yaml new file mode 100644 index 000000000..6ee27fa3f --- /dev/null +++ b/runner/cmd.yaml @@ -0,0 +1,4 @@ +stream: '-y -hide_banner -nostats %v -t %.0f -i %v -c:v copy -c:a copy -f mpegts %v -c:v libx264 -preset veryfast -tune zerolatency -maxrate 2500k -bufsize 3000k -g 60 -r 30 -x264-params keyint=60:scenecut=0 -c:a aac -ar 44100 -b:a 128k -f hls -hls_time 2 -hls_list_size 3600 -hls_playlist_type event -hls_flags append_list -hls_segment_filename %v/%%05d.ts %v' + +Transcoding: '-i %v -c:v libx264 %v' + diff --git a/runner/cmd/runner/main.go b/runner/cmd/runner/main.go index 9addd6d70..c3b70683c 100644 --- a/runner/cmd/runner/main.go +++ b/runner/cmd/runner/main.go @@ -2,7 +2,6 @@ package main import ( "github.com/tum-dev/gocast/runner" - "log/slog" "os" "os/signal" diff --git a/runner/config/cmd.go b/runner/config/cmd.go new file mode 100644 index 000000000..ae84ceb63 --- /dev/null +++ b/runner/config/cmd.go @@ -0,0 +1,29 @@ +package config + +import ( + "github.com/ghodss/yaml" + "log/slog" + "os" + "path/filepath" +) + +type CmdList struct { + //this is for adding extra parameters + Stream string `Default:"-y -hide_banner -nostats %x -t &.0f -i %s -c:v copy -c:a copy -f mpegts %x -c:v libx264 -preset veryfast -tune zerolatency -maxrate 2500k -bufsize 3000k -g 60 -r 30 -x264-params keyint=60:scenecut=0 -c:a aac -ar 44100 -b:a 128k -f hls -hls_time 2 -hls_list_size 3600 -hls_playlist_type event -hls_flags append_list -hls_segment_filename %x %x"` + Transcoding string `Default:"-i %v -c:v libx264 %v"` +} + +func NewCmd(log *slog.Logger) *CmdList { + var c CmdList + path, _ := filepath.Abs("cmd.yaml") + YamlFile, err := os.ReadFile(path) + if err != nil { + log.Error("error reading cmd.yaml", "error", err) + } + + if yaml.Unmarshal(YamlFile, &c) != nil { + log.Error("error unmarshalling cmd.yaml", "error", err) + } + log.Info("cmd loaded", "cmd", &c) + return &c +} diff --git a/runner/go.mod b/runner/go.mod index 52e71a8ec..7a250e643 100644 --- a/runner/go.mod +++ b/runner/go.mod @@ -5,15 +5,23 @@ go 1.21.0 require ( github.com/caarlos0/env v3.5.0+incompatible github.com/dusted-go/logging v1.1.1 + github.com/ghodss/yaml v1.0.0 github.com/golang/protobuf v1.5.3 + github.com/google/uuid v1.3.0 + github.com/joschahenningsen/thumbgen v0.1.2 google.golang.org/grpc v1.58.2 google.golang.org/protobuf v1.31.0 ) require ( github.com/stretchr/testify v1.8.4 // indirect + github.com/tidwall/gjson v1.14.1 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + golang.org/x/image v0.7.0 // indirect golang.org/x/net v0.12.0 // indirect golang.org/x/sys v0.10.0 // indirect golang.org/x/text v0.11.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/runner/go.sum b/runner/go.sum index 6a3f15052..3daf104ab 100644 --- a/runner/go.sum +++ b/runner/go.sum @@ -4,22 +4,67 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dusted-go/logging v1.1.1 h1:x1aSyarDh2iq7MIhCZkjbepsZD9FmAURK93jRFm2Oco= github.com/dusted-go/logging v1.1.1/go.mod h1:Lim3Rk6x2MYwpvPZ6XzPk6ZeX4Wgz9lVOptrL7ngr5w= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 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/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/joschahenningsen/thumbgen v0.1.2 h1:sHIxmvZkuPaiiCjRvKcFNqTmH5IN4kiQiVt+wpAPC8A= +github.com/joschahenningsen/thumbgen v0.1.2/go.mod h1:h8bDlQ2Bq3U/I/VlN8IRA48P7tHW8SHChVXmUWrG3bU= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo= +github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw= +golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= @@ -29,5 +74,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/runner/handlers.go b/runner/handlers.go index eec5a4387..3ed5e3a6a 100644 --- a/runner/handlers.go +++ b/runner/handlers.go @@ -23,6 +23,7 @@ func (r *Runner) RequestStream(ctx context.Context, req *protobuf.StreamRequest) r.actions.PrepareAction(), r.actions.StreamAction(), r.actions.TranscodeAction(), + r.actions.GenerateVideoThumbnail(), r.actions.UploadAction(), } jobID := r.AddJob(ctx, a) @@ -37,3 +38,12 @@ func (r *Runner) RequestStreamEnd(ctx context.Context, request *protobuf.StreamE } return nil, errors.New("job not found") } + +func (r *Runner) GenerateLivePreview(ctx context.Context, request *protobuf.LivePreviewRequest) (*protobuf.LivePreviewResponse, error) { + if job, ok := r.jobs[request.GetRunnerID()]; ok { + job.Cancel(errors.New("canceled by user request"), actions.StreamAction) + return &protobuf.LivePreviewResponse{}, nil + } + + return nil, errors.New("Live Preview not Generated") +} diff --git a/runner/protobuf/runner.pb.go b/runner/protobuf/runner.pb.go index 15441a1f8..b1ba9d215 100644 --- a/runner/protobuf/runner.pb.go +++ b/runner/protobuf/runner.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 -// protoc v3.12.4 +// protoc v4.25.0 // source: runner.proto package protobuf @@ -21,35 +21,696 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type LivePreviewRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RunnerID string `protobuf:"bytes,1,opt,name=RunnerID,proto3" json:"RunnerID,omitempty"` + HLSUrl string `protobuf:"bytes,2,opt,name=HLSUrl,proto3" json:"HLSUrl,omitempty"` +} + +func (x *LivePreviewRequest) Reset() { + *x = LivePreviewRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LivePreviewRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LivePreviewRequest) ProtoMessage() {} + +func (x *LivePreviewRequest) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LivePreviewRequest.ProtoReflect.Descriptor instead. +func (*LivePreviewRequest) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{0} +} + +func (x *LivePreviewRequest) GetRunnerID() string { + if x != nil { + return x.RunnerID + } + return "" +} + +func (x *LivePreviewRequest) GetHLSUrl() string { + if x != nil { + return x.HLSUrl + } + return "" +} + +type LivePreviewResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + LiveThumb []byte `protobuf:"bytes,1,opt,name=LiveThumb,proto3" json:"LiveThumb,omitempty"` +} + +func (x *LivePreviewResponse) Reset() { + *x = LivePreviewResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LivePreviewResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LivePreviewResponse) ProtoMessage() {} + +func (x *LivePreviewResponse) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LivePreviewResponse.ProtoReflect.Descriptor instead. +func (*LivePreviewResponse) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{1} +} + +func (x *LivePreviewResponse) GetLiveThumb() []byte { + if x != nil { + return x.LiveThumb + } + return nil +} + +type DeleteSectionImageRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Path string `protobuf:"bytes,1,opt,name=Path,proto3" json:"Path,omitempty"` +} + +func (x *DeleteSectionImageRequest) Reset() { + *x = DeleteSectionImageRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteSectionImageRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteSectionImageRequest) ProtoMessage() {} + +func (x *DeleteSectionImageRequest) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteSectionImageRequest.ProtoReflect.Descriptor instead. +func (*DeleteSectionImageRequest) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{2} +} + +func (x *DeleteSectionImageRequest) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +type GenerateSectionImageResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Paths []string `protobuf:"bytes,1,rep,name=Paths,proto3" json:"Paths,omitempty"` +} + +func (x *GenerateSectionImageResponse) Reset() { + *x = GenerateSectionImageResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GenerateSectionImageResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenerateSectionImageResponse) ProtoMessage() {} + +func (x *GenerateSectionImageResponse) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenerateSectionImageResponse.ProtoReflect.Descriptor instead. +func (*GenerateSectionImageResponse) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{3} +} + +func (x *GenerateSectionImageResponse) GetPaths() []string { + if x != nil { + return x.Paths + } + return nil +} + +type Section struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Hours uint32 `protobuf:"varint,1,opt,name=Hours,proto3" json:"Hours,omitempty"` + Minutes uint32 `protobuf:"varint,2,opt,name=Minutes,proto3" json:"Minutes,omitempty"` + Seconds uint32 `protobuf:"varint,3,opt,name=Seconds,proto3" json:"Seconds,omitempty"` +} + +func (x *Section) Reset() { + *x = Section{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Section) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Section) ProtoMessage() {} + +func (x *Section) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Section.ProtoReflect.Descriptor instead. +func (*Section) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{4} +} + +func (x *Section) GetHours() uint32 { + if x != nil { + return x.Hours + } + return 0 +} + +func (x *Section) GetMinutes() uint32 { + if x != nil { + return x.Minutes + } + return 0 +} + +func (x *Section) GetSeconds() uint32 { + if x != nil { + return x.Seconds + } + return 0 +} + +type GenerateSectionImageRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PlaylistURL string `protobuf:"bytes,1,opt,name=PlaylistURL,proto3" json:"PlaylistURL,omitempty"` + CourseName string `protobuf:"bytes,2,opt,name=CourseName,proto3" json:"CourseName,omitempty"` + CourseYear uint32 `protobuf:"varint,3,opt,name=CourseYear,proto3" json:"CourseYear,omitempty"` + CourseTeachingTerm string `protobuf:"bytes,4,opt,name=CourseTeachingTerm,proto3" json:"CourseTeachingTerm,omitempty"` + Sections []*Section `protobuf:"bytes,5,rep,name=Sections,proto3" json:"Sections,omitempty"` +} + +func (x *GenerateSectionImageRequest) Reset() { + *x = GenerateSectionImageRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GenerateSectionImageRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GenerateSectionImageRequest) ProtoMessage() {} + +func (x *GenerateSectionImageRequest) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GenerateSectionImageRequest.ProtoReflect.Descriptor instead. +func (*GenerateSectionImageRequest) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{5} +} + +func (x *GenerateSectionImageRequest) GetPlaylistURL() string { + if x != nil { + return x.PlaylistURL + } + return "" +} + +func (x *GenerateSectionImageRequest) GetCourseName() string { + if x != nil { + return x.CourseName + } + return "" +} + +func (x *GenerateSectionImageRequest) GetCourseYear() uint32 { + if x != nil { + return x.CourseYear + } + return 0 +} + +func (x *GenerateSectionImageRequest) GetCourseTeachingTerm() string { + if x != nil { + return x.CourseTeachingTerm + } + return "" +} + +func (x *GenerateSectionImageRequest) GetSections() []*Section { + if x != nil { + return x.Sections + } + return nil +} + +type Status struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ok bool `protobuf:"varint,1,opt,name=ok,proto3" json:"ok,omitempty"` +} + +func (x *Status) Reset() { + *x = Status{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Status) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Status) ProtoMessage() {} + +func (x *Status) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Status.ProtoReflect.Descriptor instead. +func (*Status) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{6} +} + +func (x *Status) GetOk() bool { + if x != nil { + return x.Ok + } + return false +} + type StreamRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Stream uint64 `protobuf:"varint,1,opt,name=stream,proto3" json:"stream,omitempty"` - Course uint64 `protobuf:"varint,2,opt,name=course,proto3" json:"course,omitempty"` - Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` - End *timestamp.Timestamp `protobuf:"bytes,4,opt,name=end,proto3" json:"end,omitempty"` - Source string `protobuf:"bytes,5,opt,name=source,proto3" json:"source,omitempty"` + Stream uint64 `protobuf:"varint,1,opt,name=stream,proto3" json:"stream,omitempty"` + Course uint64 `protobuf:"varint,2,opt,name=course,proto3" json:"course,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + End *timestamp.Timestamp `protobuf:"bytes,4,opt,name=end,proto3" json:"end,omitempty"` + Source string `protobuf:"bytes,5,opt,name=source,proto3" json:"source,omitempty"` +} + +func (x *StreamRequest) Reset() { + *x = StreamRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamRequest) ProtoMessage() {} + +func (x *StreamRequest) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamRequest.ProtoReflect.Descriptor instead. +func (*StreamRequest) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{7} +} + +func (x *StreamRequest) GetStream() uint64 { + if x != nil { + return x.Stream + } + return 0 +} + +func (x *StreamRequest) GetCourse() uint64 { + if x != nil { + return x.Course + } + return 0 +} + +func (x *StreamRequest) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *StreamRequest) GetEnd() *timestamp.Timestamp { + if x != nil { + return x.End + } + return nil +} + +func (x *StreamRequest) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + +type StreamResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Job string `protobuf:"bytes,1,opt,name=job,proto3" json:"job,omitempty"` +} + +func (x *StreamResponse) Reset() { + *x = StreamResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamResponse) ProtoMessage() {} + +func (x *StreamResponse) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamResponse.ProtoReflect.Descriptor instead. +func (*StreamResponse) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{8} +} + +func (x *StreamResponse) GetJob() string { + if x != nil { + return x.Job + } + return "" +} + +type StreamEndRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + JobID string `protobuf:"bytes,1,opt,name=jobID,proto3" json:"jobID,omitempty"` + KeepVod bool `protobuf:"varint,2,opt,name=keepVod,proto3" json:"keepVod,omitempty"` +} + +func (x *StreamEndRequest) Reset() { + *x = StreamEndRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamEndRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamEndRequest) ProtoMessage() {} + +func (x *StreamEndRequest) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamEndRequest.ProtoReflect.Descriptor instead. +func (*StreamEndRequest) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{9} +} + +func (x *StreamEndRequest) GetJobID() string { + if x != nil { + return x.JobID + } + return "" +} + +func (x *StreamEndRequest) GetKeepVod() bool { + if x != nil { + return x.KeepVod + } + return false +} + +type StreamEndResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *StreamEndResponse) Reset() { + *x = StreamEndResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamEndResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamEndResponse) ProtoMessage() {} + +func (x *StreamEndResponse) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamEndResponse.ProtoReflect.Descriptor instead. +func (*StreamEndResponse) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{10} +} + +type StreamInfoForUploadRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RunnerID string `protobuf:"bytes,1,opt,name=RunnerID,proto3" json:"RunnerID,omitempty"` + UploadKey uint32 `protobuf:"varint,2,opt,name=UploadKey,proto3" json:"UploadKey,omitempty"` +} + +func (x *StreamInfoForUploadRequest) Reset() { + *x = StreamInfoForUploadRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamInfoForUploadRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamInfoForUploadRequest) ProtoMessage() {} + +func (x *StreamInfoForUploadRequest) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamInfoForUploadRequest.ProtoReflect.Descriptor instead. +func (*StreamInfoForUploadRequest) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{11} +} + +func (x *StreamInfoForUploadRequest) GetRunnerID() string { + if x != nil { + return x.RunnerID + } + return "" +} + +func (x *StreamInfoForUploadRequest) GetUploadKey() uint32 { + if x != nil { + return x.UploadKey + } + return 0 +} + +type StreamInfoForUploadResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CourseSlug string `protobuf:"bytes,1,opt,name=CourseSlug,proto3" json:"CourseSlug,omitempty"` + CourseTerm string `protobuf:"bytes,2,opt,name=CourseTerm,proto3" json:"CourseTerm,omitempty"` + CourseYear uint32 `protobuf:"varint,3,opt,name=CourseYear,proto3" json:"CourseYear,omitempty"` + StreamStart *timestamp.Timestamp `protobuf:"bytes,4,opt,name=StreamStart,proto3" json:"StreamStart,omitempty"` + StreamEnd *timestamp.Timestamp `protobuf:"bytes,5,opt,name=StreamEnd,proto3" json:"StreamEnd,omitempty"` + StreamID uint32 `protobuf:"varint,6,opt,name=StreamID,proto3" json:"StreamID,omitempty"` + VideoType string `protobuf:"bytes,7,opt,name=VideoType,proto3" json:"VideoType,omitempty"` } -func (x *StreamRequest) Reset() { - *x = StreamRequest{} +func (x *StreamInfoForUploadResponse) Reset() { + *x = StreamInfoForUploadResponse{} if protoimpl.UnsafeEnabled { - mi := &file_runner_proto_msgTypes[0] + mi := &file_runner_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *StreamRequest) String() string { +func (x *StreamInfoForUploadResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*StreamRequest) ProtoMessage() {} +func (*StreamInfoForUploadResponse) ProtoMessage() {} -func (x *StreamRequest) ProtoReflect() protoreflect.Message { - mi := &file_runner_proto_msgTypes[0] +func (x *StreamInfoForUploadResponse) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -60,71 +721,307 @@ func (x *StreamRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use StreamRequest.ProtoReflect.Descriptor instead. -func (*StreamRequest) Descriptor() ([]byte, []int) { - return file_runner_proto_rawDescGZIP(), []int{0} +// Deprecated: Use StreamInfoForUploadResponse.ProtoReflect.Descriptor instead. +func (*StreamInfoForUploadResponse) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{12} } -func (x *StreamRequest) GetStream() uint64 { +func (x *StreamInfoForUploadResponse) GetCourseSlug() string { if x != nil { - return x.Stream + return x.CourseSlug + } + return "" +} + +func (x *StreamInfoForUploadResponse) GetCourseTerm() string { + if x != nil { + return x.CourseTerm + } + return "" +} + +func (x *StreamInfoForUploadResponse) GetCourseYear() uint32 { + if x != nil { + return x.CourseYear } return 0 } -func (x *StreamRequest) GetCourse() uint64 { +func (x *StreamInfoForUploadResponse) GetStreamStart() *timestamp.Timestamp { if x != nil { - return x.Course + return x.StreamStart + } + return nil +} + +func (x *StreamInfoForUploadResponse) GetStreamEnd() *timestamp.Timestamp { + if x != nil { + return x.StreamEnd + } + return nil +} + +func (x *StreamInfoForUploadResponse) GetStreamID() uint32 { + if x != nil { + return x.StreamID } return 0 } -func (x *StreamRequest) GetVersion() string { +func (x *StreamInfoForUploadResponse) GetVideoType() string { if x != nil { - return x.Version + return x.VideoType } return "" } -func (x *StreamRequest) GetEnd() *timestamp.Timestamp { +type VoDUploadFinished struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RunnerID string `protobuf:"bytes,1,opt,name=RunnerID,proto3" json:"RunnerID,omitempty"` + StreamID uint32 `protobuf:"varint,2,opt,name=StreamID,proto3" json:"StreamID,omitempty"` + HLSUrl string `protobuf:"bytes,3,opt,name=HLSUrl,proto3" json:"HLSUrl,omitempty"` + SourceType string `protobuf:"bytes,4,opt,name=SourceType,proto3" json:"SourceType,omitempty"` + ThumbnailUrl string `protobuf:"bytes,5,opt,name=ThumbnailUrl,proto3" json:"ThumbnailUrl,omitempty"` +} + +func (x *VoDUploadFinished) Reset() { + *x = VoDUploadFinished{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VoDUploadFinished) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VoDUploadFinished) ProtoMessage() {} + +func (x *VoDUploadFinished) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VoDUploadFinished.ProtoReflect.Descriptor instead. +func (*VoDUploadFinished) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{13} +} + +func (x *VoDUploadFinished) GetRunnerID() string { if x != nil { - return x.End + return x.RunnerID + } + return "" +} + +func (x *VoDUploadFinished) GetStreamID() uint32 { + if x != nil { + return x.StreamID + } + return 0 +} + +func (x *VoDUploadFinished) GetHLSUrl() string { + if x != nil { + return x.HLSUrl + } + return "" +} + +func (x *VoDUploadFinished) GetSourceType() string { + if x != nil { + return x.SourceType + } + return "" +} + +func (x *VoDUploadFinished) GetThumbnailUrl() string { + if x != nil { + return x.ThumbnailUrl + } + return "" +} + +type SilenceResults struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RunnerID string `protobuf:"bytes,1,opt,name=RunnerID,proto3" json:"RunnerID,omitempty"` + StreamID uint32 `protobuf:"varint,2,opt,name=StreamID,proto3" json:"StreamID,omitempty"` + Starts []uint32 `protobuf:"varint,3,rep,packed,name=starts,proto3" json:"starts,omitempty"` + Ends []uint32 `protobuf:"varint,4,rep,packed,name=ends,proto3" json:"ends,omitempty"` +} + +func (x *SilenceResults) Reset() { + *x = SilenceResults{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SilenceResults) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SilenceResults) ProtoMessage() {} + +func (x *SilenceResults) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SilenceResults.ProtoReflect.Descriptor instead. +func (*SilenceResults) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{14} +} + +func (x *SilenceResults) GetRunnerID() string { + if x != nil { + return x.RunnerID + } + return "" +} + +func (x *SilenceResults) GetStreamID() uint32 { + if x != nil { + return x.StreamID + } + return 0 +} + +func (x *SilenceResults) GetStarts() []uint32 { + if x != nil { + return x.Starts } return nil } -func (x *StreamRequest) GetSource() string { +func (x *SilenceResults) GetEnds() []uint32 { if x != nil { - return x.Source + return x.Ends + } + return nil +} + +type StreamStarted struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RunnerID string `protobuf:"bytes,1,opt,name=RunnerID,proto3" json:"RunnerID,omitempty"` + StreamID uint32 `protobuf:"varint,2,opt,name=StreamID,proto3" json:"StreamID,omitempty"` + HLSUrl string `protobuf:"bytes,3,opt,name=HLSUrl,proto3" json:"HLSUrl,omitempty"` + SourceType string `protobuf:"bytes,4,opt,name=SourceType,proto3" json:"SourceType,omitempty"` +} + +func (x *StreamStarted) Reset() { + *x = StreamStarted{} + if protoimpl.UnsafeEnabled { + mi := &file_runner_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StreamStarted) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StreamStarted) ProtoMessage() {} + +func (x *StreamStarted) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StreamStarted.ProtoReflect.Descriptor instead. +func (*StreamStarted) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{15} +} + +func (x *StreamStarted) GetRunnerID() string { + if x != nil { + return x.RunnerID } return "" } -type StreamResponse struct { +func (x *StreamStarted) GetStreamID() uint32 { + if x != nil { + return x.StreamID + } + return 0 +} + +func (x *StreamStarted) GetHLSUrl() string { + if x != nil { + return x.HLSUrl + } + return "" +} + +func (x *StreamStarted) GetSourceType() string { + if x != nil { + return x.SourceType + } + return "" +} + +type StreamEnded struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Job string `protobuf:"bytes,1,opt,name=job,proto3" json:"job,omitempty"` + RunnerID string `protobuf:"bytes,1,opt,name=RunnerID,proto3" json:"RunnerID,omitempty"` + StreamID uint32 `protobuf:"varint,2,opt,name=StreamID,proto3" json:"StreamID,omitempty"` } -func (x *StreamResponse) Reset() { - *x = StreamResponse{} +func (x *StreamEnded) Reset() { + *x = StreamEnded{} if protoimpl.UnsafeEnabled { - mi := &file_runner_proto_msgTypes[1] + mi := &file_runner_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *StreamResponse) String() string { +func (x *StreamEnded) String() string { return protoimpl.X.MessageStringOf(x) } -func (*StreamResponse) ProtoMessage() {} +func (*StreamEnded) ProtoMessage() {} -func (x *StreamResponse) ProtoReflect() protoreflect.Message { - mi := &file_runner_proto_msgTypes[1] +func (x *StreamEnded) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -135,44 +1032,55 @@ func (x *StreamResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use StreamResponse.ProtoReflect.Descriptor instead. -func (*StreamResponse) Descriptor() ([]byte, []int) { - return file_runner_proto_rawDescGZIP(), []int{1} +// Deprecated: Use StreamEnded.ProtoReflect.Descriptor instead. +func (*StreamEnded) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{16} } -func (x *StreamResponse) GetJob() string { +func (x *StreamEnded) GetRunnerID() string { if x != nil { - return x.Job + return x.RunnerID } return "" } -type StreamEndRequest struct { +func (x *StreamEnded) GetStreamID() uint32 { + if x != nil { + return x.StreamID + } + return 0 +} + +type ThumbnailsFinished struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - JobID string `protobuf:"bytes,1,opt,name=jobID,proto3" json:"jobID,omitempty"` - KeepVod bool `protobuf:"varint,2,opt,name=keepVod,proto3" json:"keepVod,omitempty"` + RunnerID string `protobuf:"bytes,1,opt,name=RunnerID,proto3" json:"RunnerID,omitempty"` + StreamID uint32 `protobuf:"varint,2,opt,name=StreamID,proto3" json:"StreamID,omitempty"` + FilePath string `protobuf:"bytes,3,opt,name=FilePath,proto3" json:"FilePath,omitempty"` + Interval uint32 `protobuf:"varint,4,opt,name=Interval,proto3" json:"Interval,omitempty"` + SourceType string `protobuf:"bytes,5,opt,name=SourceType,proto3" json:"SourceType,omitempty"` + LargeThumbnailPath string `protobuf:"bytes,6,opt,name=LargeThumbnailPath,proto3" json:"LargeThumbnailPath,omitempty"` } -func (x *StreamEndRequest) Reset() { - *x = StreamEndRequest{} +func (x *ThumbnailsFinished) Reset() { + *x = ThumbnailsFinished{} if protoimpl.UnsafeEnabled { - mi := &file_runner_proto_msgTypes[2] + mi := &file_runner_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *StreamEndRequest) String() string { +func (x *ThumbnailsFinished) String() string { return protoimpl.X.MessageStringOf(x) } -func (*StreamEndRequest) ProtoMessage() {} +func (*ThumbnailsFinished) ProtoMessage() {} -func (x *StreamEndRequest) ProtoReflect() protoreflect.Message { - mi := &file_runner_proto_msgTypes[2] +func (x *ThumbnailsFinished) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -183,48 +1091,83 @@ func (x *StreamEndRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use StreamEndRequest.ProtoReflect.Descriptor instead. -func (*StreamEndRequest) Descriptor() ([]byte, []int) { - return file_runner_proto_rawDescGZIP(), []int{2} +// Deprecated: Use ThumbnailsFinished.ProtoReflect.Descriptor instead. +func (*ThumbnailsFinished) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{17} } -func (x *StreamEndRequest) GetJobID() string { +func (x *ThumbnailsFinished) GetRunnerID() string { if x != nil { - return x.JobID + return x.RunnerID } return "" } -func (x *StreamEndRequest) GetKeepVod() bool { +func (x *ThumbnailsFinished) GetStreamID() uint32 { if x != nil { - return x.KeepVod + return x.StreamID + } + return 0 +} + +func (x *ThumbnailsFinished) GetFilePath() string { + if x != nil { + return x.FilePath + } + return "" +} + +func (x *ThumbnailsFinished) GetInterval() uint32 { + if x != nil { + return x.Interval + } + return 0 +} + +func (x *ThumbnailsFinished) GetSourceType() string { + if x != nil { + return x.SourceType + } + return "" +} + +func (x *ThumbnailsFinished) GetLargeThumbnailPath() string { + if x != nil { + return x.LargeThumbnailPath } - return false + return "" } -type StreamEndResponse struct { +type TranscodingFailureNotification struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + RunnerID string `protobuf:"bytes,1,opt,name=RunnerID,proto3" json:"RunnerID,omitempty"` + StreamID uint32 `protobuf:"varint,2,opt,name=StreamID,proto3" json:"StreamID,omitempty"` + Version string `protobuf:"bytes,3,opt,name=Version,proto3" json:"Version,omitempty"` + FilePath string `protobuf:"bytes,4,opt,name=FilePath,proto3" json:"FilePath,omitempty"` + Logs string `protobuf:"bytes,5,opt,name=Logs,proto3" json:"Logs,omitempty"` + ExitCode int64 `protobuf:"varint,6,opt,name=ExitCode,proto3" json:"ExitCode,omitempty"` } -func (x *StreamEndResponse) Reset() { - *x = StreamEndResponse{} +func (x *TranscodingFailureNotification) Reset() { + *x = TranscodingFailureNotification{} if protoimpl.UnsafeEnabled { - mi := &file_runner_proto_msgTypes[3] + mi := &file_runner_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *StreamEndResponse) String() string { +func (x *TranscodingFailureNotification) String() string { return protoimpl.X.MessageStringOf(x) } -func (*StreamEndResponse) ProtoMessage() {} +func (*TranscodingFailureNotification) ProtoMessage() {} -func (x *StreamEndResponse) ProtoReflect() protoreflect.Message { - mi := &file_runner_proto_msgTypes[3] +func (x *TranscodingFailureNotification) ProtoReflect() protoreflect.Message { + mi := &file_runner_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -235,9 +1178,51 @@ func (x *StreamEndResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use StreamEndResponse.ProtoReflect.Descriptor instead. -func (*StreamEndResponse) Descriptor() ([]byte, []int) { - return file_runner_proto_rawDescGZIP(), []int{3} +// Deprecated: Use TranscodingFailureNotification.ProtoReflect.Descriptor instead. +func (*TranscodingFailureNotification) Descriptor() ([]byte, []int) { + return file_runner_proto_rawDescGZIP(), []int{18} +} + +func (x *TranscodingFailureNotification) GetRunnerID() string { + if x != nil { + return x.RunnerID + } + return "" +} + +func (x *TranscodingFailureNotification) GetStreamID() uint32 { + if x != nil { + return x.StreamID + } + return 0 +} + +func (x *TranscodingFailureNotification) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *TranscodingFailureNotification) GetFilePath() string { + if x != nil { + return x.FilePath + } + return "" +} + +func (x *TranscodingFailureNotification) GetLogs() string { + if x != nil { + return x.Logs + } + return "" +} + +func (x *TranscodingFailureNotification) GetExitCode() int64 { + if x != nil { + return x.ExitCode + } + return 0 } type RegisterRequest struct { @@ -252,7 +1237,7 @@ type RegisterRequest struct { func (x *RegisterRequest) Reset() { *x = RegisterRequest{} if protoimpl.UnsafeEnabled { - mi := &file_runner_proto_msgTypes[4] + mi := &file_runner_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -265,7 +1250,7 @@ func (x *RegisterRequest) String() string { func (*RegisterRequest) ProtoMessage() {} func (x *RegisterRequest) ProtoReflect() protoreflect.Message { - mi := &file_runner_proto_msgTypes[4] + mi := &file_runner_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -278,7 +1263,7 @@ func (x *RegisterRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterRequest.ProtoReflect.Descriptor instead. func (*RegisterRequest) Descriptor() ([]byte, []int) { - return file_runner_proto_rawDescGZIP(), []int{4} + return file_runner_proto_rawDescGZIP(), []int{19} } func (x *RegisterRequest) GetHostname() string { @@ -299,12 +1284,14 @@ type RegisterResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"` } func (x *RegisterResponse) Reset() { *x = RegisterResponse{} if protoimpl.UnsafeEnabled { - mi := &file_runner_proto_msgTypes[5] + mi := &file_runner_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -317,7 +1304,7 @@ func (x *RegisterResponse) String() string { func (*RegisterResponse) ProtoMessage() {} func (x *RegisterResponse) ProtoReflect() protoreflect.Message { - mi := &file_runner_proto_msgTypes[5] + mi := &file_runner_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -330,7 +1317,14 @@ func (x *RegisterResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterResponse.ProtoReflect.Descriptor instead. func (*RegisterResponse) Descriptor() ([]byte, []int) { - return file_runner_proto_rawDescGZIP(), []int{5} + return file_runner_proto_rawDescGZIP(), []int{20} +} + +func (x *RegisterResponse) GetID() string { + if x != nil { + return x.ID + } + return "" } type HeartbeatRequest struct { @@ -338,19 +1332,20 @@ type HeartbeatRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ID uint64 `protobuf:"varint,1,opt,name=ID,proto3" json:"ID,omitempty"` - Workload uint32 `protobuf:"varint,2,opt,name=Workload,proto3" json:"Workload,omitempty"` - Version string `protobuf:"bytes,3,opt,name=Version,proto3" json:"Version,omitempty"` - CPU string `protobuf:"bytes,4,opt,name=CPU,proto3" json:"CPU,omitempty"` - Memory string `protobuf:"bytes,5,opt,name=Memory,proto3" json:"Memory,omitempty"` - Disk string `protobuf:"bytes,6,opt,name=Disk,proto3" json:"Disk,omitempty"` - Uptime string `protobuf:"bytes,7,opt,name=Uptime,proto3" json:"Uptime,omitempty"` + Hostname string `protobuf:"bytes,1,opt,name=hostname,proto3" json:"hostname,omitempty"` + Port int32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"` + Workload uint32 `protobuf:"varint,3,opt,name=Workload,proto3" json:"Workload,omitempty"` + Version string `protobuf:"bytes,4,opt,name=Version,proto3" json:"Version,omitempty"` + CPU string `protobuf:"bytes,5,opt,name=CPU,proto3" json:"CPU,omitempty"` + Memory string `protobuf:"bytes,6,opt,name=Memory,proto3" json:"Memory,omitempty"` + Disk string `protobuf:"bytes,7,opt,name=Disk,proto3" json:"Disk,omitempty"` + Uptime string `protobuf:"bytes,8,opt,name=Uptime,proto3" json:"Uptime,omitempty"` } func (x *HeartbeatRequest) Reset() { *x = HeartbeatRequest{} if protoimpl.UnsafeEnabled { - mi := &file_runner_proto_msgTypes[6] + mi := &file_runner_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -363,7 +1358,7 @@ func (x *HeartbeatRequest) String() string { func (*HeartbeatRequest) ProtoMessage() {} func (x *HeartbeatRequest) ProtoReflect() protoreflect.Message { - mi := &file_runner_proto_msgTypes[6] + mi := &file_runner_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -376,12 +1371,19 @@ func (x *HeartbeatRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use HeartbeatRequest.ProtoReflect.Descriptor instead. func (*HeartbeatRequest) Descriptor() ([]byte, []int) { - return file_runner_proto_rawDescGZIP(), []int{6} + return file_runner_proto_rawDescGZIP(), []int{21} } -func (x *HeartbeatRequest) GetID() uint64 { +func (x *HeartbeatRequest) GetHostname() string { if x != nil { - return x.ID + return x.Hostname + } + return "" +} + +func (x *HeartbeatRequest) GetPort() int32 { + if x != nil { + return x.Port } return 0 } @@ -432,12 +1434,14 @@ type HeartbeatResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + Ok bool `protobuf:"varint,1,opt,name=ok,proto3" json:"ok,omitempty"` } func (x *HeartbeatResponse) Reset() { *x = HeartbeatResponse{} if protoimpl.UnsafeEnabled { - mi := &file_runner_proto_msgTypes[7] + mi := &file_runner_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -450,7 +1454,7 @@ func (x *HeartbeatResponse) String() string { func (*HeartbeatResponse) ProtoMessage() {} func (x *HeartbeatResponse) ProtoReflect() protoreflect.Message { - mi := &file_runner_proto_msgTypes[7] + mi := &file_runner_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -463,7 +1467,14 @@ func (x *HeartbeatResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use HeartbeatResponse.ProtoReflect.Descriptor instead. func (*HeartbeatResponse) Descriptor() ([]byte, []int) { - return file_runner_proto_rawDescGZIP(), []int{7} + return file_runner_proto_rawDescGZIP(), []int{22} +} + +func (x *HeartbeatResponse) GetOk() bool { + if x != nil { + return x.Ok + } + return false } type SelfStreamRequest struct { @@ -477,7 +1488,7 @@ type SelfStreamRequest struct { func (x *SelfStreamRequest) Reset() { *x = SelfStreamRequest{} if protoimpl.UnsafeEnabled { - mi := &file_runner_proto_msgTypes[8] + mi := &file_runner_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -490,7 +1501,7 @@ func (x *SelfStreamRequest) String() string { func (*SelfStreamRequest) ProtoMessage() {} func (x *SelfStreamRequest) ProtoReflect() protoreflect.Message { - mi := &file_runner_proto_msgTypes[8] + mi := &file_runner_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -503,7 +1514,7 @@ func (x *SelfStreamRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SelfStreamRequest.ProtoReflect.Descriptor instead. func (*SelfStreamRequest) Descriptor() ([]byte, []int) { - return file_runner_proto_rawDescGZIP(), []int{8} + return file_runner_proto_rawDescGZIP(), []int{23} } func (x *SelfStreamRequest) GetStreamKey() string { @@ -526,7 +1537,7 @@ type SelfStreamResponse struct { func (x *SelfStreamResponse) Reset() { *x = SelfStreamResponse{} if protoimpl.UnsafeEnabled { - mi := &file_runner_proto_msgTypes[9] + mi := &file_runner_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -539,7 +1550,7 @@ func (x *SelfStreamResponse) String() string { func (*SelfStreamResponse) ProtoMessage() {} func (x *SelfStreamResponse) ProtoReflect() protoreflect.Message { - mi := &file_runner_proto_msgTypes[9] + mi := &file_runner_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -552,7 +1563,7 @@ func (x *SelfStreamResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SelfStreamResponse.ProtoReflect.Descriptor instead. func (*SelfStreamResponse) Descriptor() ([]byte, []int) { - return file_runner_proto_rawDescGZIP(), []int{9} + return file_runner_proto_rawDescGZIP(), []int{24} } func (x *SelfStreamResponse) GetStream() uint64 { @@ -582,79 +1593,249 @@ var file_runner_proto_rawDesc = []byte{ 0x0a, 0x0c, 0x72, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9f, 0x01, 0x0a, 0x0d, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x73, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x75, 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x06, 0x63, 0x6f, 0x75, 0x72, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, - 0x65, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x22, 0x0a, 0x0e, 0x53, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, - 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x22, - 0x42, 0x0a, 0x10, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x65, - 0x70, 0x56, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x6b, 0x65, 0x65, 0x70, - 0x56, 0x6f, 0x64, 0x22, 0x13, 0x0a, 0x11, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x41, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x68, - 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, - 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x12, 0x0a, 0x10, 0x52, - 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0xae, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x02, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, - 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x43, 0x50, - 0x55, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x43, 0x50, 0x55, 0x12, 0x16, 0x0a, 0x06, - 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4d, 0x65, - 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x69, 0x73, 0x6b, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x44, 0x69, 0x73, 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x55, 0x70, 0x74, 0x69, - 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, - 0x22, 0x13, 0x0a, 0x11, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x0a, 0x11, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4b, 0x65, 0x79, 0x22, 0x5e, 0x0a, 0x12, 0x53, 0x65, 0x6c, 0x66, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, - 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x75, 0x72, 0x73, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x63, 0x6f, 0x75, 0x72, 0x73, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x32, 0x9f, 0x01, 0x0a, 0x08, 0x54, 0x6f, 0x52, - 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x44, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x10, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x12, - 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x45, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x32, 0xeb, 0x01, 0x0a, 0x0a, 0x46, - 0x72, 0x6f, 0x6d, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x43, 0x0a, 0x08, 0x52, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, - 0x0a, 0x09, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x1a, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x11, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1b, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x11, 0x5a, 0x0f, 0x72, 0x75, 0x6e, 0x6e, - 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x48, 0x0a, 0x12, 0x4c, 0x69, 0x76, + 0x65, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1a, 0x0a, 0x08, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x48, + 0x4c, 0x53, 0x55, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x48, 0x4c, 0x53, + 0x55, 0x72, 0x6c, 0x22, 0x33, 0x0a, 0x13, 0x4c, 0x69, 0x76, 0x65, 0x50, 0x72, 0x65, 0x76, 0x69, + 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x4c, 0x69, + 0x76, 0x65, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x4c, + 0x69, 0x76, 0x65, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x22, 0x2f, 0x0a, 0x19, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x50, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x50, 0x61, 0x74, 0x68, 0x22, 0x34, 0x0a, 0x1c, 0x47, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6d, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x50, 0x61, 0x74, + 0x68, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x50, 0x61, 0x74, 0x68, 0x73, 0x22, + 0x53, 0x0a, 0x07, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x48, 0x6f, + 0x75, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x48, 0x6f, 0x75, 0x72, 0x73, + 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x69, 0x6e, 0x75, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x07, 0x4d, 0x69, 0x6e, 0x75, 0x74, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x53, 0x65, + 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x53, 0x65, 0x63, + 0x6f, 0x6e, 0x64, 0x73, 0x22, 0xde, 0x01, 0x0a, 0x1b, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, + 0x65, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x50, 0x6c, 0x61, 0x79, 0x6c, 0x69, 0x73, 0x74, + 0x55, 0x52, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x50, 0x6c, 0x61, 0x79, 0x6c, + 0x69, 0x73, 0x74, 0x55, 0x52, 0x4c, 0x12, 0x1e, 0x0a, 0x0a, 0x43, 0x6f, 0x75, 0x72, 0x73, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x43, 0x6f, 0x75, 0x72, + 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x43, 0x6f, 0x75, 0x72, 0x73, 0x65, + 0x59, 0x65, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x43, 0x6f, 0x75, 0x72, + 0x73, 0x65, 0x59, 0x65, 0x61, 0x72, 0x12, 0x2e, 0x0a, 0x12, 0x43, 0x6f, 0x75, 0x72, 0x73, 0x65, + 0x54, 0x65, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x72, 0x6d, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x12, 0x43, 0x6f, 0x75, 0x72, 0x73, 0x65, 0x54, 0x65, 0x61, 0x63, 0x68, 0x69, + 0x6e, 0x67, 0x54, 0x65, 0x72, 0x6d, 0x12, 0x2d, 0x0a, 0x08, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x53, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x18, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x02, 0x6f, 0x6b, 0x22, + 0x9f, 0x01, 0x0a, 0x0d, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x75, + 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x63, 0x6f, 0x75, 0x72, 0x73, + 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x03, 0x65, + 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x22, 0x22, 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x22, 0x42, 0x0a, 0x10, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, + 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6a, 0x6f, 0x62, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x44, 0x12, + 0x18, 0x0a, 0x07, 0x6b, 0x65, 0x65, 0x70, 0x56, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x07, 0x6b, 0x65, 0x65, 0x70, 0x56, 0x6f, 0x64, 0x22, 0x13, 0x0a, 0x11, 0x53, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x56, + 0x0a, 0x1a, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x46, 0x6f, 0x72, 0x55, + 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x55, 0x70, 0x6c, 0x6f, + 0x61, 0x64, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x55, 0x70, 0x6c, + 0x6f, 0x61, 0x64, 0x4b, 0x65, 0x79, 0x22, 0xaf, 0x02, 0x0a, 0x1b, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x46, 0x6f, 0x72, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x43, 0x6f, 0x75, 0x72, 0x73, 0x65, + 0x53, 0x6c, 0x75, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x43, 0x6f, 0x75, 0x72, + 0x73, 0x65, 0x53, 0x6c, 0x75, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x43, 0x6f, 0x75, 0x72, 0x73, 0x65, + 0x54, 0x65, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x43, 0x6f, 0x75, 0x72, + 0x73, 0x65, 0x54, 0x65, 0x72, 0x6d, 0x12, 0x1e, 0x0a, 0x0a, 0x43, 0x6f, 0x75, 0x72, 0x73, 0x65, + 0x59, 0x65, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x43, 0x6f, 0x75, 0x72, + 0x73, 0x65, 0x59, 0x65, 0x61, 0x72, 0x12, 0x3c, 0x0a, 0x0b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, + 0x74, 0x61, 0x72, 0x74, 0x12, 0x38, 0x0a, 0x09, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, + 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x52, 0x09, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x12, 0x1a, + 0x0a, 0x08, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x44, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x08, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x56, 0x69, + 0x64, 0x65, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x56, + 0x69, 0x64, 0x65, 0x6f, 0x54, 0x79, 0x70, 0x65, 0x22, 0xa7, 0x01, 0x0a, 0x11, 0x56, 0x6f, 0x44, + 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x1a, + 0x0a, 0x08, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x48, 0x4c, 0x53, 0x55, 0x72, 0x6c, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x48, 0x4c, 0x53, 0x55, 0x72, 0x6c, 0x12, 0x1e, + 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, + 0x0a, 0x0c, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x55, 0x72, 0x6c, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x55, + 0x72, 0x6c, 0x22, 0x7c, 0x0a, 0x0e, 0x53, 0x69, 0x6c, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x49, 0x44, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x49, 0x44, + 0x12, 0x1a, 0x0a, 0x08, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x08, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0d, 0x42, 0x02, 0x10, 0x01, + 0x52, 0x06, 0x73, 0x74, 0x61, 0x72, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x04, 0x65, 0x6e, 0x64, 0x73, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x42, 0x02, 0x10, 0x01, 0x52, 0x04, 0x65, 0x6e, 0x64, 0x73, + 0x22, 0x7f, 0x0a, 0x0d, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, + 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, + 0x08, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x08, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x48, 0x4c, 0x53, + 0x55, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x48, 0x4c, 0x53, 0x55, 0x72, + 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x22, 0x45, 0x0a, 0x0b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x65, 0x64, + 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x44, 0x22, 0xd4, 0x01, 0x0a, 0x12, 0x54, 0x68, 0x75, + 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x73, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, + 0x1a, 0x0a, 0x08, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x50, + 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x50, + 0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, + 0x1e, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x2e, 0x0a, 0x12, 0x4c, 0x61, 0x72, 0x67, 0x65, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, + 0x6c, 0x50, 0x61, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x4c, 0x61, 0x72, + 0x67, 0x65, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x22, + 0xbe, 0x01, 0x0a, 0x1e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x46, + 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, + 0x0a, 0x08, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x08, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, + 0x12, 0x12, 0x0a, 0x04, 0x4c, 0x6f, 0x67, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x45, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x45, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, + 0x22, 0x41, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, + 0x6f, 0x72, 0x74, 0x22, 0x22, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x22, 0xce, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, + 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, + 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x43, 0x50, 0x55, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x43, 0x50, 0x55, 0x12, 0x16, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, + 0x44, 0x69, 0x73, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x44, 0x69, 0x73, 0x6b, + 0x12, 0x16, 0x0a, 0x06, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x23, 0x0a, 0x11, 0x48, 0x65, 0x61, 0x72, + 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, + 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x02, 0x6f, 0x6b, 0x22, 0x31, 0x0a, + 0x11, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4b, 0x65, 0x79, + 0x22, 0x5e, 0x0a, 0x12, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x16, + 0x0a, 0x06, 0x63, 0x6f, 0x75, 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, + 0x63, 0x6f, 0x75, 0x72, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x32, 0x98, 0x03, 0x0a, 0x08, 0x54, 0x6f, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x44, 0x0a, + 0x0d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x17, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x10, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x54, 0x0a, 0x13, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4c, 0x69, + 0x76, 0x65, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x76, 0x65, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x76, 0x65, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x15, 0x47, 0x65, 0x6e, 0x65, + 0x72, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6d, 0x61, 0x67, 0x65, + 0x73, 0x12, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x47, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6d, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x12, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6d, 0x61, + 0x67, 0x65, 0x12, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6d, 0x61, 0x67, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x32, 0x92, 0x06, 0x0a, 0x0a, + 0x46, 0x72, 0x6f, 0x6d, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x43, 0x0a, 0x08, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, + 0x46, 0x0a, 0x09, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x1a, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x11, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1b, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x17, 0x4e, 0x6f, 0x74, + 0x69, 0x66, 0x79, 0x56, 0x6f, 0x44, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6e, 0x69, + 0x73, 0x68, 0x65, 0x64, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x56, 0x6f, 0x44, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, + 0x64, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x14, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x53, + 0x69, 0x6c, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x18, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x69, 0x6c, 0x65, 0x6e, 0x63, 0x65, + 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x13, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x79, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x65, 0x64, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x1a, 0x10, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, + 0x3e, 0x0a, 0x11, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, + 0x6e, 0x64, 0x65, 0x64, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x1a, 0x10, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, + 0x4c, 0x0a, 0x18, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, + 0x69, 0x6c, 0x73, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x1c, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, + 0x73, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x58, 0x0a, + 0x18, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x69, + 0x6e, 0x67, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, + 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x67, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x46, 0x6f, 0x72, 0x55, 0x70, 0x6c, 0x6f, 0x61, + 0x64, 0x12, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x46, 0x6f, 0x72, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x46, 0x6f, 0x72, + 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x42, 0x11, 0x5a, 0x0f, 0x72, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -669,37 +1850,75 @@ func file_runner_proto_rawDescGZIP() []byte { return file_runner_proto_rawDescData } -var file_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 25) var file_runner_proto_goTypes = []interface{}{ - (*StreamRequest)(nil), // 0: protobuf.StreamRequest - (*StreamResponse)(nil), // 1: protobuf.StreamResponse - (*StreamEndRequest)(nil), // 2: protobuf.StreamEndRequest - (*StreamEndResponse)(nil), // 3: protobuf.StreamEndResponse - (*RegisterRequest)(nil), // 4: protobuf.RegisterRequest - (*RegisterResponse)(nil), // 5: protobuf.RegisterResponse - (*HeartbeatRequest)(nil), // 6: protobuf.HeartbeatRequest - (*HeartbeatResponse)(nil), // 7: protobuf.HeartbeatResponse - (*SelfStreamRequest)(nil), // 8: protobuf.SelfStreamRequest - (*SelfStreamResponse)(nil), // 9: protobuf.SelfStreamResponse - (*timestamp.Timestamp)(nil), // 10: google.protobuf.Timestamp + (*LivePreviewRequest)(nil), // 0: protobuf.LivePreviewRequest + (*LivePreviewResponse)(nil), // 1: protobuf.LivePreviewResponse + (*DeleteSectionImageRequest)(nil), // 2: protobuf.DeleteSectionImageRequest + (*GenerateSectionImageResponse)(nil), // 3: protobuf.GenerateSectionImageResponse + (*Section)(nil), // 4: protobuf.Section + (*GenerateSectionImageRequest)(nil), // 5: protobuf.GenerateSectionImageRequest + (*Status)(nil), // 6: protobuf.Status + (*StreamRequest)(nil), // 7: protobuf.StreamRequest + (*StreamResponse)(nil), // 8: protobuf.StreamResponse + (*StreamEndRequest)(nil), // 9: protobuf.StreamEndRequest + (*StreamEndResponse)(nil), // 10: protobuf.StreamEndResponse + (*StreamInfoForUploadRequest)(nil), // 11: protobuf.StreamInfoForUploadRequest + (*StreamInfoForUploadResponse)(nil), // 12: protobuf.StreamInfoForUploadResponse + (*VoDUploadFinished)(nil), // 13: protobuf.VoDUploadFinished + (*SilenceResults)(nil), // 14: protobuf.SilenceResults + (*StreamStarted)(nil), // 15: protobuf.StreamStarted + (*StreamEnded)(nil), // 16: protobuf.StreamEnded + (*ThumbnailsFinished)(nil), // 17: protobuf.ThumbnailsFinished + (*TranscodingFailureNotification)(nil), // 18: protobuf.TranscodingFailureNotification + (*RegisterRequest)(nil), // 19: protobuf.RegisterRequest + (*RegisterResponse)(nil), // 20: protobuf.RegisterResponse + (*HeartbeatRequest)(nil), // 21: protobuf.HeartbeatRequest + (*HeartbeatResponse)(nil), // 22: protobuf.HeartbeatResponse + (*SelfStreamRequest)(nil), // 23: protobuf.SelfStreamRequest + (*SelfStreamResponse)(nil), // 24: protobuf.SelfStreamResponse + (*timestamp.Timestamp)(nil), // 25: google.protobuf.Timestamp } var file_runner_proto_depIdxs = []int32{ - 10, // 0: protobuf.StreamRequest.end:type_name -> google.protobuf.Timestamp - 0, // 1: protobuf.ToRunner.RequestStream:input_type -> protobuf.StreamRequest - 2, // 2: protobuf.ToRunner.RequestStreamEnd:input_type -> protobuf.StreamEndRequest - 4, // 3: protobuf.FromRunner.Register:input_type -> protobuf.RegisterRequest - 6, // 4: protobuf.FromRunner.Heartbeat:input_type -> protobuf.HeartbeatRequest - 8, // 5: protobuf.FromRunner.RequestSelfStream:input_type -> protobuf.SelfStreamRequest - 1, // 6: protobuf.ToRunner.RequestStream:output_type -> protobuf.StreamResponse - 3, // 7: protobuf.ToRunner.RequestStreamEnd:output_type -> protobuf.StreamEndResponse - 5, // 8: protobuf.FromRunner.Register:output_type -> protobuf.RegisterResponse - 7, // 9: protobuf.FromRunner.Heartbeat:output_type -> protobuf.HeartbeatResponse - 9, // 10: protobuf.FromRunner.RequestSelfStream:output_type -> protobuf.SelfStreamResponse - 6, // [6:11] is the sub-list for method output_type - 1, // [1:6] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 4, // 0: protobuf.GenerateSectionImageRequest.Sections:type_name -> protobuf.Section + 25, // 1: protobuf.StreamRequest.end:type_name -> google.protobuf.Timestamp + 25, // 2: protobuf.StreamInfoForUploadResponse.StreamStart:type_name -> google.protobuf.Timestamp + 25, // 3: protobuf.StreamInfoForUploadResponse.StreamEnd:type_name -> google.protobuf.Timestamp + 7, // 4: protobuf.ToRunner.RequestStream:input_type -> protobuf.StreamRequest + 9, // 5: protobuf.ToRunner.RequestStreamEnd:input_type -> protobuf.StreamEndRequest + 0, // 6: protobuf.ToRunner.GenerateLivePreview:input_type -> protobuf.LivePreviewRequest + 5, // 7: protobuf.ToRunner.GenerateSectionImages:input_type -> protobuf.GenerateSectionImageRequest + 2, // 8: protobuf.ToRunner.DeleteSectionImage:input_type -> protobuf.DeleteSectionImageRequest + 19, // 9: protobuf.FromRunner.Register:input_type -> protobuf.RegisterRequest + 21, // 10: protobuf.FromRunner.Heartbeat:input_type -> protobuf.HeartbeatRequest + 23, // 11: protobuf.FromRunner.RequestSelfStream:input_type -> protobuf.SelfStreamRequest + 13, // 12: protobuf.FromRunner.NotifyVoDUploadFinished:input_type -> protobuf.VoDUploadFinished + 14, // 13: protobuf.FromRunner.NotifySilenceResults:input_type -> protobuf.SilenceResults + 15, // 14: protobuf.FromRunner.NotifyStreamStarted:input_type -> protobuf.StreamStarted + 16, // 15: protobuf.FromRunner.NotifyStreamEnded:input_type -> protobuf.StreamEnded + 17, // 16: protobuf.FromRunner.NotifyThumbnailsFinished:input_type -> protobuf.ThumbnailsFinished + 18, // 17: protobuf.FromRunner.NotifyTranscodingFailure:input_type -> protobuf.TranscodingFailureNotification + 11, // 18: protobuf.FromRunner.GetStreamInfoForUpload:input_type -> protobuf.StreamInfoForUploadRequest + 8, // 19: protobuf.ToRunner.RequestStream:output_type -> protobuf.StreamResponse + 10, // 20: protobuf.ToRunner.RequestStreamEnd:output_type -> protobuf.StreamEndResponse + 1, // 21: protobuf.ToRunner.GenerateLivePreview:output_type -> protobuf.LivePreviewResponse + 6, // 22: protobuf.ToRunner.GenerateSectionImages:output_type -> protobuf.Status + 6, // 23: protobuf.ToRunner.DeleteSectionImage:output_type -> protobuf.Status + 20, // 24: protobuf.FromRunner.Register:output_type -> protobuf.RegisterResponse + 22, // 25: protobuf.FromRunner.Heartbeat:output_type -> protobuf.HeartbeatResponse + 24, // 26: protobuf.FromRunner.RequestSelfStream:output_type -> protobuf.SelfStreamResponse + 6, // 27: protobuf.FromRunner.NotifyVoDUploadFinished:output_type -> protobuf.Status + 6, // 28: protobuf.FromRunner.NotifySilenceResults:output_type -> protobuf.Status + 6, // 29: protobuf.FromRunner.NotifyStreamStarted:output_type -> protobuf.Status + 6, // 30: protobuf.FromRunner.NotifyStreamEnded:output_type -> protobuf.Status + 6, // 31: protobuf.FromRunner.NotifyThumbnailsFinished:output_type -> protobuf.Status + 6, // 32: protobuf.FromRunner.NotifyTranscodingFailure:output_type -> protobuf.Status + 12, // 33: protobuf.FromRunner.GetStreamInfoForUpload:output_type -> protobuf.StreamInfoForUploadResponse + 19, // [19:34] is the sub-list for method output_type + 4, // [4:19] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_runner_proto_init() } @@ -709,7 +1928,7 @@ func file_runner_proto_init() { } if !protoimpl.UnsafeEnabled { file_runner_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamRequest); i { + switch v := v.(*LivePreviewRequest); i { case 0: return &v.state case 1: @@ -721,7 +1940,7 @@ func file_runner_proto_init() { } } file_runner_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamResponse); i { + switch v := v.(*LivePreviewResponse); i { case 0: return &v.state case 1: @@ -733,7 +1952,7 @@ func file_runner_proto_init() { } } file_runner_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamEndRequest); i { + switch v := v.(*DeleteSectionImageRequest); i { case 0: return &v.state case 1: @@ -745,7 +1964,7 @@ func file_runner_proto_init() { } } file_runner_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StreamEndResponse); i { + switch v := v.(*GenerateSectionImageResponse); i { case 0: return &v.state case 1: @@ -757,7 +1976,7 @@ func file_runner_proto_init() { } } file_runner_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterRequest); i { + switch v := v.(*Section); i { case 0: return &v.state case 1: @@ -769,7 +1988,7 @@ func file_runner_proto_init() { } } file_runner_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RegisterResponse); i { + switch v := v.(*GenerateSectionImageRequest); i { case 0: return &v.state case 1: @@ -781,7 +2000,7 @@ func file_runner_proto_init() { } } file_runner_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HeartbeatRequest); i { + switch v := v.(*Status); i { case 0: return &v.state case 1: @@ -793,7 +2012,7 @@ func file_runner_proto_init() { } } file_runner_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*HeartbeatResponse); i { + switch v := v.(*StreamRequest); i { case 0: return &v.state case 1: @@ -805,7 +2024,7 @@ func file_runner_proto_init() { } } file_runner_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SelfStreamRequest); i { + switch v := v.(*StreamResponse); i { case 0: return &v.state case 1: @@ -817,6 +2036,186 @@ func file_runner_proto_init() { } } file_runner_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StreamEndRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StreamEndResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StreamInfoForUploadRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StreamInfoForUploadResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VoDUploadFinished); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SilenceResults); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StreamStarted); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StreamEnded); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ThumbnailsFinished); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TranscodingFailureNotification); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RegisterResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HeartbeatRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*HeartbeatResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SelfStreamRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_runner_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SelfStreamResponse); i { case 0: return &v.state @@ -835,7 +2234,7 @@ func file_runner_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_runner_proto_rawDesc, NumEnums: 0, - NumMessages: 10, + NumMessages: 25, NumExtensions: 0, NumServices: 2, }, diff --git a/runner/protobuf/runner_grpc.pb.go b/runner/protobuf/runner_grpc.pb.go index 33a656cf9..339f3355d 100644 --- a/runner/protobuf/runner_grpc.pb.go +++ b/runner/protobuf/runner_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 -// - protoc v3.12.4 +// - protoc v4.25.0 // source: runner.proto package protobuf @@ -25,6 +25,9 @@ type ToRunnerClient interface { // Requests a stream from a lecture hall RequestStream(ctx context.Context, in *StreamRequest, opts ...grpc.CallOption) (*StreamResponse, error) RequestStreamEnd(ctx context.Context, in *StreamEndRequest, opts ...grpc.CallOption) (*StreamEndResponse, error) + GenerateLivePreview(ctx context.Context, in *LivePreviewRequest, opts ...grpc.CallOption) (*LivePreviewResponse, error) + GenerateSectionImages(ctx context.Context, in *GenerateSectionImageRequest, opts ...grpc.CallOption) (*Status, error) + DeleteSectionImage(ctx context.Context, in *DeleteSectionImageRequest, opts ...grpc.CallOption) (*Status, error) } type toRunnerClient struct { @@ -53,6 +56,33 @@ func (c *toRunnerClient) RequestStreamEnd(ctx context.Context, in *StreamEndRequ return out, nil } +func (c *toRunnerClient) GenerateLivePreview(ctx context.Context, in *LivePreviewRequest, opts ...grpc.CallOption) (*LivePreviewResponse, error) { + out := new(LivePreviewResponse) + err := c.cc.Invoke(ctx, "/protobuf.ToRunner/GenerateLivePreview", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *toRunnerClient) GenerateSectionImages(ctx context.Context, in *GenerateSectionImageRequest, opts ...grpc.CallOption) (*Status, error) { + out := new(Status) + err := c.cc.Invoke(ctx, "/protobuf.ToRunner/GenerateSectionImages", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *toRunnerClient) DeleteSectionImage(ctx context.Context, in *DeleteSectionImageRequest, opts ...grpc.CallOption) (*Status, error) { + out := new(Status) + err := c.cc.Invoke(ctx, "/protobuf.ToRunner/DeleteSectionImage", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // ToRunnerServer is the server API for ToRunner service. // All implementations must embed UnimplementedToRunnerServer // for forward compatibility @@ -60,6 +90,9 @@ type ToRunnerServer interface { // Requests a stream from a lecture hall RequestStream(context.Context, *StreamRequest) (*StreamResponse, error) RequestStreamEnd(context.Context, *StreamEndRequest) (*StreamEndResponse, error) + GenerateLivePreview(context.Context, *LivePreviewRequest) (*LivePreviewResponse, error) + GenerateSectionImages(context.Context, *GenerateSectionImageRequest) (*Status, error) + DeleteSectionImage(context.Context, *DeleteSectionImageRequest) (*Status, error) mustEmbedUnimplementedToRunnerServer() } @@ -73,6 +106,15 @@ func (UnimplementedToRunnerServer) RequestStream(context.Context, *StreamRequest func (UnimplementedToRunnerServer) RequestStreamEnd(context.Context, *StreamEndRequest) (*StreamEndResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RequestStreamEnd not implemented") } +func (UnimplementedToRunnerServer) GenerateLivePreview(context.Context, *LivePreviewRequest) (*LivePreviewResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GenerateLivePreview not implemented") +} +func (UnimplementedToRunnerServer) GenerateSectionImages(context.Context, *GenerateSectionImageRequest) (*Status, error) { + return nil, status.Errorf(codes.Unimplemented, "method GenerateSectionImages not implemented") +} +func (UnimplementedToRunnerServer) DeleteSectionImage(context.Context, *DeleteSectionImageRequest) (*Status, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteSectionImage not implemented") +} func (UnimplementedToRunnerServer) mustEmbedUnimplementedToRunnerServer() {} // UnsafeToRunnerServer may be embedded to opt out of forward compatibility for this service. @@ -122,6 +164,60 @@ func _ToRunner_RequestStreamEnd_Handler(srv interface{}, ctx context.Context, de return interceptor(ctx, in, info, handler) } +func _ToRunner_GenerateLivePreview_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LivePreviewRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ToRunnerServer).GenerateLivePreview(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.ToRunner/GenerateLivePreview", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ToRunnerServer).GenerateLivePreview(ctx, req.(*LivePreviewRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ToRunner_GenerateSectionImages_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GenerateSectionImageRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ToRunnerServer).GenerateSectionImages(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.ToRunner/GenerateSectionImages", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ToRunnerServer).GenerateSectionImages(ctx, req.(*GenerateSectionImageRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _ToRunner_DeleteSectionImage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteSectionImageRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ToRunnerServer).DeleteSectionImage(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.ToRunner/DeleteSectionImage", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ToRunnerServer).DeleteSectionImage(ctx, req.(*DeleteSectionImageRequest)) + } + return interceptor(ctx, in, info, handler) +} + // ToRunner_ServiceDesc is the grpc.ServiceDesc for ToRunner service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -137,6 +233,18 @@ var ToRunner_ServiceDesc = grpc.ServiceDesc{ MethodName: "RequestStreamEnd", Handler: _ToRunner_RequestStreamEnd_Handler, }, + { + MethodName: "GenerateLivePreview", + Handler: _ToRunner_GenerateLivePreview_Handler, + }, + { + MethodName: "GenerateSectionImages", + Handler: _ToRunner_GenerateSectionImages_Handler, + }, + { + MethodName: "DeleteSectionImage", + Handler: _ToRunner_DeleteSectionImage_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "runner.proto", @@ -150,6 +258,13 @@ type FromRunnerClient interface { Register(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) Heartbeat(ctx context.Context, in *HeartbeatRequest, opts ...grpc.CallOption) (*HeartbeatResponse, error) RequestSelfStream(ctx context.Context, in *SelfStreamRequest, opts ...grpc.CallOption) (*SelfStreamResponse, error) + NotifyVoDUploadFinished(ctx context.Context, in *VoDUploadFinished, opts ...grpc.CallOption) (*Status, error) + NotifySilenceResults(ctx context.Context, in *SilenceResults, opts ...grpc.CallOption) (*Status, error) + NotifyStreamStarted(ctx context.Context, in *StreamStarted, opts ...grpc.CallOption) (*Status, error) + NotifyStreamEnded(ctx context.Context, in *StreamEnded, opts ...grpc.CallOption) (*Status, error) + NotifyThumbnailsFinished(ctx context.Context, in *ThumbnailsFinished, opts ...grpc.CallOption) (*Status, error) + NotifyTranscodingFailure(ctx context.Context, in *TranscodingFailureNotification, opts ...grpc.CallOption) (*Status, error) + GetStreamInfoForUpload(ctx context.Context, in *StreamInfoForUploadRequest, opts ...grpc.CallOption) (*StreamInfoForUploadResponse, error) } type fromRunnerClient struct { @@ -187,6 +302,69 @@ func (c *fromRunnerClient) RequestSelfStream(ctx context.Context, in *SelfStream return out, nil } +func (c *fromRunnerClient) NotifyVoDUploadFinished(ctx context.Context, in *VoDUploadFinished, opts ...grpc.CallOption) (*Status, error) { + out := new(Status) + err := c.cc.Invoke(ctx, "/protobuf.FromRunner/NotifyVoDUploadFinished", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *fromRunnerClient) NotifySilenceResults(ctx context.Context, in *SilenceResults, opts ...grpc.CallOption) (*Status, error) { + out := new(Status) + err := c.cc.Invoke(ctx, "/protobuf.FromRunner/NotifySilenceResults", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *fromRunnerClient) NotifyStreamStarted(ctx context.Context, in *StreamStarted, opts ...grpc.CallOption) (*Status, error) { + out := new(Status) + err := c.cc.Invoke(ctx, "/protobuf.FromRunner/NotifyStreamStarted", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *fromRunnerClient) NotifyStreamEnded(ctx context.Context, in *StreamEnded, opts ...grpc.CallOption) (*Status, error) { + out := new(Status) + err := c.cc.Invoke(ctx, "/protobuf.FromRunner/NotifyStreamEnded", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *fromRunnerClient) NotifyThumbnailsFinished(ctx context.Context, in *ThumbnailsFinished, opts ...grpc.CallOption) (*Status, error) { + out := new(Status) + err := c.cc.Invoke(ctx, "/protobuf.FromRunner/NotifyThumbnailsFinished", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *fromRunnerClient) NotifyTranscodingFailure(ctx context.Context, in *TranscodingFailureNotification, opts ...grpc.CallOption) (*Status, error) { + out := new(Status) + err := c.cc.Invoke(ctx, "/protobuf.FromRunner/NotifyTranscodingFailure", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *fromRunnerClient) GetStreamInfoForUpload(ctx context.Context, in *StreamInfoForUploadRequest, opts ...grpc.CallOption) (*StreamInfoForUploadResponse, error) { + out := new(StreamInfoForUploadResponse) + err := c.cc.Invoke(ctx, "/protobuf.FromRunner/GetStreamInfoForUpload", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // FromRunnerServer is the server API for FromRunner service. // All implementations must embed UnimplementedFromRunnerServer // for forward compatibility @@ -195,6 +373,13 @@ type FromRunnerServer interface { Register(context.Context, *RegisterRequest) (*RegisterResponse, error) Heartbeat(context.Context, *HeartbeatRequest) (*HeartbeatResponse, error) RequestSelfStream(context.Context, *SelfStreamRequest) (*SelfStreamResponse, error) + NotifyVoDUploadFinished(context.Context, *VoDUploadFinished) (*Status, error) + NotifySilenceResults(context.Context, *SilenceResults) (*Status, error) + NotifyStreamStarted(context.Context, *StreamStarted) (*Status, error) + NotifyStreamEnded(context.Context, *StreamEnded) (*Status, error) + NotifyThumbnailsFinished(context.Context, *ThumbnailsFinished) (*Status, error) + NotifyTranscodingFailure(context.Context, *TranscodingFailureNotification) (*Status, error) + GetStreamInfoForUpload(context.Context, *StreamInfoForUploadRequest) (*StreamInfoForUploadResponse, error) mustEmbedUnimplementedFromRunnerServer() } @@ -211,6 +396,27 @@ func (UnimplementedFromRunnerServer) Heartbeat(context.Context, *HeartbeatReques func (UnimplementedFromRunnerServer) RequestSelfStream(context.Context, *SelfStreamRequest) (*SelfStreamResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RequestSelfStream not implemented") } +func (UnimplementedFromRunnerServer) NotifyVoDUploadFinished(context.Context, *VoDUploadFinished) (*Status, error) { + return nil, status.Errorf(codes.Unimplemented, "method NotifyVoDUploadFinished not implemented") +} +func (UnimplementedFromRunnerServer) NotifySilenceResults(context.Context, *SilenceResults) (*Status, error) { + return nil, status.Errorf(codes.Unimplemented, "method NotifySilenceResults not implemented") +} +func (UnimplementedFromRunnerServer) NotifyStreamStarted(context.Context, *StreamStarted) (*Status, error) { + return nil, status.Errorf(codes.Unimplemented, "method NotifyStreamStarted not implemented") +} +func (UnimplementedFromRunnerServer) NotifyStreamEnded(context.Context, *StreamEnded) (*Status, error) { + return nil, status.Errorf(codes.Unimplemented, "method NotifyStreamEnded not implemented") +} +func (UnimplementedFromRunnerServer) NotifyThumbnailsFinished(context.Context, *ThumbnailsFinished) (*Status, error) { + return nil, status.Errorf(codes.Unimplemented, "method NotifyThumbnailsFinished not implemented") +} +func (UnimplementedFromRunnerServer) NotifyTranscodingFailure(context.Context, *TranscodingFailureNotification) (*Status, error) { + return nil, status.Errorf(codes.Unimplemented, "method NotifyTranscodingFailure not implemented") +} +func (UnimplementedFromRunnerServer) GetStreamInfoForUpload(context.Context, *StreamInfoForUploadRequest) (*StreamInfoForUploadResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetStreamInfoForUpload not implemented") +} func (UnimplementedFromRunnerServer) mustEmbedUnimplementedFromRunnerServer() {} // UnsafeFromRunnerServer may be embedded to opt out of forward compatibility for this service. @@ -278,6 +484,132 @@ func _FromRunner_RequestSelfStream_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _FromRunner_NotifyVoDUploadFinished_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VoDUploadFinished) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FromRunnerServer).NotifyVoDUploadFinished(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.FromRunner/NotifyVoDUploadFinished", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FromRunnerServer).NotifyVoDUploadFinished(ctx, req.(*VoDUploadFinished)) + } + return interceptor(ctx, in, info, handler) +} + +func _FromRunner_NotifySilenceResults_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SilenceResults) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FromRunnerServer).NotifySilenceResults(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.FromRunner/NotifySilenceResults", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FromRunnerServer).NotifySilenceResults(ctx, req.(*SilenceResults)) + } + return interceptor(ctx, in, info, handler) +} + +func _FromRunner_NotifyStreamStarted_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StreamStarted) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FromRunnerServer).NotifyStreamStarted(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.FromRunner/NotifyStreamStarted", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FromRunnerServer).NotifyStreamStarted(ctx, req.(*StreamStarted)) + } + return interceptor(ctx, in, info, handler) +} + +func _FromRunner_NotifyStreamEnded_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StreamEnded) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FromRunnerServer).NotifyStreamEnded(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.FromRunner/NotifyStreamEnded", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FromRunnerServer).NotifyStreamEnded(ctx, req.(*StreamEnded)) + } + return interceptor(ctx, in, info, handler) +} + +func _FromRunner_NotifyThumbnailsFinished_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ThumbnailsFinished) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FromRunnerServer).NotifyThumbnailsFinished(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.FromRunner/NotifyThumbnailsFinished", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FromRunnerServer).NotifyThumbnailsFinished(ctx, req.(*ThumbnailsFinished)) + } + return interceptor(ctx, in, info, handler) +} + +func _FromRunner_NotifyTranscodingFailure_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TranscodingFailureNotification) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FromRunnerServer).NotifyTranscodingFailure(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.FromRunner/NotifyTranscodingFailure", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FromRunnerServer).NotifyTranscodingFailure(ctx, req.(*TranscodingFailureNotification)) + } + return interceptor(ctx, in, info, handler) +} + +func _FromRunner_GetStreamInfoForUpload_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(StreamInfoForUploadRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FromRunnerServer).GetStreamInfoForUpload(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/protobuf.FromRunner/GetStreamInfoForUpload", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FromRunnerServer).GetStreamInfoForUpload(ctx, req.(*StreamInfoForUploadRequest)) + } + return interceptor(ctx, in, info, handler) +} + // FromRunner_ServiceDesc is the grpc.ServiceDesc for FromRunner service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -297,6 +629,34 @@ var FromRunner_ServiceDesc = grpc.ServiceDesc{ MethodName: "RequestSelfStream", Handler: _FromRunner_RequestSelfStream_Handler, }, + { + MethodName: "NotifyVoDUploadFinished", + Handler: _FromRunner_NotifyVoDUploadFinished_Handler, + }, + { + MethodName: "NotifySilenceResults", + Handler: _FromRunner_NotifySilenceResults_Handler, + }, + { + MethodName: "NotifyStreamStarted", + Handler: _FromRunner_NotifyStreamStarted_Handler, + }, + { + MethodName: "NotifyStreamEnded", + Handler: _FromRunner_NotifyStreamEnded_Handler, + }, + { + MethodName: "NotifyThumbnailsFinished", + Handler: _FromRunner_NotifyThumbnailsFinished_Handler, + }, + { + MethodName: "NotifyTranscodingFailure", + Handler: _FromRunner_NotifyTranscodingFailure_Handler, + }, + { + MethodName: "GetStreamInfoForUpload", + Handler: _FromRunner_GetStreamInfoForUpload_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "runner.proto", diff --git a/runner/runner.go b/runner/runner.go index 44473ff3b..caa60dc3d 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -2,9 +2,11 @@ package runner import ( "context" + "fmt" "github.com/caarlos0/env" "github.com/google/uuid" "github.com/tum-dev/gocast/runner/actions" + "github.com/tum-dev/gocast/runner/config" "github.com/tum-dev/gocast/runner/pkg/logging" "github.com/tum-dev/gocast/runner/pkg/netutil" "github.com/tum-dev/gocast/runner/protobuf" @@ -12,15 +14,13 @@ import ( "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/reflection" - - "fmt" "log/slog" "net" "os" "time" ) -type config struct { +type envConfig struct { LogFmt string `env:"LOG_FMT" envDefault:"txt"` LogLevel string `env:"LOG_LEVEL" envDefault:"debug"` Port int `env:"PORT" envDefault:"0"` @@ -32,8 +32,9 @@ type config struct { } type Runner struct { - cfg config + cfg envConfig log *slog.Logger + cmd config.CmdList JobCount chan int draining bool @@ -47,20 +48,25 @@ type Runner struct { func NewRunner(v string) *Runner { log := logging.GetLogger(v) - var cfg config + var cfg envConfig if err := env.Parse(&cfg); err != nil { - log.Error("error parsing config", "error", err) + log.Error("error parsing envConfig", "error", err) } - log.Info("config loaded", "config", cfg) + log.Info("envConfig loaded", "envConfig", cfg) + + cmd := config.NewCmd(log) + log.Info("loading cmd.yaml", "cmd", cmd) return &Runner{ log: log, JobCount: make(chan int, 1), draining: false, cfg: cfg, + cmd: *cmd, jobs: make(map[string]*Job), actions: actions.ActionProvider{ Log: log, + Cmd: *cmd, SegmentDir: cfg.SegmentPath, RecDir: cfg.RecPath, MassDir: cfg.StoragePath, diff --git a/runner/runner.proto b/runner/runner.proto index 0cad3659a..a786f744e 100644 --- a/runner/runner.proto +++ b/runner/runner.proto @@ -8,6 +8,44 @@ service ToRunner { // Requests a stream from a lecture hall rpc RequestStream (StreamRequest) returns (StreamResponse) {} rpc RequestStreamEnd (StreamEndRequest) returns (StreamEndResponse) {} + rpc GenerateLivePreview (LivePreviewRequest) returns (LivePreviewResponse){} + rpc GenerateSectionImages (GenerateSectionImageRequest) returns (Status) {} + rpc DeleteSectionImage (DeleteSectionImageRequest) returns (Status) {} +} + +message LivePreviewRequest{ + string RunnerID = 1; + string HLSUrl = 2; +} + +message LivePreviewResponse{ + bytes LiveThumb = 1; +} + +message DeleteSectionImageRequest { + string Path = 1; +} + +message GenerateSectionImageResponse { + repeated string Paths = 1; +} + +message Section { + uint32 Hours = 1; + uint32 Minutes = 2; + uint32 Seconds = 3; +} + +message GenerateSectionImageRequest { + string PlaylistURL = 1; + string CourseName = 2; + uint32 CourseYear = 3; + string CourseTeachingTerm = 4; + repeated Section Sections = 5; +} + +message Status{ + bool ok = 1; } message StreamRequest { @@ -36,6 +74,74 @@ service FromRunner { rpc Register (RegisterRequest) returns (RegisterResponse) {} rpc Heartbeat (HeartbeatRequest) returns (HeartbeatResponse) {} rpc RequestSelfStream (SelfStreamRequest) returns (SelfStreamResponse) {} + rpc NotifyVoDUploadFinished (VoDUploadFinished) returns (Status) {} + rpc NotifySilenceResults (SilenceResults) returns (Status) {} + rpc NotifyStreamStarted (StreamStarted) returns (Status) {} + rpc NotifyStreamEnded (StreamEnded) returns (Status) {} + rpc NotifyThumbnailsFinished (ThumbnailsFinished) returns (Status) {} + rpc NotifyTranscodingFailure (TranscodingFailureNotification) returns (Status) {} + rpc GetStreamInfoForUpload (StreamInfoForUploadRequest) returns (StreamInfoForUploadResponse) {} +} + +message StreamInfoForUploadRequest{ + string RunnerID = 1; + uint32 UploadKey = 2; +} + +message StreamInfoForUploadResponse{ + string CourseSlug = 1; + string CourseTerm = 2; + uint32 CourseYear = 3; + google.protobuf.Timestamp StreamStart = 4; + google.protobuf.Timestamp StreamEnd = 5; + uint32 StreamID = 6; + string VideoType = 7; +} + +message VoDUploadFinished{ + string RunnerID = 1; + uint32 StreamID = 2; + string HLSUrl = 3; + string SourceType = 4; + string ThumbnailUrl = 5; +} + +message SilenceResults{ + string RunnerID = 1; + uint32 StreamID = 2; + repeated uint32 starts = 3 [packed = true]; + repeated uint32 ends = 4 [packed = true]; +} + +message StreamStarted { + string RunnerID = 1; + uint32 StreamID = 2; + string HLSUrl = 3; + string SourceType = 4; +} + +message StreamEnded{ + string RunnerID = 1; + uint32 StreamID = 2; +} + +message ThumbnailsFinished{ + string RunnerID = 1; + uint32 StreamID = 2; + string FilePath = 3; + uint32 Interval = 4; + string SourceType = 5; + + string LargeThumbnailPath = 6; +} + +message TranscodingFailureNotification{ + string RunnerID = 1; + uint32 StreamID = 2; + string Version = 3; + string FilePath = 4; + string Logs = 5; + int64 ExitCode = 6; } message RegisterRequest { @@ -44,19 +150,23 @@ message RegisterRequest { } message RegisterResponse { + string ID = 1; } message HeartbeatRequest { - uint64 ID = 1; - uint32 Workload = 2; - string Version = 3; - string CPU = 4; - string Memory = 5; - string Disk = 6; - string Uptime = 7; + string hostname = 1; + int32 port = 2; + uint32 Workload = 3; + string Version = 4; + string CPU = 5; + string Memory = 6; + string Disk = 7; + string Uptime = 8; } -message HeartbeatResponse {} +message HeartbeatResponse { + bool ok = 1; +} message SelfStreamRequest { string streamKey = 1; diff --git a/web/admin.go b/web/admin.go index 9a7b992f7..784eda827 100755 --- a/web/admin.go +++ b/web/admin.go @@ -5,12 +5,12 @@ import ( "encoding/json" "errors" "fmt" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "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/getsentry/sentry-go" + "github.com/gin-gonic/gin" log "github.com/sirupsen/logrus" "gorm.io/gorm" "net/http" @@ -41,6 +41,10 @@ func (r mainRoutes) AdminPage(c *gin.Context) { if err != nil { sentry.CaptureException(err) } + runners, err := r.RunnerDao.GetAll(context.Background()) + if err != nil { + sentry.CaptureException(err) + } lectureHalls := r.LectureHallsDao.GetAllLectureHalls() indexData := NewIndexData() indexData.TUMLiveContext = tumLiveContext @@ -57,6 +61,9 @@ func (r mainRoutes) AdminPage(c *gin.Context) { if c.Request.URL.Path == "/admin/workers" { page = "workers" } + if c.Request.URL.Path == "/admin/runners" { + page = "runners" + } if c.Request.URL.Path == "/admin/create-course" { page = "createCourse" } @@ -135,6 +142,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { InfoPages: infopages, ServerNotifications: serverNotifications, Notifications: notifications, + Runners: RunnersData{Runners: runners}, }) if err != nil { log.Printf("%v", err) @@ -146,6 +154,10 @@ type WorkersData struct { Token string } +type RunnersData struct { + Runners []model.Runner +} + func (r mainRoutes) LectureCutPage(c *gin.Context) { foundContext, exists := c.Get("TUMLiveContext") if !exists { @@ -304,6 +316,7 @@ type AdminPageData struct { Tokens []dao.AllTokensDto InfoPages []model.InfoPage Notifications []model.Notification + Runners RunnersData } func (apd AdminPageData) UsersAsJson() string { diff --git a/web/router.go b/web/router.go index 90d2faea0..064d34425 100755 --- a/web/router.go +++ b/web/router.go @@ -11,9 +11,9 @@ import ( "path" "github.com/Masterminds/sprig/v3" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/tools" + "github.com/gin-gonic/gin" ) var templateExecutor tools.TemplateExecutor @@ -125,6 +125,7 @@ func configMainRoute(router *gin.Engine) { adminGroup.GET("/admin/notifications", routes.AdminPage) adminGroup.GET("/admin/audits", routes.AdminPage) adminGroup.GET("/admin/maintenance", routes.AdminPage) + adminGroup.GET("/admin/runners", routes.AdminPage) courseAdminGroup := router.Group("/") courseAdminGroup.Use(tools.InitCourse(daoWrapper)) diff --git a/web/template/admin/admin.gohtml b/web/template/admin/admin.gohtml index 72a4ff16c..ee7367dd5 100755 --- a/web/template/admin/admin.gohtml +++ b/web/template/admin/admin.gohtml @@ -44,6 +44,13 @@ href="/admin/workers">Workers +
  • + + + Runners + +
  • Workers
  • +
  • + + + Runners + +
  • +

    Runners

    +
    + + + + + + + + + + + + {{- /*gotype: github.com/TUM-Dev/gocast/web.RunnersData*/ -}} + {{range $runner := .Runners}} + huui there + + + + + + + + {{end}} + + +
    NameStatusWorkloadUptimeActions
    +
    {{$runner.Host}}@{{$runner.Version}} +
    +
    + CPU: {{$runner.CPU}} + Mem: {{$runner.Memory}} + Disk: {{$runner.Disk}} +
    +
    {{if $runner.IsAlive}} + Alive{{else}} + Dead{{end}}{{$runner.Status}} + + {{$runner.Workload}} + {{$runner.Uptime}} + +
    +
    + + +{{end}} \ No newline at end of file From ecc8147f9cceef27ba70afda82d4b101b1b3ecfc Mon Sep 17 00:00:00 2001 From: Dawin Yurtseven Date: Thu, 7 Dec 2023 16:09:31 +0100 Subject: [PATCH 03/31] a slight push of progress before switchi --- api/runner_grpc.go | 2 +- model/runner.go | 19 ++++++------------- runner/actions/actions.go | 1 + runner/runner.go | 14 ++++++++++++++ 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/api/runner_grpc.go b/api/runner_grpc.go index d286d435a..f174453f8 100644 --- a/api/runner_grpc.go +++ b/api/runner_grpc.go @@ -56,7 +56,7 @@ func (g GrpcRunnerServer) Heartbeat(ctx context.Context, request *protobuf.Heart log.WithError(err).Error("Failed to get runner") return &protobuf.HeartbeatResponse{Ok: false}, err } - + ctx = context.WithValue(ctx, "runner", runner) p, err := r.UpdateStats(dao.DB, ctx) return &protobuf.HeartbeatResponse{Ok: p}, err } diff --git a/model/runner.go b/model/runner.go index 71552b136..8f9357af7 100644 --- a/model/runner.go +++ b/model/runner.go @@ -35,19 +35,12 @@ func (r *Runner) BeforeCreate(tx *gorm.DB) (err error) { } // SendHeartbeat updates the last seen time of the runner and gives runner stats -func (r *Runner) UpdateStats(tx *gorm.DB, context context.Context) (bool, error) { - - tx.Model(&r).Updates(Runner{ - LastSeen: sql.NullTime{Time: tx.NowFunc(), Valid: true}, - Status: r.Status, - Workload: r.Workload, - CPU: r.CPU, - Memory: r.Memory, - Disk: r.Disk, - Uptime: r.Uptime, - Version: r.Version, - }) - +func (r *Runner) UpdateStats(tx *gorm.DB, ctx context.Context) (bool, error) { + runner := ctx.Value("runner").(Runner) + err := tx.WithContext(ctx).Model(&r).Updates(runner).Error + if err != nil { + return false, err + } return true, nil } diff --git a/runner/actions/actions.go b/runner/actions/actions.go index 333da8a4e..9165547d1 100644 --- a/runner/actions/actions.go +++ b/runner/actions/actions.go @@ -42,6 +42,7 @@ const ( TranscodeAction = "transcode" UploadAction = "upload" ThumbnailAction = "thumbnail" + HeartBeatAction = "heartbeat" ) type Action struct { diff --git a/runner/runner.go b/runner/runner.go index caa60dc3d..630368057 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -158,6 +158,20 @@ func (r *Runner) dialIn() (protobuf.FromRunnerClient, error) { return protobuf.NewFromRunnerClient(conn), nil } +// Todo: implement heartbeat here so you can reach server and make actions from runner more easier to reach +func (r *Runner) ReadDiagnostics(retries int) (protobuf.HeartbeatRequest, error) { + con, err := r.dialIn() + if err != nil { + r.log.Warn("error connecting to gocast", "error", err, "sleeping(s)", registerRetries-retries) + time.Sleep(time.Second * time.Duration(registerRetries-retries)) + return r.ReadDiagnostics(retries - 1) + } + if con == nil { + + } + return protobuf.HeartbeatRequest{}, nil +} + type Job struct { ID string Actions []*actions.Action From 220c68910bf49e3c05c84b19b6312cc736a4e381 Mon Sep 17 00:00:00 2001 From: Dawin Yurtseven Date: Thu, 28 Dec 2023 13:35:00 +0100 Subject: [PATCH 04/31] added some communication with tumlive and runner and working on selfstream.go --- api/router.go | 3 +- api/runner.go | 39 ++ api/runner_grpc.go | 64 +++- dao/dao_base.go | 2 +- dao/runner.go | 11 +- model/runner.go | 6 +- runner/actions/actions.go | 12 +- runner/actions/selfstream.go | 16 + runner/actions/transcode.go | 3 +- runner/actions/upload.go | 116 +++++- runner/cmd.yaml | 2 +- runner/go.mod | 15 +- runner/go.sum | 41 +++ runner/handlers.go | 17 +- runner/protobuf/runner.pb.go | 382 ++++++++++++-------- runner/runner.go | 84 ++++- runner/runner.proto | 22 +- runner/vmstat/vmstat.go | 101 ++++++ web/template/admin/admin_tabs/runner.gohtml | 11 +- 19 files changed, 754 insertions(+), 193 deletions(-) create mode 100644 api/runner.go create mode 100644 runner/actions/selfstream.go create mode 100644 runner/vmstat/vmstat.go diff --git a/api/router.go b/api/router.go index 1b03a7eec..78f6f8909 100755 --- a/api/router.go +++ b/api/router.go @@ -1,9 +1,9 @@ package api import ( - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/tools" + "github.com/gin-gonic/gin" ) // ConfigChatRouter configure gin router for chat (without gzip) @@ -40,6 +40,7 @@ func ConfigGinRouter(router *gin.Engine) { configServerNotificationsRoutes(router, daoWrapper) configTokenRouter(router, daoWrapper) configWorkerRouter(router, daoWrapper) + configRunnerRouter(router, daoWrapper) configNotificationsRouter(router, daoWrapper) configInfoPageRouter(router, daoWrapper) configGinSearchRouter(router, daoWrapper) diff --git a/api/runner.go b/api/runner.go new file mode 100644 index 000000000..86a9fde84 --- /dev/null +++ b/api/runner.go @@ -0,0 +1,39 @@ +package api + +import ( + "context" + "github.com/TUM-Dev/gocast/dao" + "github.com/TUM-Dev/gocast/tools" + "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" + "net/http" +) + +func configRunnerRouter(r *gin.Engine, daoWrapper dao.DaoWrapper) { + g := r.Group("/api/runner") + g.Use(tools.Admin) + + routes := runnerRoutes{dao: daoWrapper.RunnerDao} + + g.DELETE("/:HostName", routes.deleteRunner) +} + +type runnerRoutes struct { + dao dao.RunnerDao +} + +func (r runnerRoutes) deleteRunner(c *gin.Context) { + log.Info("delete runner with hostname: ", c.Param("Hostname")) + ctx := context.Background() + err := r.dao.Delete(ctx, c.Param("Hostname")) + if err != nil { + //logging for later + _ = c.Error(tools.RequestError{ + Status: http.StatusInternalServerError, + CustomMessage: "can not delete runner", + Err: err, + }) + return + } + +} diff --git a/api/runner_grpc.go b/api/runner_grpc.go index f174453f8..3f41c1116 100644 --- a/api/runner_grpc.go +++ b/api/runner_grpc.go @@ -3,6 +3,7 @@ package api import ( "context" "database/sql" + "errors" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" log "github.com/sirupsen/logrus" @@ -10,6 +11,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/reflection" + "google.golang.org/protobuf/types/known/timestamppb" "net" "time" ) @@ -41,6 +43,17 @@ func (g GrpcRunnerServer) Heartbeat(ctx context.Context, request *protobuf.Heart runner := model.Runner{ Hostname: request.Hostname, Port: int(request.Port), + } + + r, err := g.RunnerDao.Get(ctx, runner.Hostname) + if err != nil { + log.WithError(err).Error("Failed to get runner") + return &protobuf.HeartbeatResponse{Ok: false}, err + } + + newStats := model.Runner{ + Hostname: request.Hostname, + Port: int(request.Port), LastSeen: sql.NullTime{Valid: true, Time: time.Now()}, Status: "Alive", Workload: uint(request.Workload), @@ -50,20 +63,53 @@ func (g GrpcRunnerServer) Heartbeat(ctx context.Context, request *protobuf.Heart Uptime: request.Uptime, Version: request.Version, } - - r, err := g.RunnerDao.Get(ctx, runner.Hostname) - if err != nil { - log.WithError(err).Error("Failed to get runner") - return &protobuf.HeartbeatResponse{Ok: false}, err - } - ctx = context.WithValue(ctx, "runner", runner) + ctx = context.WithValue(ctx, "newStats", newStats) + log.Info("Updating runner stats ", "runner", r) p, err := r.UpdateStats(dao.DB, ctx) return &protobuf.HeartbeatResponse{Ok: p}, err } +// RequestSelfStream is called by the runner when a stream is supposed to be started by obs or other third party software +// returns an error if anything goes wrong OR the stream may not be published func (g GrpcRunnerServer) RequestSelfStream(ctx context.Context, request *protobuf.SelfStreamRequest) (*protobuf.SelfStreamResponse, error) { - //TODO implement me - panic("implement me") + //TODO Test me/Improve me + if request.StreamKey == "" { + return nil, errors.New("stream key is empty") + } + stream, err := g.StreamsDao.GetStreamByKey(ctx, request.StreamKey) + if err != nil { + return nil, err + } + course, err := g.CoursesDao.GetCourseById(ctx, stream.CourseID) + if err != nil { + return nil, err + } + 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") + } + ingestServer, err := g.IngestServerDao.GetBestIngestServer() + if err != nil { + return nil, err + } + slot, err := g.IngestServerDao.GetStreamSlot(ingestServer.ID) + if err != nil { + return nil, err + } + slot.StreamID = stream.ID + g.IngestServerDao.SaveSlot(slot) + + return &protobuf.SelfStreamResponse{ + Stream: uint64(stream.ID), + Course: uint64(course.ID), + CourseYear: uint64(course.Year), + StreamStart: timestamppb.New(stream.Start), + StreamEnd: timestamppb.New(stream.End), + UploadVoD: course.VODEnabled, + IngestServer: ingestServer.Url, + StreamName: stream.StreamName, + OutURL: ingestServer.OutUrl, + }, nil } func (g GrpcRunnerServer) mustEmbedUnimplementedFromRunnerServer() { diff --git a/dao/dao_base.go b/dao/dao_base.go index 6f1888853..f9850cd45 100644 --- a/dao/dao_base.go +++ b/dao/dao_base.go @@ -36,7 +36,7 @@ type DaoWrapper struct { SubtitlesDao TranscodingFailureDao EmailDao - RunnerDao RunnerDao + RunnerDao } func NewDaoWrapper() DaoWrapper { diff --git a/dao/runner.go b/dao/runner.go index d5ee21176..931c6c122 100644 --- a/dao/runner.go +++ b/dao/runner.go @@ -3,6 +3,7 @@ package dao import ( "context" "github.com/TUM-Dev/gocast/model" + log "github.com/sirupsen/logrus" "gorm.io/gorm" "gorm.io/gorm/clause" ) @@ -37,8 +38,14 @@ func (d runnerDao) Get(c context.Context, hostname string) (res model.Runner, er } // Get all Runners in an array -func (d runnerDao) GetAll(c context.Context) (res []model.Runner, err error) { - return res, d.db.WithContext(c).Model(&model.Runner{}).Find(&res).Error +func (d runnerDao) GetAll(c context.Context) ([]model.Runner, error) { + var runners []model.Runner + err := d.db.WithContext(c).Model(&model.Runner{}).Find(&runners).Error + if err != nil { + log.Error("no runners found") + return nil, err + } + return runners, err } // Create a Runner. diff --git a/model/runner.go b/model/runner.go index 8f9357af7..ccfbbb272 100644 --- a/model/runner.go +++ b/model/runner.go @@ -36,14 +36,14 @@ func (r *Runner) BeforeCreate(tx *gorm.DB) (err error) { // SendHeartbeat updates the last seen time of the runner and gives runner stats func (r *Runner) UpdateStats(tx *gorm.DB, ctx context.Context) (bool, error) { - runner := ctx.Value("runner").(Runner) - err := tx.WithContext(ctx).Model(&r).Updates(runner).Error + newStats := ctx.Value("newStats").(Runner) + err := tx.WithContext(ctx).Model(&r).Updates(newStats).Error if err != nil { return false, err } return true, nil } -func (r *Runner) isAlive() bool { +func (r *Runner) IsAlive() bool { return r.LastSeen.Time.After(time.Now().Add(time.Minute * -6)) } diff --git a/runner/actions/actions.go b/runner/actions/actions.go index 9165547d1..43a9c6af8 100644 --- a/runner/actions/actions.go +++ b/runner/actions/actions.go @@ -37,12 +37,12 @@ func (a *ActionProvider) GetMassDir(courseID, streamID uint64, version string) s type ActionType string const ( - PrepareAction ActionType = "prepare" - StreamAction = "stream" - TranscodeAction = "transcode" - UploadAction = "upload" - ThumbnailAction = "thumbnail" - HeartBeatAction = "heartbeat" + PrepareAction ActionType = "prepare" + StreamAction = "stream" + TranscodeAction = "transcode" + UploadAction = "upload" + ThumbnailAction = "thumbnail" + SelfStreamAction = "selfstream" ) type Action struct { diff --git a/runner/actions/selfstream.go b/runner/actions/selfstream.go new file mode 100644 index 000000000..2b0b502bd --- /dev/null +++ b/runner/actions/selfstream.go @@ -0,0 +1,16 @@ +package actions + +import ( + "context" + "log/slog" +) + +func (a *ActionProvider) SelfStreamAction() *Action { + return &Action{ + Type: SelfStreamAction, + ActionFn: func(ctx context.Context, log *slog.Logger) (context.Context, error) { + + return ctx, nil + }, + } +} diff --git a/runner/actions/transcode.go b/runner/actions/transcode.go index dbe0eb031..87cfcd74b 100644 --- a/runner/actions/transcode.go +++ b/runner/actions/transcode.go @@ -15,6 +15,7 @@ func (a *ActionProvider) TranscodeAction() *Action { return &Action{ Type: TranscodeAction, ActionFn: func(ctx context.Context, log *slog.Logger) (context.Context, error) { + files, ok := ctx.Value("files").([]string) if !ok { return ctx, ErrActionInputWrongType @@ -47,7 +48,7 @@ func (a *ActionProvider) TranscodeAction() *Action { if len(fileName) == 1 { filenames = fileName[0] } else { - filenames := `"concat:` + fileName[0] + filenames = `"concat:` + fileName[0] for i := 1; i < len(fileName); i++ { filenames += "|" + fileName[i] } diff --git a/runner/actions/upload.go b/runner/actions/upload.go index 27dae23cc..569e67e84 100644 --- a/runner/actions/upload.go +++ b/runner/actions/upload.go @@ -2,14 +2,128 @@ package actions import ( "context" + "fmt" + "github.com/TUM-Dev/gocast/worker/cfg" + "io" "log/slog" + "mime/multipart" + "net/http" + "os" + "strings" + "time" ) func (a *ActionProvider) UploadAction() *Action { return &Action{ Type: UploadAction, ActionFn: func(ctx context.Context, log *slog.Logger) (context.Context, error) { - return ctx, nil + + streamID, ok := ctx.Value("stream").(uint64) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain stream", ErrRequiredContextValNotFound) + } + courseID, ok := ctx.Value("course").(uint64) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain courseID", ErrRequiredContextValNotFound) + } + version, ok := ctx.Value("version").(string) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain version", ErrRequiredContextValNotFound) + } + + URLstring := ctx.Value("URL").(string) + + fileName := fmt.Sprintf("%s/%s/%s/%s.mp4", a.MassDir, courseID, streamID, version) + + client := &http.Client{ + // 5 minutes timeout, some large files can take a while. + Timeout: time.Minute * 5, + } + + r, w := io.Pipe() + writer := multipart.NewWriter(w) + + //the same function as in the worker but without function calling + //so analyzing it and changing it later won't give much to look through + + go func() { + defer func(w *io.PipeWriter) { + err := w.Close() + if err != nil { + + } + }(w) + defer func(writer *multipart.Writer) { + err := writer.Close() + if err != nil { + + } + }(writer) + formFileWriter, err := writer.CreateFormFile("filename", fileName) + if err != nil { + log.Error("Cannot create form file: ", err) + return + } + FileReader, err := os.Open(fileName) + if err != nil { + log.Error("Cannot create form file: ", err) + return + } + defer func(FileReader *os.File) { + err := FileReader.Close() + if err != nil { + + } + }(FileReader) + _, err = io.Copy(formFileWriter, FileReader) + if err != nil { + log.Error("Cannot create form file: ", err) + return + } + + fields := map[string]string{ + "benutzer": cfg.LrzUser, + "mailadresse": cfg.LrzMail, + "telefon": cfg.LrzPhone, + "unidir": "tum", + "subdir": cfg.LrzSubDir, + "info": "", + } + + for name, value := range fields { + formFileWriter, err := writer.CreateFormField(name) + if err != nil { + log.Error("Cannot create form field: ", err) + return + } + _, err = io.Copy(formFileWriter, strings.NewReader(value)) + if err != nil { + log.Error("Cannot create form field: ", err) + return + } + if err != nil { + log.Error("Cannot create form field: ", err) + return + } + } + }() + rsp, err := client.Post(URLstring, writer.FormDataContentType(), r) + if err == nil && rsp.StatusCode != http.StatusOK { + log.Error("Request failed with response code: ", rsp.StatusCode) + } + if err == nil && rsp != nil { + all, err := io.ReadAll(rsp.Body) + if err == nil { + log.Debug(string(all), "fileUploaded", fileName) + } + } + if err != nil { + log.Error("Failed to post video to TUMLive", "error", err) + return ctx, err + } + log.Info("Successfully posted video to TUMLive", "stream", fileName) + + return ctx, err }, } } diff --git a/runner/cmd.yaml b/runner/cmd.yaml index 6ee27fa3f..72d1c4c15 100644 --- a/runner/cmd.yaml +++ b/runner/cmd.yaml @@ -1,4 +1,4 @@ stream: '-y -hide_banner -nostats %v -t %.0f -i %v -c:v copy -c:a copy -f mpegts %v -c:v libx264 -preset veryfast -tune zerolatency -maxrate 2500k -bufsize 3000k -g 60 -r 30 -x264-params keyint=60:scenecut=0 -c:a aac -ar 44100 -b:a 128k -f hls -hls_time 2 -hls_list_size 3600 -hls_playlist_type event -hls_flags append_list -hls_segment_filename %v/%%05d.ts %v' -Transcoding: '-i %v -c:v libx264 %v' +Transcoding: '-i %v -c copy -f mpegts probesize 100M -analyzeduration 250M -c:v libx264 -c:a aac -b:a 128k %v' diff --git a/runner/go.mod b/runner/go.mod index 7a250e643..1887bf32e 100644 --- a/runner/go.mod +++ b/runner/go.mod @@ -2,25 +2,38 @@ module github.com/tum-dev/gocast/runner go 1.21.0 +toolchain go1.21.3 + require ( github.com/caarlos0/env v3.5.0+incompatible github.com/dusted-go/logging v1.1.1 github.com/ghodss/yaml v1.0.0 github.com/golang/protobuf v1.5.3 github.com/google/uuid v1.3.0 + github.com/icza/gox v0.0.0-20230924165045-adcb03233bb5 github.com/joschahenningsen/thumbgen v0.1.2 + github.com/shirou/gopsutil/v3 v3.23.11 + github.com/sirupsen/logrus v1.9.3 + golang.org/x/sync v0.3.0 google.golang.org/grpc v1.58.2 google.golang.org/protobuf v1.31.0 ) require ( + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/stretchr/testify v1.8.4 // indirect github.com/tidwall/gjson v1.14.1 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect golang.org/x/image v0.7.0 // indirect golang.org/x/net v0.12.0 // indirect - golang.org/x/sys v0.10.0 // indirect + golang.org/x/sys v0.15.0 // indirect golang.org/x/text v0.11.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/runner/go.sum b/runner/go.sum index 3daf104ab..2f4f75435 100644 --- a/runner/go.sum +++ b/runner/go.sum @@ -1,23 +1,48 @@ github.com/caarlos0/env v3.5.0+incompatible h1:Yy0UN8o9Wtr/jGHZDpCBLpNrzcFLLM2yixi/rBrKyJs= github.com/caarlos0/env v3.5.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dusted-go/logging v1.1.1 h1:x1aSyarDh2iq7MIhCZkjbepsZD9FmAURK93jRFm2Oco= github.com/dusted-go/logging v1.1.1/go.mod h1:Lim3Rk6x2MYwpvPZ6XzPk6ZeX4Wgz9lVOptrL7ngr5w= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 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/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/icza/gox v0.0.0-20230924165045-adcb03233bb5 h1:K7KEFpKgVcjj98jOu2Z3xMBTtTwfYVT90Zmo3ZuWmbE= +github.com/icza/gox v0.0.0-20230924165045-adcb03233bb5/go.mod h1:VbcN86fRkkUMPX2ufM85Um8zFndLZswoIW1eYtpAcVk= github.com/joschahenningsen/thumbgen v0.1.2 h1:sHIxmvZkuPaiiCjRvKcFNqTmH5IN4kiQiVt+wpAPC8A= github.com/joschahenningsen/thumbgen v0.1.2/go.mod h1:h8bDlQ2Bq3U/I/VlN8IRA48P7tHW8SHChVXmUWrG3bU= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= +github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ= +github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo= @@ -26,7 +51,13 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw= @@ -42,14 +73,23 @@ golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -77,5 +117,6 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/runner/handlers.go b/runner/handlers.go index 3ed5e3a6a..c7b5bbd4d 100644 --- a/runner/handlers.go +++ b/runner/handlers.go @@ -16,22 +16,26 @@ func contextFromStreamReq(req *protobuf.StreamRequest, ctx context.Context) cont } func (r *Runner) RequestStream(ctx context.Context, req *protobuf.StreamRequest) (*protobuf.StreamResponse, error) { + r.ReadDiagnostics(5) // don't reuse context from grpc, it will be canceled when the request is done. ctx = context.Background() ctx = contextFromStreamReq(req, ctx) + ctx = context.WithValue(ctx, "URL", "") a := []*actions.Action{ r.actions.PrepareAction(), r.actions.StreamAction(), r.actions.TranscodeAction(), - r.actions.GenerateVideoThumbnail(), + //r.actions.GenerateVideoThumbnail(), r.actions.UploadAction(), } jobID := r.AddJob(ctx, a) + r.log.Info("job added", "jobID", jobID) return &protobuf.StreamResponse{Job: jobID}, nil } func (r *Runner) RequestStreamEnd(ctx context.Context, request *protobuf.StreamEndRequest) (*protobuf.StreamEndResponse, error) { + r.ReadDiagnostics(5) if job, ok := r.jobs[request.GetJobID()]; ok { job.Cancel(errors.New("canceled by user request"), actions.StreamAction, actions.UploadAction) return &protobuf.StreamEndResponse{}, nil @@ -40,6 +44,7 @@ func (r *Runner) RequestStreamEnd(ctx context.Context, request *protobuf.StreamE } func (r *Runner) GenerateLivePreview(ctx context.Context, request *protobuf.LivePreviewRequest) (*protobuf.LivePreviewResponse, error) { + r.ReadDiagnostics(5) if job, ok := r.jobs[request.GetRunnerID()]; ok { job.Cancel(errors.New("canceled by user request"), actions.StreamAction) return &protobuf.LivePreviewResponse{}, nil @@ -47,3 +52,13 @@ func (r *Runner) GenerateLivePreview(ctx context.Context, request *protobuf.Live return nil, errors.New("Live Preview not Generated") } + +func (r *Runner) GenerateSectionImages(ctx context.Context, request *protobuf.GenerateSectionImageRequest) (*protobuf.Status, error) { + r.ReadDiagnostics(5) + if job, ok := r.jobs[request.PlaylistURL]; ok { + job.Cancel(errors.New("canceled by user request"), actions.StreamAction) + return &protobuf.Status{Ok: true}, nil + } + + return nil, errors.New("Section Images not Generated") +} diff --git a/runner/protobuf/runner.pb.go b/runner/protobuf/runner.pb.go index b1ba9d215..0fa242c06 100644 --- a/runner/protobuf/runner.pb.go +++ b/runner/protobuf/runner.pb.go @@ -1332,14 +1332,16 @@ type HeartbeatRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Hostname string `protobuf:"bytes,1,opt,name=hostname,proto3" json:"hostname,omitempty"` - Port int32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"` - Workload uint32 `protobuf:"varint,3,opt,name=Workload,proto3" json:"Workload,omitempty"` - Version string `protobuf:"bytes,4,opt,name=Version,proto3" json:"Version,omitempty"` - CPU string `protobuf:"bytes,5,opt,name=CPU,proto3" json:"CPU,omitempty"` - Memory string `protobuf:"bytes,6,opt,name=Memory,proto3" json:"Memory,omitempty"` - Disk string `protobuf:"bytes,7,opt,name=Disk,proto3" json:"Disk,omitempty"` - Uptime string `protobuf:"bytes,8,opt,name=Uptime,proto3" json:"Uptime,omitempty"` + Hostname string `protobuf:"bytes,1,opt,name=hostname,proto3" json:"hostname,omitempty"` + Port int32 `protobuf:"varint,2,opt,name=port,proto3" json:"port,omitempty"` + LastSeen *timestamp.Timestamp `protobuf:"bytes,3,opt,name=LastSeen,proto3" json:"LastSeen,omitempty"` + Status string `protobuf:"bytes,4,opt,name=Status,proto3" json:"Status,omitempty"` + Workload uint32 `protobuf:"varint,5,opt,name=Workload,proto3" json:"Workload,omitempty"` + CPU string `protobuf:"bytes,6,opt,name=CPU,proto3" json:"CPU,omitempty"` + Memory string `protobuf:"bytes,7,opt,name=Memory,proto3" json:"Memory,omitempty"` + Disk string `protobuf:"bytes,8,opt,name=Disk,proto3" json:"Disk,omitempty"` + Uptime string `protobuf:"bytes,9,opt,name=Uptime,proto3" json:"Uptime,omitempty"` + Version string `protobuf:"bytes,10,opt,name=Version,proto3" json:"Version,omitempty"` } func (x *HeartbeatRequest) Reset() { @@ -1388,20 +1390,27 @@ func (x *HeartbeatRequest) GetPort() int32 { return 0 } -func (x *HeartbeatRequest) GetWorkload() uint32 { +func (x *HeartbeatRequest) GetLastSeen() *timestamp.Timestamp { if x != nil { - return x.Workload + return x.LastSeen } - return 0 + return nil } -func (x *HeartbeatRequest) GetVersion() string { +func (x *HeartbeatRequest) GetStatus() string { if x != nil { - return x.Version + return x.Status } return "" } +func (x *HeartbeatRequest) GetWorkload() uint32 { + if x != nil { + return x.Workload + } + return 0 +} + func (x *HeartbeatRequest) GetCPU() string { if x != nil { return x.CPU @@ -1430,6 +1439,13 @@ func (x *HeartbeatRequest) GetUptime() string { return "" } +func (x *HeartbeatRequest) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + type HeartbeatResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1529,9 +1545,15 @@ type SelfStreamResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Stream uint64 `protobuf:"varint,1,opt,name=stream,proto3" json:"stream,omitempty"` - Course uint64 `protobuf:"varint,2,opt,name=course,proto3" json:"course,omitempty"` - Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + Stream uint64 `protobuf:"varint,1,opt,name=stream,proto3" json:"stream,omitempty"` + Course uint64 `protobuf:"varint,2,opt,name=course,proto3" json:"course,omitempty"` + CourseYear uint64 `protobuf:"varint,3,opt,name=courseYear,proto3" json:"courseYear,omitempty"` + StreamStart *timestamp.Timestamp `protobuf:"bytes,4,opt,name=streamStart,proto3" json:"streamStart,omitempty"` + StreamEnd *timestamp.Timestamp `protobuf:"bytes,5,opt,name=streamEnd,proto3" json:"streamEnd,omitempty"` + UploadVoD bool `protobuf:"varint,6,opt,name=uploadVoD,proto3" json:"uploadVoD,omitempty"` + IngestServer string `protobuf:"bytes,7,opt,name=ingestServer,proto3" json:"ingestServer,omitempty"` + StreamName string `protobuf:"bytes,8,opt,name=streamName,proto3" json:"streamName,omitempty"` + OutURL string `protobuf:"bytes,9,opt,name=outURL,proto3" json:"outURL,omitempty"` } func (x *SelfStreamResponse) Reset() { @@ -1580,9 +1602,51 @@ func (x *SelfStreamResponse) GetCourse() uint64 { return 0 } -func (x *SelfStreamResponse) GetVersion() string { +func (x *SelfStreamResponse) GetCourseYear() uint64 { if x != nil { - return x.Version + return x.CourseYear + } + return 0 +} + +func (x *SelfStreamResponse) GetStreamStart() *timestamp.Timestamp { + if x != nil { + return x.StreamStart + } + return nil +} + +func (x *SelfStreamResponse) GetStreamEnd() *timestamp.Timestamp { + if x != nil { + return x.StreamEnd + } + return nil +} + +func (x *SelfStreamResponse) GetUploadVoD() bool { + if x != nil { + return x.UploadVoD + } + return false +} + +func (x *SelfStreamResponse) GetIngestServer() string { + if x != nil { + return x.IngestServer + } + return "" +} + +func (x *SelfStreamResponse) GetStreamName() string { + if x != nil { + return x.StreamName + } + return "" +} + +func (x *SelfStreamResponse) GetOutURL() string { + if x != nil { + return x.OutURL } return "" } @@ -1734,108 +1798,129 @@ var file_runner_proto_rawDesc = []byte{ 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x22, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x22, 0xce, 0x01, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x22, 0x9e, 0x02, 0x0a, 0x10, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1a, 0x0a, 0x08, - 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, - 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x43, 0x50, 0x55, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x43, 0x50, 0x55, 0x12, 0x16, 0x0a, 0x06, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, - 0x44, 0x69, 0x73, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x44, 0x69, 0x73, 0x6b, - 0x12, 0x16, 0x0a, 0x06, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x23, 0x0a, 0x11, 0x48, 0x65, 0x61, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x36, 0x0a, 0x08, + 0x4c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x4c, 0x61, 0x73, 0x74, + 0x53, 0x65, 0x65, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, + 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, + 0x57, 0x6f, 0x72, 0x6b, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x43, 0x50, 0x55, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x43, 0x50, 0x55, 0x12, 0x16, 0x0a, 0x06, 0x4d, 0x65, + 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4d, 0x65, 0x6d, 0x6f, + 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x69, 0x73, 0x6b, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x44, 0x69, 0x73, 0x6b, 0x12, 0x16, 0x0a, 0x06, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x23, 0x0a, 0x11, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x02, 0x6f, 0x6b, 0x22, 0x31, 0x0a, 0x11, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4b, 0x65, 0x79, - 0x22, 0x5e, 0x0a, 0x12, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x16, - 0x0a, 0x06, 0x63, 0x6f, 0x75, 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, - 0x63, 0x6f, 0x75, 0x72, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x32, 0x98, 0x03, 0x0a, 0x08, 0x54, 0x6f, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x44, 0x0a, - 0x0d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x17, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x10, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x54, 0x0a, 0x13, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4c, 0x69, - 0x76, 0x65, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x76, 0x65, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x76, 0x65, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x15, 0x47, 0x65, 0x6e, 0x65, - 0x72, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6d, 0x61, 0x67, 0x65, - 0x73, 0x12, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x47, 0x65, 0x6e, - 0x65, 0x72, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6d, 0x61, 0x67, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x12, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6d, 0x61, - 0x67, 0x65, 0x12, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6d, 0x61, 0x67, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x32, 0x92, 0x06, 0x0a, 0x0a, - 0x46, 0x72, 0x6f, 0x6d, 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x43, 0x0a, 0x08, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, 0x65, 0x67, - 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x46, 0x0a, 0x09, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x1a, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x11, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1b, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x17, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x79, 0x56, 0x6f, 0x44, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6e, 0x69, - 0x73, 0x68, 0x65, 0x64, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x56, 0x6f, 0x44, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, - 0x64, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x14, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x53, - 0x69, 0x6c, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x18, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x69, 0x6c, 0x65, 0x6e, 0x63, 0x65, - 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x13, 0x4e, - 0x6f, 0x74, 0x69, 0x66, 0x79, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x74, 0x61, 0x72, 0x74, - 0x65, 0x64, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x1a, 0x10, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, - 0x3e, 0x0a, 0x11, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, - 0x6e, 0x64, 0x65, 0x64, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x1a, 0x10, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, - 0x4c, 0x0a, 0x18, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, - 0x69, 0x6c, 0x73, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x1c, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, - 0x73, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x58, 0x0a, - 0x18, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x69, - 0x6e, 0x67, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, - 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x67, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x53, 0x74, - 0x72, 0x65, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x46, 0x6f, 0x72, 0x55, 0x70, 0x6c, 0x6f, 0x61, - 0x64, 0x12, 0x24, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x46, 0x6f, 0x72, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x46, 0x6f, 0x72, - 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x42, 0x11, 0x5a, 0x0f, 0x72, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x22, 0xd6, 0x02, 0x0a, 0x12, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, + 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x75, 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x06, 0x63, 0x6f, 0x75, 0x72, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x75, 0x72, 0x73, + 0x65, 0x59, 0x65, 0x61, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x63, 0x6f, 0x75, + 0x72, 0x73, 0x65, 0x59, 0x65, 0x61, 0x72, 0x12, 0x3c, 0x0a, 0x0b, 0x73, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x53, 0x74, 0x61, 0x72, 0x74, 0x12, 0x38, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, + 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x12, + 0x1c, 0x0a, 0x09, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x56, 0x6f, 0x44, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x09, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x56, 0x6f, 0x44, 0x12, 0x22, 0x0a, + 0x0c, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x55, 0x52, 0x4c, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x55, 0x52, 0x4c, 0x32, 0x98, 0x03, 0x0a, 0x08, 0x54, 0x6f, + 0x52, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x12, 0x44, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x10, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, + 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x13, 0x47, + 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x76, 0x65, 0x50, 0x72, 0x65, 0x76, 0x69, + 0x65, 0x77, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, + 0x76, 0x65, 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x76, 0x65, + 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x52, 0x0a, 0x15, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x53, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x73, 0x12, 0x25, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x53, 0x65, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, + 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x23, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x22, 0x00, 0x32, 0x92, 0x06, 0x0a, 0x0a, 0x46, 0x72, 0x6f, 0x6d, 0x52, 0x75, 0x6e, + 0x6e, 0x65, 0x72, 0x12, 0x43, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, + 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x09, 0x48, 0x65, 0x61, 0x72, + 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x48, 0x65, 0x61, + 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x50, 0x0a, 0x11, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, 0x65, 0x6c, 0x66, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x53, 0x65, 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, + 0x6c, 0x66, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x17, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x56, 0x6f, 0x44, 0x55, + 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x1b, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x6f, 0x44, 0x55, 0x70, 0x6c, 0x6f, + 0x61, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x44, + 0x0a, 0x14, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x53, 0x69, 0x6c, 0x65, 0x6e, 0x63, 0x65, 0x52, + 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x53, 0x69, 0x6c, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, + 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x22, 0x00, 0x12, 0x42, 0x0a, 0x13, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x12, 0x17, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x74, 0x61, + 0x72, 0x74, 0x65, 0x64, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x11, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x12, 0x15, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, + 0x6e, 0x64, 0x65, 0x64, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x18, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x79, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x73, 0x46, 0x69, 0x6e, 0x69, + 0x73, 0x68, 0x65, 0x64, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x54, 0x68, 0x75, 0x6d, 0x62, 0x6e, 0x61, 0x69, 0x6c, 0x73, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, + 0x65, 0x64, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x18, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x46, 0x61, 0x69, 0x6c, 0x75, + 0x72, 0x65, 0x12, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, + 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x10, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, + 0x12, 0x67, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x6e, 0x66, + 0x6f, 0x46, 0x6f, 0x72, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x24, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, + 0x46, 0x6f, 0x72, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x46, 0x6f, 0x72, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x11, 0x5a, 0x0f, 0x72, 0x75, 0x6e, + 0x6e, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1884,41 +1969,44 @@ var file_runner_proto_depIdxs = []int32{ 25, // 1: protobuf.StreamRequest.end:type_name -> google.protobuf.Timestamp 25, // 2: protobuf.StreamInfoForUploadResponse.StreamStart:type_name -> google.protobuf.Timestamp 25, // 3: protobuf.StreamInfoForUploadResponse.StreamEnd:type_name -> google.protobuf.Timestamp - 7, // 4: protobuf.ToRunner.RequestStream:input_type -> protobuf.StreamRequest - 9, // 5: protobuf.ToRunner.RequestStreamEnd:input_type -> protobuf.StreamEndRequest - 0, // 6: protobuf.ToRunner.GenerateLivePreview:input_type -> protobuf.LivePreviewRequest - 5, // 7: protobuf.ToRunner.GenerateSectionImages:input_type -> protobuf.GenerateSectionImageRequest - 2, // 8: protobuf.ToRunner.DeleteSectionImage:input_type -> protobuf.DeleteSectionImageRequest - 19, // 9: protobuf.FromRunner.Register:input_type -> protobuf.RegisterRequest - 21, // 10: protobuf.FromRunner.Heartbeat:input_type -> protobuf.HeartbeatRequest - 23, // 11: protobuf.FromRunner.RequestSelfStream:input_type -> protobuf.SelfStreamRequest - 13, // 12: protobuf.FromRunner.NotifyVoDUploadFinished:input_type -> protobuf.VoDUploadFinished - 14, // 13: protobuf.FromRunner.NotifySilenceResults:input_type -> protobuf.SilenceResults - 15, // 14: protobuf.FromRunner.NotifyStreamStarted:input_type -> protobuf.StreamStarted - 16, // 15: protobuf.FromRunner.NotifyStreamEnded:input_type -> protobuf.StreamEnded - 17, // 16: protobuf.FromRunner.NotifyThumbnailsFinished:input_type -> protobuf.ThumbnailsFinished - 18, // 17: protobuf.FromRunner.NotifyTranscodingFailure:input_type -> protobuf.TranscodingFailureNotification - 11, // 18: protobuf.FromRunner.GetStreamInfoForUpload:input_type -> protobuf.StreamInfoForUploadRequest - 8, // 19: protobuf.ToRunner.RequestStream:output_type -> protobuf.StreamResponse - 10, // 20: protobuf.ToRunner.RequestStreamEnd:output_type -> protobuf.StreamEndResponse - 1, // 21: protobuf.ToRunner.GenerateLivePreview:output_type -> protobuf.LivePreviewResponse - 6, // 22: protobuf.ToRunner.GenerateSectionImages:output_type -> protobuf.Status - 6, // 23: protobuf.ToRunner.DeleteSectionImage:output_type -> protobuf.Status - 20, // 24: protobuf.FromRunner.Register:output_type -> protobuf.RegisterResponse - 22, // 25: protobuf.FromRunner.Heartbeat:output_type -> protobuf.HeartbeatResponse - 24, // 26: protobuf.FromRunner.RequestSelfStream:output_type -> protobuf.SelfStreamResponse - 6, // 27: protobuf.FromRunner.NotifyVoDUploadFinished:output_type -> protobuf.Status - 6, // 28: protobuf.FromRunner.NotifySilenceResults:output_type -> protobuf.Status - 6, // 29: protobuf.FromRunner.NotifyStreamStarted:output_type -> protobuf.Status - 6, // 30: protobuf.FromRunner.NotifyStreamEnded:output_type -> protobuf.Status - 6, // 31: protobuf.FromRunner.NotifyThumbnailsFinished:output_type -> protobuf.Status - 6, // 32: protobuf.FromRunner.NotifyTranscodingFailure:output_type -> protobuf.Status - 12, // 33: protobuf.FromRunner.GetStreamInfoForUpload:output_type -> protobuf.StreamInfoForUploadResponse - 19, // [19:34] is the sub-list for method output_type - 4, // [4:19] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name + 25, // 4: protobuf.HeartbeatRequest.LastSeen:type_name -> google.protobuf.Timestamp + 25, // 5: protobuf.SelfStreamResponse.streamStart:type_name -> google.protobuf.Timestamp + 25, // 6: protobuf.SelfStreamResponse.streamEnd:type_name -> google.protobuf.Timestamp + 7, // 7: protobuf.ToRunner.RequestStream:input_type -> protobuf.StreamRequest + 9, // 8: protobuf.ToRunner.RequestStreamEnd:input_type -> protobuf.StreamEndRequest + 0, // 9: protobuf.ToRunner.GenerateLivePreview:input_type -> protobuf.LivePreviewRequest + 5, // 10: protobuf.ToRunner.GenerateSectionImages:input_type -> protobuf.GenerateSectionImageRequest + 2, // 11: protobuf.ToRunner.DeleteSectionImage:input_type -> protobuf.DeleteSectionImageRequest + 19, // 12: protobuf.FromRunner.Register:input_type -> protobuf.RegisterRequest + 21, // 13: protobuf.FromRunner.Heartbeat:input_type -> protobuf.HeartbeatRequest + 23, // 14: protobuf.FromRunner.RequestSelfStream:input_type -> protobuf.SelfStreamRequest + 13, // 15: protobuf.FromRunner.NotifyVoDUploadFinished:input_type -> protobuf.VoDUploadFinished + 14, // 16: protobuf.FromRunner.NotifySilenceResults:input_type -> protobuf.SilenceResults + 15, // 17: protobuf.FromRunner.NotifyStreamStarted:input_type -> protobuf.StreamStarted + 16, // 18: protobuf.FromRunner.NotifyStreamEnded:input_type -> protobuf.StreamEnded + 17, // 19: protobuf.FromRunner.NotifyThumbnailsFinished:input_type -> protobuf.ThumbnailsFinished + 18, // 20: protobuf.FromRunner.NotifyTranscodingFailure:input_type -> protobuf.TranscodingFailureNotification + 11, // 21: protobuf.FromRunner.GetStreamInfoForUpload:input_type -> protobuf.StreamInfoForUploadRequest + 8, // 22: protobuf.ToRunner.RequestStream:output_type -> protobuf.StreamResponse + 10, // 23: protobuf.ToRunner.RequestStreamEnd:output_type -> protobuf.StreamEndResponse + 1, // 24: protobuf.ToRunner.GenerateLivePreview:output_type -> protobuf.LivePreviewResponse + 6, // 25: protobuf.ToRunner.GenerateSectionImages:output_type -> protobuf.Status + 6, // 26: protobuf.ToRunner.DeleteSectionImage:output_type -> protobuf.Status + 20, // 27: protobuf.FromRunner.Register:output_type -> protobuf.RegisterResponse + 22, // 28: protobuf.FromRunner.Heartbeat:output_type -> protobuf.HeartbeatResponse + 24, // 29: protobuf.FromRunner.RequestSelfStream:output_type -> protobuf.SelfStreamResponse + 6, // 30: protobuf.FromRunner.NotifyVoDUploadFinished:output_type -> protobuf.Status + 6, // 31: protobuf.FromRunner.NotifySilenceResults:output_type -> protobuf.Status + 6, // 32: protobuf.FromRunner.NotifyStreamStarted:output_type -> protobuf.Status + 6, // 33: protobuf.FromRunner.NotifyStreamEnded:output_type -> protobuf.Status + 6, // 34: protobuf.FromRunner.NotifyThumbnailsFinished:output_type -> protobuf.Status + 6, // 35: protobuf.FromRunner.NotifyTranscodingFailure:output_type -> protobuf.Status + 12, // 36: protobuf.FromRunner.GetStreamInfoForUpload:output_type -> protobuf.StreamInfoForUploadResponse + 22, // [22:37] is the sub-list for method output_type + 7, // [7:22] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name } func init() { file_runner_proto_init() } diff --git a/runner/runner.go b/runner/runner.go index 630368057..3d992afa8 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -5,15 +5,18 @@ import ( "fmt" "github.com/caarlos0/env" "github.com/google/uuid" + log "github.com/sirupsen/logrus" "github.com/tum-dev/gocast/runner/actions" "github.com/tum-dev/gocast/runner/config" "github.com/tum-dev/gocast/runner/pkg/logging" "github.com/tum-dev/gocast/runner/pkg/netutil" "github.com/tum-dev/gocast/runner/protobuf" + "github.com/tum-dev/gocast/runner/vmstat" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/reflection" + "google.golang.org/protobuf/types/known/timestamppb" "log/slog" "net" "os" @@ -29,6 +32,7 @@ type envConfig struct { RecPath string `env:"REC_PATH" envDefault:"storage/rec"` GocastServer string `env:"GOCAST_SERVER" envDefault:"localhost:50056"` Hostname string `env:"REALHOST" envDefault:"localhost"` + Version string `env:"VERSION" envDefault:"v0.0.0"` } type Runner struct { @@ -43,6 +47,10 @@ type Runner struct { actions actions.ActionProvider hlsServer *HLSServer + stats *vmstat.VmStat + + StartTime time.Time + protobuf.UnimplementedToRunnerServer } @@ -57,6 +65,9 @@ func NewRunner(v string) *Runner { cmd := config.NewCmd(log) log.Info("loading cmd.yaml", "cmd", cmd) + vmstats := vmstat.New() + + start := time.Now() return &Runner{ log: log, JobCount: make(chan int, 1), @@ -72,6 +83,8 @@ func NewRunner(v string) *Runner { MassDir: cfg.StoragePath, }, hlsServer: NewHLSServer(cfg.SegmentPath, log.WithGroup("HLSServer")), + stats: vmstats, + StartTime: start, } } @@ -137,6 +150,7 @@ func (r *Runner) RegisterWithGocast(retries int) { r.log.Warn("error connecting to gocast", "error", err, "sleeping(s)", registerRetries-retries) time.Sleep(time.Second * time.Duration(registerRetries-retries)) r.RegisterWithGocast(retries - 1) + r.ReadDiagnostics(5) return } _, err = con.Register(context.Background(), &protobuf.RegisterRequest{Hostname: r.cfg.Hostname, Port: int32(r.cfg.Port)}) @@ -144,8 +158,10 @@ func (r *Runner) RegisterWithGocast(retries int) { r.log.Warn("error registering with gocast", "error", err, "sleeping(s)", registerRetries-retries) time.Sleep(time.Second * time.Duration(registerRetries-retries)) r.RegisterWithGocast(retries - 1) + r.ReadDiagnostics(5) return } + r.ReadDiagnostics(5) } // dialIn connects to manager instance and returns a client @@ -158,18 +174,72 @@ func (r *Runner) dialIn() (protobuf.FromRunnerClient, error) { return protobuf.NewFromRunnerClient(conn), nil } -// Todo: implement heartbeat here so you can reach server and make actions from runner more easier to reach -func (r *Runner) ReadDiagnostics(retries int) (protobuf.HeartbeatRequest, error) { +func (r *Runner) ReadDiagnostics(retries int) { + + r.log.Info("Started Sending Diagnostic Data", "retriesLeft", retries) + + if retries == 0 { + return + } + err := r.stats.Update() + if err != nil { + r.ReadDiagnostics(retries - 1) + return + } + cpu := r.stats.GetCpuStr() + memory := r.stats.GetMemStr() + disk := r.stats.GetDiskStr() + uptime := time.Now().Sub(r.StartTime).String() con, err := r.dialIn() if err != nil { - r.log.Warn("error connecting to gocast", "error", err, "sleeping(s)", registerRetries-retries) - time.Sleep(time.Second * time.Duration(registerRetries-retries)) - return r.ReadDiagnostics(retries - 1) + log.Warn("couldn't dial into server", "error", err, "sleeping(s)", 5-retries) + time.Sleep(time.Second * time.Duration(5-retries)) + r.ReadDiagnostics(retries - 1) + return } - if con == nil { + _, err = con.Heartbeat(context.Background(), &protobuf.HeartbeatRequest{ + Hostname: r.cfg.Hostname, + Port: int32(r.cfg.Port), + LastSeen: timestamppb.New(time.Now()), + Status: "Alive", + Workload: uint32(len(r.jobs)), + CPU: cpu, + Memory: memory, + Disk: disk, + Uptime: uptime, + Version: r.cfg.Version, + }) + if err != nil { + r.log.Warn("Error sending the heartbeat", "error", err, "sleeping(s)", 5-retries) + time.Sleep(time.Second * time.Duration(5-retries)) + r.ReadDiagnostics(retries - 1) + return + } + r.log.Info("Successfully sent heartbeat", "retriesLeft", retries) +} + +func (r *Runner) RequestSelfStream(ctx context.Context, retries int) { + r.log.Info("Started Requesting Self Stream", "retriesLeft", retries) + + streamKey := ctx.Value("streamkey").(string) + + if retries == 0 { + r.log.Error("no more retries left, can't start Self Stream") + return } - return protobuf.HeartbeatRequest{}, nil + + con, err := r.dialIn() + if err != nil { + r.log.Warn("error connecting to gocast", "error", err, "sleeping(s)", 5-retries) + time.Sleep(time.Second * time.Duration(5-retries)) + r.RequestSelfStream(ctx, retries-1) + return + } + + _, err = con.RequestSelfStream(context.Background(), &protobuf.SelfStreamRequest{ + StreamKey: streamKey, + }) } type Job struct { diff --git a/runner/runner.proto b/runner/runner.proto index a786f744e..dd4c21d25 100644 --- a/runner/runner.proto +++ b/runner/runner.proto @@ -156,12 +156,14 @@ message RegisterResponse { message HeartbeatRequest { string hostname = 1; int32 port = 2; - uint32 Workload = 3; - string Version = 4; - string CPU = 5; - string Memory = 6; - string Disk = 7; - string Uptime = 8; + google.protobuf.Timestamp LastSeen = 3; + string Status = 4; + uint32 Workload = 5; + string CPU = 6; + string Memory = 7; + string Disk = 8; + string Uptime = 9; + string Version = 10; } message HeartbeatResponse { @@ -175,6 +177,12 @@ message SelfStreamRequest { message SelfStreamResponse { uint64 stream = 1; uint64 course = 2; - string version = 3; + uint64 courseYear = 3; + google.protobuf.Timestamp streamStart = 4; + google.protobuf.Timestamp streamEnd = 5; + bool uploadVoD = 6; + string ingestServer = 7; + string streamName = 8; + string outURL = 9; } diff --git a/runner/vmstat/vmstat.go b/runner/vmstat/vmstat.go new file mode 100644 index 000000000..c683e3f57 --- /dev/null +++ b/runner/vmstat/vmstat.go @@ -0,0 +1,101 @@ +package vmstat + +import ( + "context" + "fmt" + "github.com/icza/gox/fmtx" + "github.com/shirou/gopsutil/v3/cpu" + "github.com/shirou/gopsutil/v3/disk" + "github.com/shirou/gopsutil/v3/mem" + "golang.org/x/sync/errgroup" + "time" +) + +type VmStat struct { + diskPath string + + CpuPercent float64 + + MemTotal uint64 + MemAvailable uint64 + + DiskTotal uint64 + DiskPercent float64 + DiskUsed uint64 +} + +var ( + ErrCPUInvalid = fmt.Errorf("len (cpu.Percent) != 1") +) + +func New() *VmStat { + return &VmStat{diskPath: "/"} +} + +func NewWithPath(path string) *VmStat { + return &VmStat{diskPath: path} +} + +func (s *VmStat) Update() error { + g, _ := errgroup.WithContext(context.Background()) + g.Go(s.getCpu) + g.Go(s.getMem) + g.Go(s.getDisk) + return g.Wait() +} + +func (s *VmStat) getMem() error { + memory, err := mem.VirtualMemory() + if err != nil { + return err + } + s.MemAvailable = memory.Available + s.MemTotal = memory.Total + return nil +} + +func (s *VmStat) getCpu() error { + percent, err := cpu.Percent(time.Second*5, false) + if err != nil { + return err + } + if len(percent) != 1 { + return ErrCPUInvalid + } + s.CpuPercent = percent[0] + return nil +} + +func (s *VmStat) getDisk() error { + usage, err := disk.Usage("/") + if err != nil { + return err + } + s.DiskUsed = usage.Used + s.DiskTotal = usage.Total + s.DiskPercent = usage.UsedPercent + return nil +} + +func (s *VmStat) GetCpuStr() string { + return fmt.Sprintf("%.f%%", s.CpuPercent) +} + +func (s *VmStat) GetMemStr() string { + if s.MemAvailable == 0 || s.MemTotal == 0 { + return "unknown" + } + return fmt.Sprintf("%sM/%sM (%.f%%)", + fmtx.FormatInt(int64(s.MemAvailable/1e+6), 3, '.'), + fmtx.FormatInt(int64(s.MemTotal/1e+6), 3, '.'), + (1-(float64(s.MemAvailable)/float64(s.MemTotal)))*100) +} + +func (s *VmStat) GetDiskStr() string { + return fmt.Sprintf("%dG/%dG (%.f%%)", s.DiskUsed/1e+9, s.DiskTotal/1e+9, s.DiskPercent) +} + +func (s *VmStat) String() string { + return fmt.Sprintf("CPU: [%s], Mem: [%s], Disk: [%s]", + s.GetCpuStr(), s.GetMemStr(), s.GetDiskStr()) +} diff --git a/web/template/admin/admin_tabs/runner.gohtml b/web/template/admin/admin_tabs/runner.gohtml index f52e70731..0ff064a2b 100644 --- a/web/template/admin/admin_tabs/runner.gohtml +++ b/web/template/admin/admin_tabs/runner.gohtml @@ -15,11 +15,12 @@ {{- /*gotype: github.com/TUM-Dev/gocast/web.RunnersData*/ -}} {{range $runner := .Runners}} - huui there + - -
    {{$runner.Host}} +
    {{$runner.Hostname}}@{{$runner.Version}} +
    CPU: {{$runner.CPU}} @@ -36,10 +37,10 @@ {{$runner.Uptime}} - From ce364685379b817afebbdba9259fd1c7f42455f9 Mon Sep 17 00:00:00 2001 From: Dawin Yurtseven Date: Tue, 2 Jan 2024 16:57:00 +0100 Subject: [PATCH 05/31] merge runner with dev --- .gitattributes | 1 + .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/deploy-server.yml | 2 +- .github/workflows/deploy-workers.yml | 2 +- .github/workflows/go-test.yml | 2 +- .github/workflows/golangci-lint.yml | 3 +- .golangci.yml | 9 +- .idea/runConfigurations/all.xml | 8 - README.md | 2 +- api/api_logger.go | 10 + api/chat.go | 65 +- api/courseimport.go | 21 +- api/courses.go | 76 +- api/download.go | 7 +- api/download_ics.go | 5 +- api/lecture_halls.go | 19 +- api/live_update.go | 9 +- api/maintenance.go | 21 +- api/notifications.go | 7 +- api/progress.go | 9 +- api/realtime.go | 5 +- api/seek_stats.go | 7 +- api/server-notifications.go | 13 +- api/statistics.go | 45 +- api/stream.go | 59 +- api/token.go | 7 +- api/users.go | 65 +- api/voice_service_grpc.go | 9 +- api/worker.go | 5 +- api/worker_grpc.go | 121 ++- api/wsHub.go | 12 +- cmd/tumlive/tumlive.go | 60 +- dao/courses.go | 10 +- dao/dao_logger.go | 10 + dao/video-seek.go | 3 +- go.mod | 5 +- go.sum | 22 +- go.work | 4 +- go.work.sum | 35 +- model/course.go | 3 +- model/model_logger.go | 10 + model/stream.go | 13 + model/user.go | 33 + runner/go.mod | 23 +- runner/go.sum | 811 ++++++++++++++++++ runner/runner.go | 2 +- tools/bot/bot.go | 5 +- tools/bot/bot_logger.go | 10 + tools/bot/matrix.go | 7 +- tools/branding.go | 3 +- tools/camera/camera_logger.go | 10 + tools/camera/panasonic.go | 15 +- tools/config.go | 17 +- tools/email.go | 7 +- tools/meiliExporter.go | 17 +- tools/meiliSearch.go | 3 +- tools/middlewares.go | 15 +- tools/presets.go | 23 +- tools/realtime/channel_store.go | 3 +- tools/realtime/realtime.go | 5 +- tools/realtime/realtime_logger.go | 10 + tools/session.go | 4 +- tools/template_executor.go | 5 +- tools/tools_logger.go | 10 + tools/tum/campus-online-base.go | 5 +- tools/tum/courses.go | 9 +- tools/tum/events.go | 11 +- tools/tum/students.go | 7 +- tools/tum/tum_logger.go | 10 + vod-service/internal/internal_logger.go | 10 + vod-service/internal/vodService.go | 11 +- web/admin.go | 29 +- web/assets/css/main.css | 5 + web/assets/init-admin.js | 106 ++- web/course.go | 16 +- web/index.go | 17 +- web/popup.go | 5 +- web/router.go | 3 +- web/saml.go | 30 +- .../admin/admin_tabs/course-import.gohtml | 4 +- .../admin/admin_tabs/create-course.gohtml | 23 +- .../admin/admin_tabs/edit-course.gohtml | 2 +- web/template/home.gohtml | 51 +- web/template/login.gohtml | 12 +- web/template/partial/close-btn.gohtml | 10 + .../course/manage/course_actions.gohtml | 12 +- .../course/manage/course_settings.gohtml | 2 +- .../lecture-type-slide.gohtml | 12 +- .../course/manage/create-lecture-form.gohtml | 8 +- .../course/manage/edit-video-sections.gohtml | 209 +++-- .../manage/lecture-management-card.gohtml | 2 +- .../course/manage/semester-selection.gohtml | 12 +- web/template/partial/footer.gohtml | 24 + web/template/partial/info-dropdown.gohtml | 2 +- web/template/partial/theme-selector.gohtml | 5 +- web/template/popup-chat.gohtml | 3 +- web/template/user-settings.gohtml | 52 +- web/template/video_only.gohtml | 2 +- web/template/watch.gohtml | 25 +- web/ts/TUMLiveVjs.ts | 7 +- web/ts/api/admin-lecture-list.ts | 119 +++ web/ts/api/video-sections.ts | 19 - web/ts/change-set.ts | 42 +- web/ts/components/main.ts | 21 +- web/ts/components/popup.ts | 13 + web/ts/course-import.ts | 27 +- web/ts/data-store/admin-lecture-list.ts | 94 +- web/ts/data-store/video-sections.ts | 35 +- web/ts/edit-course.ts | 158 +++- web/ts/entry/admins.ts | 2 +- web/ts/entry/video.ts | 1 - web/ts/stream-playlist.ts | 20 +- web/ts/user-settings.ts | 16 + web/ts/video-sections.ts | 134 --- web/user.go | 11 +- web/watch.go | 15 +- web/web_logger.go | 10 + worker/edge/go.mod | 2 +- worker/go.mod | 2 +- worker/worker/request_handlers.go | 82 +- worker/worker/transcode.go | 13 +- 121 files changed, 2391 insertions(+), 1039 deletions(-) create mode 100644 .gitattributes delete mode 100644 .idea/runConfigurations/all.xml create mode 100644 api/api_logger.go create mode 100644 dao/dao_logger.go create mode 100644 model/model_logger.go create mode 100644 tools/bot/bot_logger.go create mode 100644 tools/camera/camera_logger.go create mode 100644 tools/realtime/realtime_logger.go create mode 100644 tools/tools_logger.go create mode 100644 tools/tum/tum_logger.go create mode 100644 vod-service/internal/internal_logger.go create mode 100644 web/template/partial/close-btn.gohtml create mode 100644 web/template/partial/footer.gohtml delete mode 100644 web/ts/video-sections.ts create mode 100644 web/web_logger.go diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..d207b1802 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.go text eol=lf diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c531a2e44..dec7c1742 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -55,7 +55,7 @@ jobs: # uses a compiled language #- run: | - # make bootstrap + # make all # make release - name: Perform CodeQL Analysis diff --git a/.github/workflows/deploy-server.yml b/.github/workflows/deploy-server.yml index 65704f2ff..a6f8757fe 100644 --- a/.github/workflows/deploy-server.yml +++ b/.github/workflows/deploy-server.yml @@ -43,6 +43,6 @@ jobs: context: . pull: true push: true - build-args: version=${{ github.sha }} + build-args: version=${{ github.ref_name }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/deploy-workers.yml b/.github/workflows/deploy-workers.yml index 444c17cb8..bf9d2811c 100644 --- a/.github/workflows/deploy-workers.yml +++ b/.github/workflows/deploy-workers.yml @@ -54,6 +54,6 @@ jobs: context: ./${{ matrix.module }} pull: true push: true - build-args: version=${{ steps.vars.outputs.sha_short }} + build-args: version=${{ github.ref_name }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index 53e79d7ba..142575890 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -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: diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index e8a5eade6..07b5e5e60 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -15,9 +15,10 @@ 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 with: version: latest + only-new-issues: true diff --git a/.golangci.yml b/.golangci.yml index d42a24da6..88cd15960 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,3 +1,4 @@ +# For a description for each linter, see https://golangci-lint.run/usage/linters/. linters: enable: - gosimple @@ -14,7 +15,6 @@ linters: - ineffassign - gofumpt - revive - - depguard - nakedret - unconvert - wastedassign @@ -25,7 +25,7 @@ linters: fast: false run: - go: '1.19' + go: '1.21' timeout: 10m skip-dirs: - node_modules @@ -67,13 +67,14 @@ linters-settings: - name: modifies-value-receiver gofumpt: extra-rules: false - lang-version: "1.19" + lang-version: "1.21" issues: max-issues-per-linter: 0 max-same-issues: 0 new: true - new-from-rev: HEAD + new-from-rev: dev + fix: false exclude-rules: # Exclude some linters from running on tests files. - path: _test\.go diff --git a/.idea/runConfigurations/all.xml b/.idea/runConfigurations/all.xml deleted file mode 100644 index 38b79f9b7..000000000 --- a/.idea/runConfigurations/all.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index c32a96118..1ef96930c 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ docker run --detach \ ### Install go -- Install **go >=1.18** by following the steps [here](https://go.dev/doc/install) +- Install **go >=1.21** by following the steps [here](https://go.dev/doc/install) - Preferably use [JetBrains GoLand](https://youtu.be/vetAfxQxyJE) and open this project as it simplifies this entire process - Go to File -> Settings -> Go -> Go Modules and enable go modules integration. - Run `npm i` in the `./web` directory to install the required node modules diff --git a/api/api_logger.go b/api/api_logger.go new file mode 100644 index 000000000..d7a7b552c --- /dev/null +++ b/api/api_logger.go @@ -0,0 +1,10 @@ +package api + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "api") diff --git a/api/chat.go b/api/chat.go index bc6b575ab..f66c02dba 100644 --- a/api/chat.go +++ b/api/chat.go @@ -19,7 +19,6 @@ import ( "github.com/getsentry/sentry-go" "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" ) const ( @@ -65,7 +64,7 @@ func RegisterRealtimeChatChannel() { req, err := parseChatPayload(message) if err != nil { - log.WithError(err).Warn("could not unmarshal request") + logger.Warn("could not unmarshal request", "err", err) return } @@ -89,7 +88,7 @@ func RegisterRealtimeChatChannel() { case "react_to": routes.handleReactTo(tumLiveContext, message.Payload) default: - log.WithField("type", req.Type).Warn("unknown websocket request type") + logger.Warn("unknown websocket request type", "type", req.Type) } }, }) @@ -121,7 +120,7 @@ type chatRoutes struct { func (r chatRoutes) handleSubmitPollOptionVote(ctx tools.TUMLiveContext, msg []byte) { var req submitPollOptionVote if err := json.Unmarshal(msg, &req); err != nil { - log.WithError(err).Warn("could not unmarshal submit poll answer request") + logger.Warn("could not unmarshal submit poll answer request", "err", err) return } if ctx.User == nil { @@ -129,7 +128,7 @@ func (r chatRoutes) handleSubmitPollOptionVote(ctx tools.TUMLiveContext, msg []b } if err := r.ChatDao.AddChatPollOptionVote(req.PollOptionId, ctx.User.ID); err != nil { - log.WithError(err).Warn("could not add poll option vote") + logger.Warn("could not add poll option vote", "err", err) return } @@ -144,7 +143,7 @@ func (r chatRoutes) handleSubmitPollOptionVote(ctx tools.TUMLiveContext, msg []b if voteUpdateJson, err := json.Marshal(voteUpdateMap); err == nil { broadcastStreamToAdmins(ctx.Stream.ID, voteUpdateJson) } else { - log.WithError(err).Warn("could not marshal vote update map") + logger.Warn("could not marshal vote update map", "err", err) return } } @@ -158,7 +157,7 @@ func (r chatRoutes) handleStartPoll(ctx tools.TUMLiveContext, msg []byte) { var req startPollReq if err := json.Unmarshal(msg, &req); err != nil { - log.WithError(err).Warn("could not unmarshal start poll request") + logger.Warn("could not unmarshal start poll request", "err", err) return } if ctx.User == nil || !ctx.User.IsAdminOfCourse(*ctx.Course) { @@ -166,14 +165,14 @@ func (r chatRoutes) handleStartPoll(ctx tools.TUMLiveContext, msg []byte) { } if len(req.Question) == 0 { - log.Warn("could not create poll with empty question") + logger.Warn("could not create poll with empty question") return } var pollOptions []model.PollOption for _, answer := range req.PollAnswers { if len(answer) == 0 { - log.Warn("could not create poll with empty answer") + logger.Warn("could not create poll with empty answer") return } pollOptions = append(pollOptions, model.PollOption{ @@ -244,7 +243,7 @@ func (r chatRoutes) handleResolve(ctx tools.TUMLiveContext, msg []byte) { var req wsIdReq err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal message delete request") + logger.Warn("could not unmarshal message delete request", "err", err) return } if ctx.User == nil || !ctx.User.IsAdminOfCourse(*ctx.Course) { @@ -253,7 +252,7 @@ func (r chatRoutes) handleResolve(ctx tools.TUMLiveContext, msg []byte) { err = r.ChatDao.ResolveChat(req.Id) if err != nil { - log.WithError(err).Error("could not delete chat") + logger.Error("could not delete chat", "err", err) } broadcast := gin.H{ @@ -261,7 +260,7 @@ func (r chatRoutes) handleResolve(ctx tools.TUMLiveContext, msg []byte) { } broadcastBytes, err := json.Marshal(broadcast) if err != nil { - log.WithError(err).Error("could not marshal delete message") + logger.Error("could not marshal delete message", "err", err) return } broadcastStream(ctx.Stream.ID, broadcastBytes) @@ -271,7 +270,7 @@ func (r chatRoutes) handleDelete(ctx tools.TUMLiveContext, msg []byte) { var req wsIdReq err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal message delete request") + logger.Warn("could not unmarshal message delete request", "err", err) return } if ctx.User == nil || !ctx.User.IsAdminOfCourse(*ctx.Course) { @@ -279,14 +278,14 @@ func (r chatRoutes) handleDelete(ctx tools.TUMLiveContext, msg []byte) { } err = r.ChatDao.DeleteChat(req.Id) if err != nil { - log.WithError(err).Error("could not delete chat") + logger.Error("could not delete chat", "err", err) } broadcast := gin.H{ "delete": req.Id, } broadcastBytes, err := json.Marshal(broadcast) if err != nil { - log.WithError(err).Error("could not marshal delete message") + logger.Error("could not marshal delete message", "err", err) return } broadcastStream(ctx.Stream.ID, broadcastBytes) @@ -296,7 +295,7 @@ func (r chatRoutes) handleApprove(ctx tools.TUMLiveContext, msg []byte) { var req wsIdReq err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal message approve request") + logger.Warn("could not unmarshal message approve request", "err", err) return } if ctx.User == nil || !ctx.User.IsAdminOfCourse(*ctx.Course) { @@ -305,7 +304,7 @@ func (r chatRoutes) handleApprove(ctx tools.TUMLiveContext, msg []byte) { err = r.ChatDao.ApproveChat(req.Id) if err != nil { - log.WithError(err).Error("could not approve chat") + logger.Error("could not approve chat", "err", err) return } @@ -315,7 +314,7 @@ func (r chatRoutes) handleApprove(ctx tools.TUMLiveContext, msg []byte) { */ chat, err := r.ChatDao.GetChat(req.Id, 0) if err != nil { - log.WithError(err).Error("could not get chat") + logger.Error("could not get chat", "err", err) } broadcast := gin.H{ "approve": req.Id, @@ -323,7 +322,7 @@ func (r chatRoutes) handleApprove(ctx tools.TUMLiveContext, msg []byte) { } broadcastBytes, err := json.Marshal(broadcast) if err != nil { - log.WithError(err).Error("could not marshal approve message") + logger.Error("could not marshal approve message", "err", err) return } broadcastStream(ctx.Stream.ID, broadcastBytes) @@ -333,23 +332,23 @@ func (r chatRoutes) handleReactTo(ctx tools.TUMLiveContext, msg []byte) { var req wsReactToReq err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal reactTo request") + logger.Warn("could not unmarshal reactTo request", "err", err) return } if _, isAllowed := allowedReactions[req.Reaction]; !isAllowed { - log.Warn("user tried to add illegal reaction") + logger.Warn("user tried to add illegal reaction") return } err = r.ChatDao.ToggleReaction(ctx.User.ID, req.wsIdReq.Id, ctx.User.Name, req.Reaction) if err != nil { - log.WithError(err).Error("error reacting to message") + logger.Error("error reacting to message", "err", err) return } reactions, err := r.ChatDao.GetReactions(req.Id) if err != nil { - log.WithError(err).Error("error getting num of chat reactions") + logger.Error("error getting num of chat reactions", "err", err) return } broadcast := gin.H{ @@ -358,7 +357,7 @@ func (r chatRoutes) handleReactTo(ctx tools.TUMLiveContext, msg []byte) { } broadcastBytes, err := json.Marshal(broadcast) if err != nil { - log.WithError(err).Error("Can't marshal reactions message") + logger.Error("Can't marshal reactions message", "err", err) return } broadcastStream(ctx.Stream.ID, broadcastBytes) @@ -368,7 +367,7 @@ func (r chatRoutes) handleRetract(ctx tools.TUMLiveContext, msg []byte) { var req wsIdReq err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal message retract request") + logger.Warn("could not unmarshal message retract request", "err", err) return } if ctx.User == nil || !ctx.User.IsAdminOfCourse(*ctx.Course) { @@ -377,19 +376,19 @@ func (r chatRoutes) handleRetract(ctx tools.TUMLiveContext, msg []byte) { err = r.ChatDao.RetractChat(req.Id) if err != nil { - log.WithError(err).Error("could not retract chat") + logger.Error("could not retract chat", "err", err) return } err = r.ChatDao.RemoveReactions(req.Id) if err != nil { - log.WithError(err).Error("could not remove reactions from chat") + logger.Error("could not remove reactions from chat", "err", err) return } chat, err := r.ChatDao.GetChat(req.Id, 0) if err != nil { - log.WithError(err).Error("could not get chat") + logger.Error("could not get chat", "err", err) } broadcast := gin.H{ "retract": req.Id, @@ -397,7 +396,7 @@ func (r chatRoutes) handleRetract(ctx tools.TUMLiveContext, msg []byte) { } broadcastBytes, err := json.Marshal(broadcast) if err != nil { - log.WithError(err).Error("could not marshal retract message") + logger.Error("could not marshal retract message", "err", err) return } broadcastStream(ctx.Stream.ID, broadcastBytes) @@ -406,7 +405,7 @@ func (r chatRoutes) handleRetract(ctx tools.TUMLiveContext, msg []byte) { func (r chatRoutes) handleMessage(ctx tools.TUMLiveContext, context *realtime.Context, msg []byte) { var chat chatReq if err := json.Unmarshal(msg, &chat); err != nil { - log.WithError(err).Error("error unmarshalling chat message") + logger.Error("error unmarshalling chat message", "err", err) return } if !ctx.Course.ChatEnabled && !ctx.Stream.ChatEnabled { @@ -578,7 +577,7 @@ func (r chatRoutes) getActivePoll(c *gin.Context) { if isAdminOfCourse { voteCount, err = r.ChatDao.GetPollOptionVoteCount(option.ID) if err != nil { - log.WithError(err).Warn("could not get poll option vote count") + logger.Warn("could not get poll option vote count", "err", err) } } @@ -681,7 +680,7 @@ func CollectStats(daoWrapper dao.DaoWrapper) func() { if s.LiveNow { // store stats for livestreams only s.Stats = append(s.Stats, stat) if err := daoWrapper.AddStat(stat); err != nil { - log.WithError(err).Error("Saving stat failed") + logger.Error("Saving stat failed", "err", err) } } } @@ -734,7 +733,7 @@ func afterUnsubscribe(id string, joinTime time.Time, recording bool, daoWrapper if recording && joinTime.Before(time.Now().Add(time.Minute*-5)) { err := daoWrapper.AddVodView(id) if err != nil { - log.WithError(err).Error("Can't save vod view") + logger.Error("Can't save vod view", "err", err) } } } diff --git a/api/courseimport.go b/api/courseimport.go index 77e81a55d..18db73131 100644 --- a/api/courseimport.go +++ b/api/courseimport.go @@ -6,13 +6,12 @@ import ( "errors" "fmt" campusonline "github.com/RBG-TUM/CAMPUSOnline" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/tum" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "html/template" "net/http" "strconv" @@ -90,7 +89,7 @@ func (r lectureHallRoutes) postSchedule(c *gin.Context) { for _, event := range courseReq.Events { lectureHall, err := r.LectureHallsDao.GetLectureHallByPartialName(event.RoomName) if err != nil { - log.WithError(err).Error("No room found for request") + logger.Error("No room found for request", "err", err) continue } var eventID uint @@ -122,7 +121,7 @@ func (r lectureHallRoutes) postSchedule(c *gin.Context) { mail := contact.Email user, err := tum.FindUserWithEmail(mail) if err != nil || user == nil { - log.WithError(err).Errorf("can't find user %v", mail) + logger.Error("can't find user "+mail, "err", err) continue } time.Sleep(time.Millisecond * 200) // wait a bit, otherwise ldap locks us out @@ -130,14 +129,14 @@ func (r lectureHallRoutes) postSchedule(c *gin.Context) { user.Role = model.LecturerType err = r.UsersDao.UpsertUser(user) if err != nil { - log.Error(err) + logger.Error("Could not upsert user", "err", err) } else { users = append(users, user) } } for _, user := range users { if err := r.CoursesDao.AddAdminToCourse(user.ID, course.ID); err != nil { - log.WithError(err).Error("can't add admin to course") + logger.Error("can't add admin to course", "err", err) } err := r.notifyCourseCreated(MailTmpl{ Name: user.Name, @@ -146,7 +145,7 @@ func (r lectureHallRoutes) postSchedule(c *gin.Context) { OptIn: req.OptIn, }, user.Email.String, fmt.Sprintf("Vorlesungsstreams %s | Lecture streaming %s", course.Name, course.Name)) if err != nil { - log.WithFields(log.Fields{"course": course.Name, "email": user.Email.String}).WithError(err).Error("can't send email") + logger.Error("can't send email", "course", course.Name, "email", user.Email.String, "err", err) } time.Sleep(time.Millisecond * 100) // 1/10th second delay, being nice to our mailrelay } @@ -172,7 +171,7 @@ func (r lectureHallRoutes) notifyCourseCreated(d MailTmpl, mailAddr string, subj var body bytes.Buffer err = templ.ExecuteTemplate(&body, "mail-course-registered.gotemplate", d) if err != nil { - log.Error(err) + logger.Error("Could not execute mail-course-registered.gotemplate", "err", err) } return r.EmailDao.Create(context.Background(), &model.Email{ From: tools.Cfg.Mail.Sender, @@ -219,7 +218,7 @@ func (r lectureHallRoutes) getSchedule(c *gin.Context) { //todo figure out right token campus, err := campusonline.New(tools.Cfg.Campus.Tokens[0], "") if err != nil { - log.WithError(err).Error("Can't create campus client") + logger.Error("Can't create campus client", "err", err) return } var room campusonline.ICalendar @@ -245,7 +244,7 @@ func (r lectureHallRoutes) getSchedule(c *gin.Context) { room, err = campus.GetXCalOrg(from, to, depInt) } if err != nil { - log.WithError(err).Error("can not get room schedule") + logger.Error("can not get room schedule", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get room schedule", diff --git a/api/courses.go b/api/courses.go index 7502d87f5..599f2bbaa 100644 --- a/api/courses.go +++ b/api/courses.go @@ -14,7 +14,6 @@ import ( "github.com/gin-gonic/gin" "github.com/meilisearch/meilisearch-go" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "gorm.io/gorm" "io" "net/http" @@ -161,7 +160,7 @@ func (r coursesRoutes) getLive(c *gin.Context) { if stream.LectureHallID != 0 { lh, err := r.LectureHallsDao.GetLectureHallByID(stream.LectureHallID) if err != nil { - log.WithError(err).Error(err) + logger.Error("Could not get Lecture Hall ID", "err", err) } else { lectureHall = &lh } @@ -400,7 +399,7 @@ func isUserAllowedToWatchPrivateCourse(course model.Course, user *model.User) bo } func (r coursesRoutes) createVOD(c *gin.Context) { - log.Info("createVOD") + logger.Info("createVOD") var req createVODReq err := c.BindQuery(&req) if err != nil { @@ -433,7 +432,7 @@ func (r coursesRoutes) createVOD(c *gin.Context) { } func (r coursesRoutes) uploadVODMedia(c *gin.Context) { - log.Info("uploadVODMedia") + logger.Info("uploadVODMedia") var req uploadVodMediaReq if err := c.BindQuery(&req); err != nil { @@ -541,7 +540,7 @@ func (r coursesRoutes) updateSourceSettings(c *gin.Context) { Message: fmt.Sprintf("%s:'%s'", tumLiveContext.Course.Name, tumLiveContext.Course.Slug), Type: model.AuditCourseEdit, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } course.SetCameraPresetPreference(presetSettings) @@ -557,7 +556,7 @@ func (r coursesRoutes) updateSourceSettings(c *gin.Context) { course.SetSourcePreference(sourceModeSettings) if err = r.CoursesDao.UpdateCourse(c, *course); err != nil { - log.WithError(err).Error("failed to update course") + logger.Error("failed to update course", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "failed to update course", @@ -600,7 +599,7 @@ func (r coursesRoutes) activateCourseByToken(c *gin.Context) { } err = r.AuditDao.Create(&model.Audit{User: tlctx.User, Type: model.AuditCourseCreate, Message: fmt.Sprintf("opted in by token, %s:'%s'", course.Name, course.Slug)}) if err != nil { - log.WithError(err).Error("create opt in audit failed") + logger.Error("create opt in audit failed", "err", err) } } @@ -618,7 +617,7 @@ func (r coursesRoutes) removeAdminFromCourse(c *gin.Context) { admins, err := r.CoursesDao.GetCourseAdmins(tumLiveContext.Course.ID) if err != nil { - log.WithError(err).Error("could not get course admins") + logger.Error("could not get course admins", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "could not get course admins", @@ -653,12 +652,12 @@ func (r coursesRoutes) removeAdminFromCourse(c *gin.Context) { Message: fmt.Sprintf("%s:'%s' remove: %s (%d)", tumLiveContext.Course.Name, tumLiveContext.Course.Slug, user.GetPreferredName(), user.ID), // e.g. "eidi:'Einführung in die Informatik' (2020, S)" Type: model.AuditCourseEdit, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } err = r.CoursesDao.RemoveAdminFromCourse(user.ID, tumLiveContext.Course.ID) if err != nil { - log.WithError(err).Error("could not remove admin from course") + logger.Error("could not remove admin from course", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "could not remove admin from course", @@ -700,12 +699,12 @@ func (r coursesRoutes) addAdminToCourse(c *gin.Context) { Message: fmt.Sprintf("%s:'%s' add: %s (%d)", tumLiveContext.Course.Name, tumLiveContext.Course.Slug, user.GetPreferredName(), user.ID), // e.g. "eidi:'Einführung in die Informatik' (2020, S)" Type: model.AuditCourseEdit, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } err = r.CoursesDao.AddAdminToCourse(user.ID, tumLiveContext.Course.ID) if err != nil { - log.WithError(err).Error("could not add admin to course") + logger.Error("could not add admin to course", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "could not add admin to course", @@ -717,7 +716,7 @@ func (r coursesRoutes) addAdminToCourse(c *gin.Context) { user.Role = model.LecturerType err = r.UsersDao.UpdateUser(user) if err != nil { - log.WithError(err).Error("could not update user") + logger.Error("could not update user", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "could not update user", @@ -737,7 +736,7 @@ func (r coursesRoutes) getAdmins(c *gin.Context) { tumLiveContext := c.MustGet("TUMLiveContext").(tools.TUMLiveContext) admins, err := r.CoursesDao.GetCourseAdmins(tumLiveContext.Course.ID) if err != nil { - log.WithError(err).Error("error getting course admins") + logger.Error("error getting course admins", "err", err) c.AbortWithStatus(http.StatusInternalServerError) return } @@ -820,7 +819,7 @@ func (r coursesRoutes) lectureHalls(c *gin.Context, course model.Course) { for u := range lectureHallIDs { lh, err := r.LectureHallsDao.GetLectureHallByID(u) if err != nil { - log.WithError(err).Error("Can't fetch lecture hall for stream") + logger.Error("Can't fetch lecture hall for stream", "err", err) } else { // Find if sourceMode is specified for this lecture hall lectureHallData = append(lectureHallData, lhResp{ @@ -987,7 +986,7 @@ func (r coursesRoutes) updateDescription(c *gin.Context) { if msg, err := json.Marshal(wsMsg); err == nil { broadcastStream(sID, msg) } else { - log.WithError(err).Error("couldn't marshal stream rename ws msg") + logger.Error("couldn't marshal stream rename ws msg", "err", err) } } @@ -1035,7 +1034,7 @@ func (r coursesRoutes) renameLecture(c *gin.Context) { if msg, err := json.Marshal(wsMsg); err == nil { broadcastStream(sID, msg) } else { - log.WithError(err).Error("couldn't marshal stream rename ws msg") + logger.Error("couldn't marshal stream rename ws msg", "err", err) } } @@ -1062,7 +1061,7 @@ func (r coursesRoutes) updateLectureSeries(c *gin.Context) { } if err = r.StreamsDao.UpdateLectureSeries(stream); err != nil { - log.WithError(err).Error("couldn't update lecture series") + logger.Error("couldn't update lecture series", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "couldn't update lecture series", @@ -1101,10 +1100,10 @@ func (r coursesRoutes) deleteLectureSeries(c *gin.Context) { Message: fmt.Sprintf("'%s': %s (%d and series)", ctx.Course.Name, stream.Start.Format("2006 02 Jan, 15:04"), stream.ID), Type: model.AuditStreamDelete, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } if err := r.StreamsDao.DeleteLectureSeries(stream.SeriesIdentifier); err != nil { - log.WithError(err).Error("couldn't delete lecture series") + logger.Error("couldn't delete lecture series", "err", err) c.AbortWithStatusJSON(http.StatusInternalServerError, "couldn't delete lecture series") return } @@ -1143,7 +1142,7 @@ func (r coursesRoutes) deleteLectures(c *gin.Context) { Message: fmt.Sprintf("'%s': %s (%d)", tumLiveContext.Course.Name, stream.Start.Format("2006 02 Jan, 15:04"), stream.ID), Type: model.AuditStreamDelete, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } r.StreamsDao.DeleteStream(strconv.Itoa(int(stream.ID))) } @@ -1154,7 +1153,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { var req createLectureRequest if err := c.ShouldBind(&req); err != nil { - log.WithError(err).Error("invalid form") + logger.Error("invalid form", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "invalid form", @@ -1165,7 +1164,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { // Forbid setting lectureHall for vod or premiere if (req.Premiere || req.Vodup) && req.LectureHallId != "0" { - log.Error("cannot set lectureHallId on 'Premiere' or 'Vodup' Lecture.") + logger.Error("cannot set lectureHallId on 'Premiere' or 'Vodup' Lecture.") _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "cannot set lectureHallId on 'Premiere' or 'Vodup' Lecture.", @@ -1176,7 +1175,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { // try parse lectureHallId lectureHallId, err := strconv.ParseInt(req.LectureHallId, 10, 32) if err != nil { - log.WithError(err).Error("invalid LectureHallID format") + logger.Error("invalid LectureHallID format", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "invalid LectureHallId format", @@ -1197,7 +1196,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { if req.Premiere || req.Vodup { err = os.MkdirAll(premiereFolder, os.ModePerm) if err != nil { - log.WithError(err).Error("can not create folder for premiere") + logger.Error("can not create folder for premiere", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not create folder for premiere", @@ -1210,7 +1209,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { if req.Vodup { err = tools.UploadLRZ(fmt.Sprintf("%s/%s", premiereFolder, premiereFileName)) if err != nil { - log.WithError(err).Error("can not upload file for premiere") + logger.Error("can not upload file for premiere", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not upload file for premiere", @@ -1269,7 +1268,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { Message: fmt.Sprintf("Stream for '%s' Created. Time: %s", tumLiveContext.Course.Name, lecture.Start.Format("2006 02 Jan, 15:04")), Type: model.AuditStreamCreate, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit", "err", err) } tumLiveContext.Course.Streams = append(tumLiveContext.Course.Streams, lecture) @@ -1277,7 +1276,7 @@ func (r coursesRoutes) createLecture(c *gin.Context) { err = r.CoursesDao.UpdateCourse(context.Background(), *tumLiveContext.Course) if err != nil { - log.WithError(err).Warn("can not update course") + logger.Warn("can not update course", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not update course", @@ -1401,7 +1400,7 @@ func (r coursesRoutes) createCourse(c *gin.Context) { Message: fmt.Sprintf("%s:'%s' (%d, %s)", course.Slug, course.Name, course.Year, course.TeachingTerm), // e.g. "eidi:'Einführung in die Informatik' (2020, S)" Type: model.AuditCourseCreate, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } err = r.CoursesDao.CreateCourse(context.Background(), &course, true) @@ -1457,7 +1456,7 @@ func (r coursesRoutes) deleteCourseByToken(c *gin.Context) { Message: fmt.Sprintf("'%s' (%d, %s)[%d]. Token: %s", course.Name, course.Year, course.TeachingTerm, course.ID, token), Type: model.AuditCourseDelete, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit:", "err", err) } r.CoursesDao.DeleteCourse(course) @@ -1467,17 +1466,14 @@ func (r coursesRoutes) deleteCourseByToken(c *gin.Context) { func (r coursesRoutes) deleteCourse(c *gin.Context) { tumLiveContext := c.MustGet("TUMLiveContext").(tools.TUMLiveContext) - log.WithFields(log.Fields{ - "user": tumLiveContext.User.ID, - "course": tumLiveContext.Course.ID, - }).Info("Delete Course Called") + logger.Info("Delete Course Called", "user", tumLiveContext.User.ID, "course", tumLiveContext.Course.ID) if err := r.AuditDao.Create(&model.Audit{ User: tumLiveContext.User, Message: fmt.Sprintf("'%s' (%d, %s)[%d]", tumLiveContext.Course.Name, tumLiveContext.Course.Year, tumLiveContext.Course.TeachingTerm, tumLiveContext.Course.ID), Type: model.AuditCourseDelete, }); err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit", "err", err) } r.CoursesDao.DeleteCourse(*tumLiveContext.Course) @@ -1515,7 +1511,7 @@ func (r coursesRoutes) courseInfo(c *gin.Context) { } } if err != nil { // course not found - log.WithError(err).Warn("Error getting course information") + logger.Warn("Error getting course information", "err", err) c.AbortWithStatus(http.StatusNotFound) return } @@ -1556,7 +1552,7 @@ func (r coursesRoutes) copyCourse(c *gin.Context) { admins, err := r.DaoWrapper.CoursesDao.GetCourseAdmins(course.ID) if err != nil { - log.WithError(err).Error("Error getting course admins") + logger.Error("Error getting course admins", "err", err) admins = []model.User{} } course.Model = gorm.Model{} @@ -1579,7 +1575,7 @@ func (r coursesRoutes) copyCourse(c *gin.Context) { err = r.CoursesDao.CreateCourse(c, course, true) if err != nil { - log.WithError(err).Error("Can't create course") + logger.Error("Can't create course", "err", err) _ = c.Error(tools.RequestError{Status: http.StatusInternalServerError, CustomMessage: "Can't create course", Err: err}) return } @@ -1589,14 +1585,14 @@ func (r coursesRoutes) copyCourse(c *gin.Context) { stream.Model = gorm.Model{} err := r.StreamsDao.CreateStream(&stream) if err != nil { - log.WithError(err).Error("Can't create stream") + logger.Error("Can't create stream", "err", err) numErrors++ } } for _, admin := range admins { err := r.CoursesDao.AddAdminToCourse(admin.ID, course.ID) if err != nil { - log.WithError(err).Error("Can't add admin to course") + logger.Error("Can't add admin to course", "err", err) numErrors++ } } diff --git a/api/download.go b/api/download.go index 47f2ddf51..76fc97201 100644 --- a/api/download.go +++ b/api/download.go @@ -3,12 +3,11 @@ package api import ( "errors" "fmt" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "net/http" "os" ) @@ -119,7 +118,7 @@ func sendDownloadFile(c *gin.Context, file model.File, tumLiveContext tools.TUML if tumLiveContext.User != nil { uid = tumLiveContext.User.ID } - log.Info(fmt.Sprintf("Download request, user: %d, file: %d[%s]", uid, file.ID, file.Path)) + logger.Info(fmt.Sprintf("Download request, user: %d, file: %d[%s]", uid, file.ID, file.Path)) f, err := os.Open(file.Path) if err != nil { _ = c.Error(tools.RequestError{ diff --git a/api/download_ics.go b/api/download_ics.go index 3217eb5f8..3660f658c 100644 --- a/api/download_ics.go +++ b/api/download_ics.go @@ -1,11 +1,10 @@ package api import ( - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "html/template" "net/http" "strconv" @@ -15,7 +14,7 @@ import ( func configGinDownloadICSRouter(router *gin.Engine, daoWrapper dao.DaoWrapper) { templates, err := template.ParseFS(staticFS, "template/*.gotemplate") if err != nil { - log.WithError(err).Fatal("could not parse templates") + logger.Error("could not parse templates", "err", err) return } routes := downloadICSRoutes{daoWrapper, templates} diff --git a/api/lecture_halls.go b/api/lecture_halls.go index 725669ed3..7c2f40da0 100644 --- a/api/lecture_halls.go +++ b/api/lecture_halls.go @@ -4,12 +4,11 @@ import ( "embed" "errors" "fmt" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "net/http" "strconv" "strings" @@ -91,7 +90,7 @@ func (r lectureHallRoutes) updateLectureHall(c *gin.Context) { lectureHall.PwrCtrlIp = req.PwrCtrlIp err = r.LectureHallsDao.SaveLectureHall(lectureHall) if err != nil { - log.WithError(err).Error("error while updating lecture hall") + logger.Error("error while updating lecture hall", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "error while updating lecture hall", @@ -126,7 +125,7 @@ func (r lectureHallRoutes) updateLectureHallsDefaultPreset(c *gin.Context) { preset.IsDefault = true err = r.LectureHallsDao.UnsetDefaults(c.Param("id")) if err != nil { - log.WithError(err).Error("error unsetting default presets") + logger.Error("error unsetting default presets", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "error unsetting default presets", @@ -136,7 +135,7 @@ func (r lectureHallRoutes) updateLectureHallsDefaultPreset(c *gin.Context) { } err = r.LectureHallsDao.SavePreset(preset) if err != nil { - log.WithError(err).Error("error saving preset as default") + logger.Error("error saving preset as default", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "error saving preset as default", @@ -244,7 +243,7 @@ func (r lectureHallRoutes) lectureHallIcal(c *gin.Context) { c.Header("content-type", "text/calendar") err = templ.ExecuteTemplate(c.Writer, "ical.gotemplate", icalData) if err != nil { - log.Printf("%v", err) + logger.Error("Error executing template ical.gotemplate", "err", err) } } @@ -310,7 +309,7 @@ func (r lectureHallRoutes) setLectureHall(c *gin.Context) { streams, err := r.StreamsDao.GetStreamsByIds(req.StreamIDs) if err != nil || len(streams) != len(req.StreamIDs) { - log.WithError(err).Error("can not get all streams to update lecture hall") + logger.Error("can not get all streams to update lecture hall", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get all streams to update lecture hall", @@ -322,7 +321,7 @@ func (r lectureHallRoutes) setLectureHall(c *gin.Context) { if req.LectureHallID == 0 { err = r.StreamsDao.UnsetLectureHall(req.StreamIDs) if err != nil { - log.WithError(err).Error("can not update lecture hall for streams") + logger.Error("can not update lecture hall for streams", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not update lecture hall for streams", @@ -343,7 +342,7 @@ func (r lectureHallRoutes) setLectureHall(c *gin.Context) { } err = r.StreamsDao.SetLectureHall(req.StreamIDs, req.LectureHallID) if err != nil { - log.WithError(err).Error("can not update lecture hall") + logger.Error("can not update lecture hall", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not update lecture hall", diff --git a/api/live_update.go b/api/live_update.go index 443126c3c..d728d0750 100644 --- a/api/live_update.go +++ b/api/live_update.go @@ -4,14 +4,13 @@ import ( "encoding/json" "errors" "github.com/RBG-TUM/commons" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/realtime" "github.com/TUM-Dev/gocast/tools/tum" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "sync" ) @@ -85,13 +84,13 @@ func liveUpdateOnSubscribe(psc *realtime.Context) { if tumLiveContext.User != nil { userId = tumLiveContext.User.ID if userCourses, err = daoWrapper.(dao.DaoWrapper).CoursesDao.GetPublicAndLoggedInCourses(year, term); err != nil { - log.WithError(err).Error("could not fetch public and logged in courses") + logger.Error("could not fetch public and logged in courses", "err", err) return } userCourses = commons.Unique(userCourses, func(c model.Course) uint { return c.ID }) } else { if userCourses, err = daoWrapper.(dao.DaoWrapper).CoursesDao.GetPublicCourses(year, term); err != nil { - log.WithError(err).Error("could not fetch public courses") + logger.Error("could not fetch public courses", "err", err) return } } diff --git a/api/maintenance.go b/api/maintenance.go index 0a321e510..6f885fc33 100644 --- a/api/maintenance.go +++ b/api/maintenance.go @@ -1,13 +1,14 @@ package api import ( - "github.com/gin-gonic/gin" + "fmt" + "net/http" + "strconv" + "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" - "net/http" - "strconv" + "github.com/gin-gonic/gin" ) func configMaintenanceRouter(router *gin.Engine, daoWrapper dao.DaoWrapper) { @@ -50,11 +51,11 @@ func (r *maintenanceRoutes) generateThumbnails(c *gin.Context) { }) return } - log.Info("generating ", noFiles, " thumbs") + logger.Info("generating " + strconv.FormatInt(noFiles, 10) + " thumbs") go func() { courses, err := r.GetAllCourses() if err != nil { - log.WithError(err).Error("Can't get courses") + logger.Error("Can't get courses", "err", err) } processed := 0 r.thumbGenRunning = true @@ -72,14 +73,14 @@ func (r *maintenanceRoutes) generateThumbnails(c *gin.Context) { // Request thumbnail for VoD. err := RegenerateThumbs(dao.NewDaoWrapper(), file, &stream, &course) if err != nil { - log.WithError(err).Errorf( + logger.Error(fmt.Sprintf( "Can't regenerate thumbnail for stream %d with file %s", stream.ID, file.Path, - ) + )) continue } - log.Info("Processed thumbnail", processed, "of", noFiles) + logger.Info("Processed thumbnail" + string(rune(processed)) + "of" + strconv.FormatInt(noFiles, 10)) processed++ r.thumbGenProgress = float32(processed) / float32(noFiles) } @@ -110,7 +111,7 @@ func (r *maintenanceRoutes) runCronJob(c *gin.Context) { return } jobName := c.Request.FormValue("job") - log.Info("request to run ", jobName) + logger.Info("request to run " + jobName) tools.Cron.RunJob(jobName) } diff --git a/api/notifications.go b/api/notifications.go index 2d51c5802..aa11b9265 100644 --- a/api/notifications.go +++ b/api/notifications.go @@ -1,11 +1,10 @@ package api import ( - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "net/http" "strconv" ) @@ -81,7 +80,7 @@ func (r notificationRoutes) createNotification(c *gin.Context) { } notification.Body = notification.SanitizedBody // reverse json binding if err := r.NotificationsDao.AddNotification(¬ification); err != nil { - log.Error(err) + logger.Error("Error adding notification", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not add notification", @@ -104,7 +103,7 @@ func (r notificationRoutes) deleteNotification(c *gin.Context) { } err = r.NotificationsDao.DeleteNotification(uint(id)) if err != nil { - log.WithError(err).Error("error deleting notification") + logger.Error("error deleting notification", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "error deleting notification", diff --git a/api/progress.go b/api/progress.go index 5af7b4986..bcf50ab73 100644 --- a/api/progress.go +++ b/api/progress.go @@ -12,7 +12,6 @@ import ( "time" "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" ) var progressBuff *progressBuffer @@ -57,7 +56,7 @@ func (b *progressBuffer) run() { time.Sleep(b.interval) err := b.flush() if err != nil { - log.WithError(err).Error("Error flushing progress buffer") + logger.Error("Error flushing progress buffer", "err", err) } } } @@ -91,7 +90,7 @@ func (r progressRoutes) saveProgress(c *gin.Context) { err := c.BindJSON(&request) if err != nil { - log.WithError(err).Warn("Could not bind JSON.") + logger.Warn("Could not bind JSON.", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", @@ -133,7 +132,7 @@ func (r progressRoutes) markWatched(c *gin.Context) { var request watchedRequest err := c.BindJSON(&request) if err != nil { - log.WithError(err).Error("Could not bind JSON.") + logger.Error("Could not bind JSON.", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", @@ -164,7 +163,7 @@ func (r progressRoutes) markWatched(c *gin.Context) { } err = r.ProgressDao.SaveWatchedState(&prog) if err != nil { - log.WithError(err).Error("can not mark VoD as watched.") + logger.Error("can not mark VoD as watched.", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not mark VoD as watched.", diff --git a/api/realtime.go b/api/realtime.go index 0d8f5779e..302248660 100644 --- a/api/realtime.go +++ b/api/realtime.go @@ -1,11 +1,10 @@ package api import ( - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/tools/realtime" "github.com/TUM-Dev/gocast/tools/realtime/connector" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" ) type realtimeRoutes struct { @@ -25,6 +24,6 @@ func (r realtimeRoutes) handleRealtimeConnect(c *gin.Context) { properties["dao"] = r.DaoWrapper if err := RealtimeInstance.HandleRequest(c.Writer, c.Request, properties); err != nil { - log.WithError(err).Warn("Something went wrong while handling Realtime-Socket request") + logger.Warn("Something went wrong while handling Realtime-Socket request", "err", err) } } diff --git a/api/seek_stats.go b/api/seek_stats.go index 90e8b0f3f..f2e2a5510 100644 --- a/api/seek_stats.go +++ b/api/seek_stats.go @@ -1,9 +1,8 @@ package api import ( - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "net/http" ) @@ -34,7 +33,7 @@ func (r seekStatsRoutes) reportSeek(c *gin.Context) { } if err := r.VideoSeekDao.Add(c.Param("streamID"), req.Position); err != nil { - log.WithError(err).Error("Could not add seek hit") + logger.Error("Could not add seek hit", "err", err) c.AbortWithStatus(http.StatusInternalServerError) return } @@ -50,7 +49,7 @@ func (r seekStatsRoutes) getSeek(c *gin.Context) { chunks, err := r.VideoSeekDao.Get(c.Param("streamID")) if err != nil { - log.WithError(err).Error("Could not get seek hits") + logger.Error("Could not get seek hits", "err", err) c.AbortWithStatus(http.StatusInternalServerError) return } diff --git a/api/server-notifications.go b/api/server-notifications.go index 17bf6e97e..e7d8625be 100644 --- a/api/server-notifications.go +++ b/api/server-notifications.go @@ -1,13 +1,14 @@ package api import ( - "github.com/gin-gonic/gin" + "fmt" + "net/http" + "time" + "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - "log" - "net/http" - "time" + "github.com/gin-gonic/gin" ) func configServerNotificationsRoutes(engine *gin.Engine, daoWrapper dao.DaoWrapper) { @@ -25,7 +26,7 @@ type serverNotificationRoutes struct { func (r serverNotificationRoutes) updateServerNotification(c *gin.Context) { var req notificationReq if err := c.ShouldBind(&req); err != nil { - log.Printf("%v", err) + logger.Debug(fmt.Sprintf("%v", err)) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", @@ -54,7 +55,7 @@ func (r serverNotificationRoutes) updateServerNotification(c *gin.Context) { func (r serverNotificationRoutes) createServerNotification(c *gin.Context) { var req notificationReq if err := c.ShouldBind(&req); err != nil { - log.Printf("%v", err) + logger.Debug(fmt.Sprintf("%v", err)) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", diff --git a/api/statistics.go b/api/statistics.go index ae3373d58..af063ab5e 100644 --- a/api/statistics.go +++ b/api/statistics.go @@ -2,11 +2,10 @@ package api import ( "encoding/json" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "net/http" "strconv" ) @@ -52,7 +51,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "day": res, err := r.StatisticsDao.GetCourseStatsWeekdays(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsWeekdays failed") + logger.Warn("GetCourseStatsWeekdays failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get course stats weekdays", @@ -71,7 +70,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "hour": res, err := r.StatisticsDao.GetCourseStatsHourly(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsHourly failed") + logger.Warn("GetCourseStatsHourly failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get course stats hourly", @@ -90,7 +89,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "activity-live": resLive, err := r.StatisticsDao.GetStudentActivityCourseStats(cid, true) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsLive failed") + logger.Warn("GetCourseStatsLive failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get student activity course stats", @@ -112,7 +111,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "activity-vod": resVod, err := r.StatisticsDao.GetStudentActivityCourseStats(cid, false) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsVod failed") + logger.Warn("GetCourseStatsVod failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get student activity course stats", @@ -133,7 +132,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "numStudents": res, err := r.StatisticsDao.GetCourseNumStudents(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumStudents failed") + logger.Warn("GetCourseNumStudents failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get course num students", @@ -146,7 +145,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "vodViews": res, err := r.StatisticsDao.GetCourseNumVodViews(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumVodViews failed") + logger.Warn("GetCourseNumVodViews failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not getcourse num vod views", @@ -159,7 +158,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { case "liveViews": res, err := r.StatisticsDao.GetCourseNumLiveViews(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumLiveViews failed") + logger.Warn("GetCourseNumLiveViews failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get course num live views", @@ -173,7 +172,7 @@ func (r coursesRoutes) getStats(c *gin.Context) { { res, err := r.StatisticsDao.GetCourseNumVodViewsPerDay(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumLiveViews failed") + logger.Warn("GetCourseNumLiveViews failed", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get course num vod views per day", @@ -231,7 +230,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { } if req.Format != "json" && req.Format != "csv" { - log.WithField("courseId", cid).Warn("exportStats failed, invalid format") + logger.Warn("exportStats failed, invalid format", "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "exportStats failed, invalid format", @@ -247,7 +246,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { case "day": res, err := r.StatisticsDao.GetCourseStatsWeekdays(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsWeekdays failed") + logger.Warn("GetCourseStatsWeekdays failed", "err", err, "courseId", cid) } result = result.AddDataEntry(&tools.ExportDataEntry{ Name: interval, @@ -259,7 +258,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { case "hour": res, err := r.StatisticsDao.GetCourseStatsHourly(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseStatsHourly failed") + logger.Warn("GetCourseStatsHourly failed", "err", err, "courseId", cid) } result = result.AddDataEntry(&tools.ExportDataEntry{ Name: interval, @@ -271,7 +270,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { case "activity-live": resLive, err := r.StatisticsDao.GetStudentActivityCourseStats(cid, true) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetStudentActivityCourseStats failed") + logger.Warn("GetStudentActivityCourseStats failed", "err", err, "courseId", cid) } result = result.AddDataEntry(&tools.ExportDataEntry{ Name: interval, @@ -283,7 +282,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { case "activity-vod": resVod, err := r.StatisticsDao.GetStudentActivityCourseStats(cid, false) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetStudentActivityCourseStats failed") + logger.Warn("GetStudentActivityCourseStats failed", "err", err, "courseId", cid) } result = result.AddDataEntry(&tools.ExportDataEntry{ Name: interval, @@ -295,7 +294,7 @@ func (r coursesRoutes) exportStats(c *gin.Context) { case "allDays": res, err := r.StatisticsDao.GetCourseNumVodViewsPerDay(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumVodViewsPerDay failed") + logger.Warn("GetCourseNumVodViewsPerDay failed", "err", err, "courseId", cid) } result = result.AddDataEntry(&tools.ExportDataEntry{ Name: interval, @@ -309,21 +308,21 @@ func (r coursesRoutes) exportStats(c *gin.Context) { numStudents, err := r.StatisticsDao.GetCourseNumStudents(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumStudents failed") + logger.Warn("GetCourseNumStudents failed", "err", err, "courseId", cid) } else { quickStats = append(quickStats, dao.Stat{X: "Enrolled Students", Y: int(numStudents)}) } vodViews, err := r.StatisticsDao.GetCourseNumVodViews(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumVodViews failed") + logger.Warn("GetCourseNumVodViews failed", "err", err, "courseId", cid) } else { quickStats = append(quickStats, dao.Stat{X: "Vod Views", Y: int(vodViews)}) } liveViews, err := r.StatisticsDao.GetCourseNumLiveViews(cid) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("GetCourseNumLiveViews failed") + logger.Warn("GetCourseNumLiveViews failed", "err", err, "courseId", cid) } else { quickStats = append(quickStats, dao.Stat{X: "Live Views", Y: int(liveViews)}) } @@ -335,14 +334,14 @@ func (r coursesRoutes) exportStats(c *gin.Context) { }) default: - log.WithField("courseId", cid).Warn("Invalid export interval") + logger.Warn("Invalid export interval", "courseId", cid) } } if req.Format == "json" { jsonResult, err := json.Marshal(result.ExportJson()) if err != nil { - log.WithError(err).WithField("courseId", cid).Warn("json.Marshal failed for stats export") + logger.Warn("json.Marshal failed for stats export", "err", err, "courseId", cid) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "json.Marshal failed for stats export", @@ -399,7 +398,7 @@ func newChartJsOptions() chartJsOptions { } } -//chartJsDataset is a single dataset ready to be used in a Chart.js chart +// chartJsDataset is a single dataset ready to be used in a Chart.js chart type chartJsDataset struct { Label string `json:"label"` Fill bool `json:"fill"` @@ -409,7 +408,7 @@ type chartJsDataset struct { Options chartJsOptions `json:"options"` } -//New creates a chartJsDataset with some defaults +// New creates a chartJsDataset with some defaults func newChartJsDataset() chartJsDataset { return chartJsDataset{ Fill: false, diff --git a/api/stream.go b/api/stream.go index b50174cad..104d5c38f 100644 --- a/api/stream.go +++ b/api/stream.go @@ -12,15 +12,14 @@ import ( "strings" "time" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/bot" "github.com/TUM-Dev/gocast/voice-service/pb" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "gorm.io/gorm" ) @@ -209,7 +208,7 @@ func (r streamRoutes) liveStreams(c *gin.Context) { var res []liveStreamDto streams, err := r.StreamsDao.GetCurrentLive(c) if err != nil { - log.Error(err) + logger.Error("Error getting current live", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get current live streams", @@ -220,13 +219,13 @@ func (r streamRoutes) liveStreams(c *gin.Context) { for _, s := range streams { course, err := r.CoursesDao.GetCourseById(c, s.CourseID) if err != nil { - log.Error(err) + logger.Error("Error fetching course", "err", err) } lectureHall := "Selfstream" if s.LectureHallID != 0 { l, err := r.LectureHallsDao.GetLectureHallByID(s.LectureHallID) if err != nil { - log.Error(err) + logger.Error("Error fetching lecture hall", "err", err) } else { lectureHall = l.Name } @@ -247,7 +246,7 @@ func (r streamRoutes) liveStreams(c *gin.Context) { func (r streamRoutes) endStream(c *gin.Context) { tumLiveContext := c.MustGet("TUMLiveContext").(tools.TUMLiveContext) discardVoD := c.Request.URL.Query().Get("discard") == "true" - log.Info(discardVoD) + logger.Info("End stream: " + strconv.FormatBool(discardVoD)) NotifyWorkersToStopStream(*tumLiveContext.Stream, discardVoD, r.DaoWrapper) } @@ -388,7 +387,7 @@ func (r streamRoutes) getVideoSections(c *gin.Context) { tumLiveContext := c.MustGet("TUMLiveContext").(tools.TUMLiveContext) sections, err := r.VideoSectionDao.GetByStreamId(tumLiveContext.Stream.ID) if err != nil { - log.WithError(err).Error("Can't get video sections") + logger.Error("Can't get video sections", "err", err) } c.JSON(http.StatusOK, sections) @@ -406,17 +405,17 @@ func (r streamRoutes) RegenerateThumbs(c *gin.Context) { // The thumbnails are generated automatically by the worker which then notifies the backend. err := RegenerateThumbs(r.DaoWrapper, file, stream, course) if err != nil { - log.WithError(err).Errorf("Can't regenerate thumbnail for stream %d with file %s", stream.ID, file.Path) + logger.Error(fmt.Sprintf("Can't regenerate thumbnail for stream %d with file %s", stream.ID, file.Path)) continue } sections, err := r.DaoWrapper.VideoSectionDao.GetByStreamId(stream.ID) if err != nil { - log.WithError(err).Errorf("Can't get video sections for stream %d", stream.ID) + logger.Error(fmt.Sprintf("Can't get video sections for stream %d", stream.ID)) continue } err = tools.SetSignedPlaylists(stream, nil, false) if err != nil { - log.WithError(err).Errorf("Can't set signed playlists for stream %d", stream.ID) + logger.Error(fmt.Sprintf("Can't set signed playlists for stream %d", stream.ID)) continue } // Completely redo the video section image generation. This also updates the database, if the naming scheme has changed. @@ -430,7 +429,7 @@ func (r streamRoutes) RegenerateThumbs(c *gin.Context) { } err := GenerateVideoSectionImages(r.DaoWrapper, ¶meters) if err != nil { - log.WithError(err).Error("failed to generate video section images") + logger.Error("failed to generate video section images", "err", err) } }() } @@ -442,7 +441,7 @@ func (r streamRoutes) createVideoSectionBatch(c *gin.Context) { stream := context.Stream var sections []model.VideoSection if err := c.BindJSON(§ions); err != nil { - log.WithError(err).Error("failed to bind video section JSON") + logger.Error("failed to bind video section JSON", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", @@ -453,7 +452,7 @@ func (r streamRoutes) createVideoSectionBatch(c *gin.Context) { err := r.VideoSectionDao.Create(sections) if err != nil { - log.WithError(err).Error("failed to create video sections") + logger.Error("failed to create video sections", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "failed to create video sections", @@ -464,7 +463,7 @@ func (r streamRoutes) createVideoSectionBatch(c *gin.Context) { sections, err = r.VideoSectionDao.GetByStreamId(context.Stream.ID) if err != nil { - log.WithError(err).Error("failed to get video sections") + logger.Error("failed to get video sections", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "failed to get video sections", @@ -475,7 +474,7 @@ func (r streamRoutes) createVideoSectionBatch(c *gin.Context) { err = tools.SetSignedPlaylists(stream, nil, false) if err != nil { - log.WithError(err).Error("failed to set signed playlists") + logger.Error("failed to set signed playlists", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "failed to set signed playlists", @@ -493,9 +492,11 @@ func (r streamRoutes) createVideoSectionBatch(c *gin.Context) { } err := GenerateVideoSectionImages(r.DaoWrapper, ¶meters) if err != nil { - log.WithError(err).Error("failed to generate video section images") + logger.Error("failed to generate video section images", "err", err) } }() + + c.JSON(http.StatusOK, sections) } type UpdateVideoSectionRequest struct { @@ -509,7 +510,7 @@ func (r streamRoutes) updateVideoSection(c *gin.Context) { idAsString := c.Param("id") id, err := strconv.Atoi(idAsString) if err != nil { - log.WithError(err).Error("can not parse video-section id in request url") + logger.Error("can not parse video-section id in request url", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not parse video-section id in request url", @@ -521,7 +522,7 @@ func (r streamRoutes) updateVideoSection(c *gin.Context) { var update UpdateVideoSectionRequest err = c.BindJSON(&update) if err != nil { - log.WithError(err).Error("failed to bind video section JSON") + logger.Error("failed to bind video section JSON", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not bind body", @@ -537,7 +538,7 @@ func (r streamRoutes) updateVideoSection(c *gin.Context) { StartMinutes: update.StartMinutes, StartSeconds: update.StartSeconds}) if err != nil { - log.WithError(err).Error("failed to update video section") + logger.Error("failed to update video section", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not update video section", @@ -551,7 +552,7 @@ func (r streamRoutes) deleteVideoSection(c *gin.Context) { idAsString := c.Param("id") id, err := strconv.Atoi(idAsString) if err != nil { - log.WithError(err).Error("can not parse video-section id in request url") + logger.Error("can not parse video-section id in request url", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "can not parse video-section id in request url", @@ -562,7 +563,7 @@ func (r streamRoutes) deleteVideoSection(c *gin.Context) { old, err := r.VideoSectionDao.Get(uint(id)) if err != nil { - log.WithError(err).Error("invalid video-section id") + logger.Error("invalid video-section id", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusBadRequest, CustomMessage: "invalid video-section id", @@ -573,7 +574,7 @@ func (r streamRoutes) deleteVideoSection(c *gin.Context) { err = r.VideoSectionDao.Delete(uint(id)) if err != nil { - log.WithError(err).Error("can not delete video-section") + logger.Error("can not delete video-section", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not delete video-section", @@ -584,7 +585,7 @@ func (r streamRoutes) deleteVideoSection(c *gin.Context) { file, err := r.FileDao.GetFileById(fmt.Sprintf("%d", old.FileID)) if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - log.WithError(err).Error("can not get video section thumbnail file") + logger.Error("can not get video section thumbnail file", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not get video section thumbnail file", @@ -595,7 +596,7 @@ func (r streamRoutes) deleteVideoSection(c *gin.Context) { go func() { err := DeleteVideoSectionImage(r.DaoWrapper.WorkerDao, file.Path) if err != nil { - log.WithError(err).Error("failed to generate video section images") + logger.Error("failed to generate video section images", "err", err) } }() } @@ -652,7 +653,7 @@ func (r streamRoutes) newAttachment(c *gin.Context) { } if err = c.SaveUploadedFile(file, path); err != nil { - log.WithError(err).Error("could not save file with path: " + path) + logger.Error("could not save file with path: "+path, "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "could not save file with path: " + path, @@ -704,7 +705,7 @@ func (r streamRoutes) deleteAttachment(c *gin.Context) { if !toDelete.IsURL() { err = os.Remove(toDelete.Path) if err != nil { - log.WithError(err).Error("can not delete file with path: " + toDelete.Path) + logger.Error("can not delete file with path: "+toDelete.Path, "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not delete file with path: " + toDelete.Path, @@ -715,7 +716,7 @@ func (r streamRoutes) deleteAttachment(c *gin.Context) { } err = r.FileDao.DeleteFile(toDelete.ID) if err != nil { - log.WithError(err).Error("can not delete file from database") + logger.Error("can not delete file from database", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not delete file from database", @@ -823,7 +824,7 @@ func (r streamRoutes) updateStreamVisibility(c *gin.Context) { Type: model.AuditStreamEdit, }) if err != nil { - log.Error("Create Audit:", err) + logger.Error("Create Audit", "err", err) } err = r.DaoWrapper.StreamsDao.ToggleVisibility(ctx.Stream.ID, req.Private) diff --git a/api/token.go b/api/token.go index 41fc9a368..420ae01a2 100644 --- a/api/token.go +++ b/api/token.go @@ -2,12 +2,11 @@ package api import ( "database/sql" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" + "github.com/gin-gonic/gin" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "net/http" "time" ) @@ -28,7 +27,7 @@ func (r tokenRoutes) deleteToken(c *gin.Context) { id := c.Param("id") err := r.TokenDao.DeleteToken(id) if err != nil { - log.WithError(err).Error("can not delete token") + logger.Error("can not delete token", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not delete token", @@ -78,7 +77,7 @@ func (r tokenRoutes) createToken(c *gin.Context) { } err = r.TokenDao.AddToken(token) if err != nil { - log.WithError(err).Error("can not create token") + logger.Error("can not create token", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not create token", diff --git a/api/users.go b/api/users.go index e96921e63..aed805dd8 100644 --- a/api/users.go +++ b/api/users.go @@ -11,12 +11,11 @@ import ( "strings" "time" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "gorm.io/gorm" ) @@ -26,6 +25,7 @@ func configGinUsersRouter(router *gin.Engine, daoWrapper dao.DaoWrapper) { router.POST("/api/users/settings/name", routes.updatePreferredName) router.POST("/api/users/settings/greeting", routes.updatePreferredGreeting) router.POST("/api/users/settings/playbackSpeeds", routes.updatePlaybackSpeeds) + router.POST("/api/users/settings/customSpeeds", routes.updateCustomSpeeds) router.POST("/api/users/resetPassword", routes.resetPassword) @@ -113,7 +113,7 @@ func (r usersRoutes) updateUser(c *gin.Context) { user.Role = req.Role err = r.UsersDao.UpdateUser(user) if err != nil { - log.WithError(err).Error("can not update user") + logger.Error("can not update user", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not update user", @@ -304,7 +304,7 @@ func (r usersRoutes) addSingleUserToCourse(name string, email string, course mod Courses: []model.Course{course}, } if err = r.UsersDao.CreateUser(context.Background(), &createdUser); err != nil { - log.Printf("%v", err) + logger.Error("Error creating User", "err", err) } else { go r.forgotPassword(email) } @@ -313,7 +313,7 @@ func (r usersRoutes) addSingleUserToCourse(name string, email string, course mod foundUser.Courses = append(foundUser.Courses, course) err := r.UsersDao.UpdateUser(foundUser) if err != nil { - log.WithError(err).Error("Can't update user") + logger.Error("Can't update user", "err", err) return } err = r.EmailDao.Create(context.Background(), &model.Email{ @@ -325,7 +325,7 @@ func (r usersRoutes) addSingleUserToCourse(name string, email string, course mod course.Name), }) if err != nil { - log.Printf("%v", err) + logger.Error("Some error", "err", err) } } } @@ -372,7 +372,7 @@ func (r usersRoutes) pinCourse(pin bool) gin.HandlerFunc { } err := c.BindJSON(&request) if err != nil { - log.WithError(err).Error("Could not bind JSON.") + logger.Error("Could not bind JSON.", "err", err) c.AbortWithStatus(http.StatusBadRequest) return } @@ -397,7 +397,7 @@ func (r usersRoutes) pinCourse(pin bool) gin.HandlerFunc { // Update user in database err = r.UsersDao.PinCourse(*tumLiveContext.User, course, pin) if err != nil { - log.WithError(err).Error("Can't update user") + logger.Error("Can't update user", "err", err) return } } @@ -508,12 +508,12 @@ func (r usersRoutes) createUserHelper(request createUserRequest, userType uint) func (r usersRoutes) forgotPassword(email string) { u, err := r.UsersDao.GetUserByEmail(context.Background(), email) if err != nil { - log.Println("couldn't get user by email") + logger.Error("couldn't get user by email") return } registerLink, err := r.UsersDao.CreateRegisterLink(context.Background(), u) if err != nil { - log.Println("couldn't create register link") + logger.Error("couldn't create register link") return } body := fmt.Sprintf("Hello!\n"+ @@ -527,7 +527,7 @@ func (r usersRoutes) forgotPassword(email string) { Body: body, }) if err != nil { - log.Println("couldn't send password mail") + logger.Error("couldn't send password mail") } } @@ -619,6 +619,41 @@ func (r usersRoutes) updatePreferredGreeting(c *gin.Context) { } } +func (r usersRoutes) updateCustomSpeeds(c *gin.Context) { + u := c.MustGet("TUMLiveContext").(tools.TUMLiveContext).User + if u == nil { + _ = c.Error(tools.RequestError{ + Status: http.StatusUnauthorized, + CustomMessage: "login required", + }) + return + } + + var req struct{ Value []float32 } + if err := c.BindJSON(&req); err != nil { + _ = c.Error(tools.RequestError{ + Status: http.StatusBadRequest, + CustomMessage: "can not bind body", + Err: err, + }) + return + } + settingsString := "[]" + if len(req.Value) != 0 { + settingBytes, _ := json.Marshal(req.Value) + settingsString = string(settingBytes) + } + err := r.DaoWrapper.AddUserSetting(&model.UserSetting{UserID: u.ID, Type: model.UserDefinedSpeeds, Value: settingsString}) + if err != nil { + _ = c.Error(tools.RequestError{ + Status: http.StatusInternalServerError, + CustomMessage: "can not add user setting", + Err: err, + }) + return + } +} + func (r usersRoutes) updatePlaybackSpeeds(c *gin.Context) { u := c.MustGet("TUMLiveContext").(tools.TUMLiveContext).User if u == nil { @@ -736,12 +771,12 @@ func (r usersRoutes) resetPassword(c *gin.Context) { return } if err != nil { - log.WithError(err).Error("can't get user for password reset") + logger.Error("can't get user for password reset", "err", err) return } link, err := r.UsersDao.CreateRegisterLink(c, user) if err != nil { - log.WithError(err).Error("can't create register link") + logger.Error("can't create register link", "err", err) return } err = r.EmailDao.Create(c, &model.Email{ @@ -751,7 +786,7 @@ func (r usersRoutes) resetPassword(c *gin.Context) { Body: "Hi! \n\nYou can reset your TUM-Live password by clicking on the following link: \n\n" + tools.Cfg.WebUrl + "/setPassword/" + link.RegisterSecret + "\n\nIf you did not request a password reset, please ignore this email. \n\nBest regards", }) if err != nil { - log.WithError(err).Error("can't save reset password email") + logger.Error("can't save reset password email", "err", err) } } diff --git a/api/voice_service_grpc.go b/api/voice_service_grpc.go index b2da029b7..ed195728f 100644 --- a/api/voice_service_grpc.go +++ b/api/voice_service_grpc.go @@ -9,7 +9,6 @@ import ( "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/voice-service/pb" - log "github.com/sirupsen/logrus" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/keepalive" @@ -38,10 +37,10 @@ func (s subtitleReceiverServer) Receive(_ context.Context, request *pb.ReceiveRe } func init() { - log.Info("starting grpc voice-receiver") + logger.Info("starting grpc voice-receiver") lis, err := net.Listen("tcp", ":50053") if err != nil { - log.WithError(err).Error("failed to init voice-receiver server") + logger.Error("failed to init voice-receiver server", "err", err) return } grpcServer := grpc.NewServer(grpc.KeepaliveParams(keepalive.ServerParameters{ @@ -56,7 +55,7 @@ func init() { reflection.Register(grpcServer) go func() { if err := grpcServer.Serve(lis); err != nil { - log.Fatalf("failed to serve: %v", err) + logger.Error("failed to serve", "err", err) } }() } @@ -78,6 +77,6 @@ func GetSubtitleGeneratorClient() (SubtitleGeneratorClient, error) { func (s SubtitleGeneratorClient) CloseConn() { err := s.ClientConn.Close() if err != nil { - log.WithError(err).Error("could not close voice-service connection") + logger.Error("could not close voice-service connection", "err", err) } } diff --git a/api/worker.go b/api/worker.go index aac2413cd..ba2787248 100644 --- a/api/worker.go +++ b/api/worker.go @@ -1,10 +1,9 @@ package api import ( - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/gin-gonic/gin" "net/http" ) @@ -25,7 +24,7 @@ func (r workerRoutes) deleteWorker(c *gin.Context) { id := c.Param("id") err := r.dao.DeleteWorker(id) if err != nil { - log.WithError(err).Error("can not delete worker") + logger.Error("can not delete worker", "err", err) _ = c.Error(tools.RequestError{ Status: http.StatusInternalServerError, CustomMessage: "can not delete worker", diff --git a/api/worker_grpc.go b/api/worker_grpc.go index 0aa754f9e..26eb20267 100644 --- a/api/worker_grpc.go +++ b/api/worker_grpc.go @@ -19,14 +19,13 @@ 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" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" @@ -48,20 +47,20 @@ type server struct { func dialIn(targetWorker model.Worker) (*grpc.ClientConn, error) { credentials := insecure.NewCredentials() - log.Info("Connecting to:" + fmt.Sprintf("%s:50051", targetWorker.Host)) + logger.Info("Connecting to:" + fmt.Sprintf("%s:50051", targetWorker.Host)) conn, err := grpc.Dial(fmt.Sprintf("%s:50051", targetWorker.Host), grpc.WithTransportCredentials(credentials)) return conn, err } func endConnection(conn *grpc.ClientConn) { if err := conn.Close(); err != nil { - log.WithError(err).Error("Could not close connection to worker") + logger.Error("Could not close connection to worker", "err", err) } } // JoinWorkers is a request from a worker to join the pool. On success, the workerID is returned. func (s server) JoinWorkers(ctx context.Context, request *pb.JoinWorkersRequest) (*pb.JoinWorkersResponse, error) { - log.WithField("host", request.Hostname).Info("JoinWorkers called") + logger.Info("JoinWorkers called", "host", request.Hostname) if request.Token != tools.Cfg.WorkerToken { return nil, status.Error(codes.Unauthenticated, "Invalid token") } @@ -84,10 +83,10 @@ func (s server) JoinWorkers(ctx context.Context, request *pb.JoinWorkersRequest) LastSeen: time.Now(), } if err := s.DaoWrapper.WorkerDao.CreateWorker(&worker); err != nil { - log.WithError(err).Error("Could not add worker to database") + logger.Error("Could not add worker to database", "err", err) return nil, status.Errorf(codes.Internal, "Could not add worker to database") } - log.Info("Added worker to database") + logger.Info("Added worker to database") return &pb.JoinWorkersResponse{ WorkerId: worker.WorkerID, }, nil @@ -141,7 +140,7 @@ func (s server) SendSelfStreamRequest(ctx context.Context, request *pb.SelfStrea } // 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") + logger.Warn("Stream rejected, time out of bounds", "streamId", stream.ID) return nil, errors.New("stream rejected") } ingestServer, err := s.DaoWrapper.IngestServerDao.GetBestIngestServer() @@ -177,12 +176,12 @@ func (s server) NotifyStreamStart(ctx context.Context, request *pb.StreamStarted defer mutex.Unlock() _, err := s.DaoWrapper.WorkerDao.GetWorkerByID(ctx, request.GetWorkerID()) if err != nil { - log.WithField("request", request).Warn("Got stream start with invalid WorkerID") + logger.Warn("Got stream start with invalid WorkerID", "request", request) return nil, err } stream, err := s.StreamsDao.GetStreamByID(ctx, fmt.Sprintf("%d", request.StreamID)) if err != nil { - log.WithError(err).Warn("Can't get stream by ID to set live") + logger.Warn("Can't get stream by ID to set live", "err", err) return nil, err } stream.LiveNow = true @@ -197,7 +196,7 @@ func (s server) NotifyStreamStart(ctx context.Context, request *pb.StreamStarted } err = s.StreamsDao.SaveStream(&stream) if err != nil { - log.WithError(err).Error("Can't save stream when setting live") + logger.Error("Can't save stream when setting live", "err", err) return nil, err } return nil, nil @@ -210,27 +209,27 @@ func (s server) NotifyStreamFinished(ctx context.Context, request *pb.StreamFini } else { stream, err := s.StreamsDao.GetStreamByID(ctx, fmt.Sprintf("%d", request.StreamID)) if err != nil { - log.WithError(err).Error("Can't find stream to set not live") + logger.Error("Can't find stream to set not live", "err", err) } else { go func() { err := handleLightOffSwitch(stream, s.DaoWrapper) if err != nil { - log.WithError(err).Error("Can't handle light off switch") + logger.Error("Can't handle light off switch", "err", err) } err = s.StreamsDao.SaveEndedState(stream.ID, true) if err != nil { - log.WithError(err).Error("Can't set stream done") + logger.Error("Can't set stream done", "err", err) } }() } err = s.DaoWrapper.IngestServerDao.RemoveStreamFromSlot(stream.ID) if err != nil { - log.WithError(err).Error("Can't remove stream from streamName") + logger.Error("Can't remove stream from streamName", "err", err) } err = s.StreamsDao.SetStreamNotLiveById(uint(request.StreamID)) if err != nil { - log.WithError(err).Error("Can't set stream not live") + logger.Error("Can't set stream not live", "err", err) } NotifyViewersLiveState(uint(request.StreamID), false) } @@ -372,7 +371,7 @@ func (s server) NotifyTranscodingFinished(ctx context.Context, request *pb.Trans err = s.StreamsDao.RemoveTranscodingProgress(model.StreamVersion(request.SourceType), stream.ID) if err != nil { - log.WithError(err).Error("error removing transcoding progress") + logger.Error("error removing transcoding progress", "err", err) } // look for file to prevent duplication @@ -392,7 +391,7 @@ func (s server) NotifyTranscodingFinished(ctx context.Context, request *pb.Trans } err = s.DaoWrapper.StreamsDao.SaveStream(&stream) if err != nil { - log.WithError(err).Error("Can't save stream") + logger.Error("Can't save stream", "err", err) return nil, err } return &pb.Status{Ok: true}, nil @@ -414,7 +413,7 @@ func (s server) NotifyUploadFinished(ctx context.Context, req *pb.UploadFinished return nil, err } if stream.LiveNow { - log.WithField("req", req).Warn("VoD not saved, stream is live.") + logger.Warn("VoD not saved, stream is live.", "req", req) return nil, nil } stream.Recording = true @@ -479,7 +478,7 @@ func (s server) NotifyThumbnailsFinished(ctx context.Context, req *pb.Thumbnails func generateCombinedThumb(streamID uint, dao dao.DaoWrapper) { stream, err := dao.StreamsDao.GetStreamByID(context.Background(), fmt.Sprintf("%d", streamID)) if err != nil { - log.WithError(err).Warn("error getting stream") + logger.Warn("error getting stream", "err", err) return } var thumbCam, thumbPres string @@ -501,7 +500,7 @@ func generateCombinedThumb(streamID uint, dao dao.DaoWrapper) { w := workers[getWorkerWithLeastWorkload(workers)] wConn, err := dialIn(w) if err != nil { - log.WithError(err).Warn("error dialing in") + logger.Warn("error dialing in", "err", err) return } client := pb.NewToWorkerClient(wConn) @@ -511,11 +510,11 @@ func generateCombinedThumb(streamID uint, dao dao.DaoWrapper) { Path: strings.ReplaceAll(thumbPres, "PRES", "CAM_PRES"), }) if err != nil { - log.WithError(err).Warn("error combining thumbnails") + logger.Warn("error combining thumbnails", "err", err) return } if err := dao.FileDao.SetThumbnail(stream.ID, model.File{StreamID: stream.ID, Path: thumbnails.FilePath, Type: model.FILETYPE_THUMB_LG_CAM_PRES}); err != nil { - log.WithError(err).Warn("error saving thumbnail") + logger.Warn("error saving thumbnail", "err", err) } } @@ -536,7 +535,7 @@ func (s server) GetStreamInfoForUpload(ctx context.Context, request *pb.GetStrea } err = dao.NewUploadKeyDao().DeleteUploadKey(key) if err != nil { - log.WithError(err).Error("Can't delete upload key") + logger.Error("Can't delete upload key", "err", err) } return &pb.GetStreamInfoForUploadResponse{ CourseSlug: course.Slug, @@ -559,26 +558,26 @@ func (s server) NotifyStreamStarted(ctx context.Context, request *pb.StreamStart } stream, err := s.StreamsDao.GetStreamByID(ctx, fmt.Sprintf("%d", request.GetStreamID())) if err != nil { - log.WithError(err).Println("Can't find stream") + logger.Error("Can't find stream", "err", err) return nil, err } course, err := s.CoursesDao.GetCourseById(ctx, stream.CourseID) if err != nil { - log.WithError(err).Println("Can't find course") + logger.Error("Can't find course", "err", err) return nil, err } go func() { err := handleLightOnSwitch(stream, s.DaoWrapper) if err != nil { - log.WithError(err).Error("Can't handle light on switch") + logger.Error("Can't handle light on switch", "err", err) } err = handleCameraPositionSwitch(stream, s.DaoWrapper) if err != nil { - log.WithError(err).Error("Can't handle camera position switch") + logger.Error("Can't handle camera position switch", "err", err) } err = s.DaoWrapper.DeleteSilences(fmt.Sprintf("%d", stream.ID)) if err != nil { - log.WithError(err).Error("Can't delete silences") + logger.Error("Can't delete silences", "err", err) } }() go func() { @@ -587,12 +586,12 @@ func (s server) NotifyStreamStarted(ctx context.Context, request *pb.StreamStart err := s.StreamsDao.SaveStream(&stream) if err != nil { - log.WithError(err).Error("Can't save stream") + logger.Error("Can't save stream", "err", err) } err = s.StreamsDao.SetStreamLiveNowTimestampById(uint(request.StreamID), time.Now()) if err != nil { - log.WithError(err).Error("Can't set StreamLiveNowTimestamp") + logger.Error("Can't set StreamLiveNowTimestamp", "err", err) } time.Sleep(time.Second * 5) @@ -630,7 +629,7 @@ func (s server) NotifyTranscodingProgress(srv pb.FromWorker_NotifyTranscodingPro return nil } if err != nil { - log.Warnf("cannot receive %v", err) + logger.Warn("cannot receive", "err", err) return nil } err = s.DaoWrapper.StreamsDao.SaveTranscodingProgress(model.TranscodingProgress{ @@ -676,7 +675,7 @@ func CreateStreamRequest(daoWrapper dao.DaoWrapper, stream model.Stream, course } server, err := daoWrapper.IngestServerDao.GetBestIngestServer() if err != nil { - log.WithError(err).Error("Can't find ingest server") + logger.Error("Can't find ingest server", "err", err) return } var slot model.StreamName @@ -686,7 +685,7 @@ func CreateStreamRequest(daoWrapper dao.DaoWrapper, stream model.Stream, course if sourceType != "COMB" || err != nil { slot, err = daoWrapper.IngestServerDao.GetStreamSlot(server.ID) if err != nil { - log.WithError(err).Error("No free stream slot") + logger.Error("No free stream slot", "err", err) return } } @@ -710,12 +709,12 @@ func CreateStreamRequest(daoWrapper dao.DaoWrapper, stream model.Stream, course workers[workerIndex].Workload += 3 err = daoWrapper.StreamsDao.SaveWorkerForStream(stream, workers[workerIndex]) if err != nil { - log.WithError(err).Error("Could not save worker for stream") + logger.Error("Could not save worker for stream", "err", err) return } conn, err := dialIn(workers[workerIndex]) if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) workers[workerIndex].Workload -= 1 // decrease workers load only by one (backoff) return } @@ -723,7 +722,7 @@ func CreateStreamRequest(daoWrapper dao.DaoWrapper, stream model.Stream, course req.WorkerId = workers[workerIndex].WorkerID resp, err := client.RequestStream(context.Background(), &req) if err != nil || !resp.Ok { - log.WithError(err).Error("could not assign stream!") + logger.Error("could not assign stream!", "err", err) workers[workerIndex].Workload -= 1 // decrease workers load only by one (backoff) } endConnection(conn) @@ -738,25 +737,25 @@ func NotifyWorkers(daoWrapper dao.DaoWrapper) func() { streams := daoWrapper.StreamsDao.GetDueStreamsForWorkers() workers := daoWrapper.WorkerDao.GetAliveWorkers() if len(workers) == 0 && len(streams) != 0 { - log.Error("not enough workers to handle streams") + logger.Error("not enough workers to handle streams") return } for i := range streams { err := daoWrapper.StreamsDao.SaveEndedState(streams[i].ID, false) if err != nil { - log.WithError(err).Warn("Can't set stream undone") + logger.Warn("Can't set stream undone", "err", err) sentry.CaptureException(err) continue } courseForStream, err := daoWrapper.CoursesDao.GetCourseById(context.Background(), streams[i].CourseID) if err != nil { - log.WithError(err).Warn("Can't get course for stream, skipping") + logger.Warn("Can't get course for stream, skipping", "err", err) sentry.CaptureException(err) continue } lectureHallForStream, err := daoWrapper.LectureHallsDao.GetLectureHallByID(streams[i].LectureHallID) if err != nil { - log.WithError(err).Error("Can't get lecture hall for stream, skipping") + logger.Error("Can't get lecture hall for stream, skipping", "err", err) sentry.CaptureException(err) continue } @@ -786,25 +785,25 @@ func notifyWorkersPremieres(daoWrapper dao.DaoWrapper) { workers := daoWrapper.WorkerDao.GetAliveWorkers() if len(workers) == 0 && len(streams) != 0 { - log.Error("Not enough alive workers for premiere") + logger.Error("Not enough alive workers for premiere") return } for i := range streams { err := daoWrapper.StreamsDao.SaveEndedState(streams[i].ID, false) if err != nil { - log.WithError(err).Warn("Can't set stream undone") + logger.Warn("Can't set stream undone", "err", err) sentry.CaptureException(err) continue } if len(streams[i].Files) == 0 { - log.WithField("streamID", streams[i].ID).Warn("Request to self stream without file") + logger.Warn("Request to self stream without file", "streamID", streams[i].ID) continue } workerIndex := getWorkerWithLeastWorkload(workers) workers[workerIndex].Workload += 3 ingestServer, err := daoWrapper.IngestServerDao.GetBestIngestServer() if err != nil { - log.WithError(err).Error("Can't find ingest server") + logger.Error("Can't find ingest server", "err", err) continue } req := pb.PremiereRequest{ @@ -815,7 +814,7 @@ func notifyWorkersPremieres(daoWrapper dao.DaoWrapper) { } conn, err := dialIn(workers[workerIndex]) if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) endConnection(conn) workers[workerIndex].Workload -= 1 continue @@ -824,7 +823,7 @@ func notifyWorkersPremieres(daoWrapper dao.DaoWrapper) { req.WorkerID = workers[workerIndex].WorkerID resp, err := client.RequestPremiere(context.Background(), &req) if err != nil || !resp.Ok { - log.WithError(err).Error("could not assign premiere!") + logger.Error("could not assign premiere!", "err", err) workers[workerIndex].Workload -= 1 } endConnection(conn) @@ -852,7 +851,7 @@ func FetchLivePreviews(daoWrapper dao.DaoWrapper) func() { } conn, err := dialIn(workers[workerIndex]) if err != nil { - log.WithError(err).Error("Could not connect to worker") + logger.Error("Could not connect to worker", "err", err) endConnection(conn) continue } @@ -860,7 +859,7 @@ func FetchLivePreviews(daoWrapper dao.DaoWrapper) func() { workers[workerIndex].Workload += 1 if err := getLivePreviewFromWorker(&s, workers[workerIndex].WorkerID, client); err != nil { workers[workerIndex].Workload -= 1 - log.WithError(err).Error("Could not generate live preview") + logger.Error("Could not generate live preview", "err", err) endConnection(conn) continue } @@ -909,7 +908,7 @@ func RegenerateThumbs(daoWrapper dao.DaoWrapper, file model.File, stream *model. endConnection(conn) }() if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) return err } client := pb.NewToWorkerClient(conn) @@ -925,7 +924,7 @@ func RegenerateThumbs(daoWrapper dao.DaoWrapper, file model.File, stream *model. Start: timestamppb.New(stream.Start), }) if !res.Ok { - log.WithError(err).Error("did not get response from worker for thumbnail generation request") + logger.Error("did not get response from worker for thumbnail generation request", "err", err) } return nil @@ -948,7 +947,7 @@ func DeleteVideoSectionImage(workerDao dao.WorkerDao, path string) error { endConnection(conn) }() if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) return err } @@ -969,7 +968,7 @@ func GenerateVideoSectionImages(daoWrapper dao.DaoWrapper, parameters *generateV endConnection(conn) }() if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) return err } @@ -1016,12 +1015,12 @@ func GenerateVideoSectionImages(daoWrapper dao.DaoWrapper, parameters *generateV func NotifyWorkersToStopStream(stream model.Stream, discardVoD bool, daoWrapper dao.DaoWrapper) { workers, err := daoWrapper.StreamsDao.GetWorkersForStream(stream) if err != nil { - log.WithError(err).Error("Could not get workers for stream") + logger.Error("Could not get workers for stream", "err", err) return } if len(workers) == 0 { - log.Error("No workers for stream found") + logger.Error("No workers for stream found") return } @@ -1034,13 +1033,13 @@ func NotifyWorkersToStopStream(stream model.Stream, discardVoD bool, daoWrapper } conn, err := dialIn(currentWorker) if err != nil { - log.WithError(err).Error("Unable to dial server") + logger.Error("Unable to dial server", "err", err) continue } client := pb.NewToWorkerClient(conn) resp, err := client.RequestStreamEnd(context.Background(), &req) if err != nil || !resp.Ok { - log.WithError(err).Error("Could not end stream") + logger.Error("Could not end stream", "err", err) } endConnection(conn) } @@ -1048,7 +1047,7 @@ func NotifyWorkersToStopStream(stream model.Stream, discardVoD bool, daoWrapper // All workers for stream are assumed to be done err = daoWrapper.StreamsDao.ClearWorkersForStream(stream) if err != nil { - log.WithError(err).Error("Could not delete workers for stream") + logger.Error("Could not delete workers for stream", "err", err) return } } @@ -1092,10 +1091,10 @@ func getWorkerWithLeastWorkload(workers []model.Worker) int { // ServeWorkerGRPC initializes a gRPC server on port 50052 func ServeWorkerGRPC() { - log.Info("Serving heartbeat") + logger.Info("Serving heartbeat") lis, err := net.Listen("tcp", ":50052") if err != nil { - log.WithError(err).Error("Failed to init grpc server") + logger.Error("Failed to init grpc server", "err", err) return } grpcServer := grpc.NewServer(grpc.KeepaliveParams(keepalive.ServerParameters{ @@ -1109,7 +1108,7 @@ func ServeWorkerGRPC() { reflection.Register(grpcServer) go func() { if err = grpcServer.Serve(lis); err != nil { - log.WithError(err).Errorf("Can't serve grpc") + logger.Error("Can't serve grpc", "err", err) } }() } diff --git a/api/wsHub.go b/api/wsHub.go index d2876263f..0a4265165 100644 --- a/api/wsHub.go +++ b/api/wsHub.go @@ -5,12 +5,11 @@ import ( "encoding/json" "errors" "fmt" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/tools" "github.com/TUM-Dev/gocast/tools/realtime" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "strconv" "strings" "sync" @@ -52,11 +51,12 @@ var connHandler = func(context *realtime.Context) { msg, _ := json.Marshal(gin.H{"viewers": len(sessionsMap[tumLiveContext.Stream.ID])}) err := context.Send(msg) if err != nil { - log.WithError(err).Error("can't write initial stats to session") + logger.Error("can't write initial stats to session", "err", err) } } // sendServerMessageWithBackoff sends a message to the client(if it didn't send a message to this user in the last 10 Minutes and the client is logged in) +// //lint:ignore U1000 Ignore unused function func sendServerMessageWithBackoff(session *realtime.Context, userId uint, streamId uint, msg string, t string) { if userId == 0 { @@ -71,7 +71,7 @@ func sendServerMessageWithBackoff(session *realtime.Context, userId uint, stream msgBytes, _ := json.Marshal(gin.H{"server": msg, "type": t}) err := session.Send(msgBytes) if err != nil { - log.WithError(err).Error("can't write server message to session") + logger.Error("can't write server message to session", "err", err) } // set cache item with ttl, so the user won't get a message for 10 Minutes tools.SetCacheItem(cacheKey, true, time.Minute*10) @@ -83,7 +83,7 @@ func sendServerMessage(msg string, t string, sessions ...*realtime.Context) { for _, session := range sessions { err := session.Send(msgBytes) if err != nil { - log.WithError(err).Error("can't write server message to session") + logger.Error("can't write server message to session", "err", err) } } diff --git a/cmd/tumlive/tumlive.go b/cmd/tumlive/tumlive.go index 533f428c7..aa6efc7b5 100755 --- a/cmd/tumlive/tumlive.go +++ b/cmd/tumlive/tumlive.go @@ -2,6 +2,14 @@ package main import ( "fmt" + "log/slog" + "net/http" + _ "net/http/pprof" + "os" + "os/signal" + "syscall" + "time" + "github.com/TUM-Dev/gocast/api" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" @@ -13,22 +21,20 @@ import ( sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-contrib/gzip" "github.com/gin-gonic/gin" + slogGorm "github.com/orandin/slog-gorm" "github.com/pkg/profile" - log "github.com/sirupsen/logrus" "gorm.io/driver/mysql" "gorm.io/gorm" - "net/http" - _ "net/http/pprof" - "os" - "os/signal" - "syscall" - "time" ) var VersionTag = "development" type initializer func() +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "main") + var initializers = []initializer{ tools.LoadConfig, api.ServeWorkerGRPC, @@ -44,7 +50,8 @@ func initAll(initializers []initializer) { // GinServer launches the gin server func GinServer() (err error) { - router := gin.Default() + router := gin.New() + router.Use(gin.Recovery()) gin.SetMode(gin.ReleaseMode) // capture performance with sentry router.Use(sentrygin.New(sentrygin.Options{Repanic: true})) @@ -52,6 +59,19 @@ func GinServer() (err error) { tools.CookieSecure = true } + router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string { + if param.StatusCode >= 400 { + return fmt.Sprintf("{\"service\": \"GIN\", \"time\": %s, \"status\": %d, \"client\": \"%s\", \"path\": \"%s\", \"agent\": %s}\n", + param.TimeStamp.Format(time.DateTime), + param.StatusCode, + param.ClientIP, + param.Path, + param.Request.UserAgent(), + ) + } + return "" + })) + router.Use(tools.InitContext(dao.NewDaoWrapper())) liveUpdates := router.Group("/api/pub-sub") @@ -68,7 +88,7 @@ func GinServer() (err error) { //err = router.RunTLS(":443", tools.Cfg.Saml.Cert, tools.Cfg.Saml.Privkey) if err != nil { sentry.CaptureException(err) - log.WithError(err).Fatal("Error starting tumlive") + logger.Error("Error starting tumlive", "err", err) } return } @@ -86,7 +106,7 @@ func main() { }() // log with time, fmt "23.09.2021 10:00:00" - log.SetFormatter(&log.TextFormatter{TimestampFormat: "02.01.2006 15:04:05", FullTimestamp: true}) + // log.SetFormatter(&log.TextFormatter{TimestampFormat: "02.01.2006 15:04:05", FullTimestamp: true}) web.VersionTag = VersionTag osSignal = make(chan os.Signal, 1) @@ -105,12 +125,15 @@ func main() { Environment: env, }) if err != nil { - log.Fatalf("sentry.Init: %s", err) + logger.Error("sentry.Init", "err", err) } // Flush buffered events before the program terminates. defer sentry.Flush(2 * time.Second) defer sentry.Recover() } + + gormJSONLogger := slogGorm.New() + db, err := gorm.Open(mysql.Open(fmt.Sprintf( "%s:%s@tcp(%s:%d)/%s?parseTime=true&loc=Local", tools.Cfg.Db.User, @@ -120,18 +143,19 @@ func main() { tools.Cfg.Db.Database), ), &gorm.Config{ PrepareStmt: true, + Logger: gormJSONLogger, }) if err != nil { sentry.CaptureException(err) sentry.Flush(time.Second * 5) - log.Fatalf("%v", err) + logger.Error("Error opening database", "err", err) } dao.DB = db err = dao.Migrator.RunBefore(db) if err != nil { - log.Error(err) + logger.Error("Error running before db", "err", err) return } @@ -174,11 +198,11 @@ func main() { if err != nil { sentry.CaptureException(err) sentry.Flush(time.Second * 5) - log.WithError(err).Fatal("can't migrate database") + logger.Error("can't migrate database", "err", err) } err = dao.Migrator.RunAfter(db) if err != nil { - log.Error(err) + logger.Error("Error running after db", "err", err) return } @@ -193,7 +217,7 @@ func main() { if err != nil { sentry.CaptureException(err) sentry.Flush(time.Second * 5) - log.Fatalf("%v", err) + logger.Error("Error risretto.NewCache", "err", err) } dao.Cache = *cache @@ -209,7 +233,7 @@ func main() { if err != nil { sentry.CaptureException(err) sentry.Flush(time.Second * 5) - log.WithError(err).Fatal("can't launch gin server") + logger.Error("can't launch gin server", "err", err) } }() keepAlive() @@ -238,5 +262,5 @@ func initCron() { func keepAlive() { signal.Notify(osSignal, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1) s := <-osSignal - log.Infof("Exiting on signal %s", s.String()) + logger.Info("Exiting on signal" + s.String()) } diff --git a/dao/courses.go b/dao/courses.go index 23978d086..7a169f0c9 100644 --- a/dao/courses.go +++ b/dao/courses.go @@ -10,7 +10,6 @@ import ( "github.com/RBG-TUM/commons" "github.com/getsentry/sentry-go" - log "github.com/sirupsen/logrus" "gorm.io/gorm" ) @@ -201,6 +200,7 @@ func (d coursesDao) GetCourseByToken(token string) (course model.Course, err err func (d coursesDao) GetCourseById(ctx context.Context, id uint) (course model.Course, err error) { var foundCourse model.Course dbErr := DB.Preload("Streams.TranscodingProgresses"). + Preload("Streams.VideoSections"). Preload("Streams.Files"). Preload("Streams", func(db *gorm.DB) *gorm.DB { return db.Order("streams.start desc") @@ -218,7 +218,7 @@ func (d coursesDao) GetCourseBySlugYearAndTerm(ctx context.Context, slug string, return cachedCourses.(model.Course), nil } var course model.Course - err := DB.Preload("Streams.Units", func(db *gorm.DB) *gorm.DB { + err := DB.Preload("Streams.VideoSections").Preload("Streams.Units", func(db *gorm.DB) *gorm.DB { return db.Order("unit_start desc") }).Preload("Streams", func(db *gorm.DB) *gorm.DB { return db.Order("start desc") @@ -304,16 +304,16 @@ func (d coursesDao) DeleteCourse(course model.Course) { for _, stream := range course.Streams { err := DB.Delete(&stream).Error if err != nil { - log.WithError(err).Error("Can't delete stream") + logger.Error("Can't delete stream", "err", err) } } err := DB.Model(&course).Updates(map[string]interface{}{"vod_enabled": false}).Error if err != nil { - log.WithError(err).Error("Can't update course settings when deleting") + logger.Error("Can't update course settings when deleting", "err", err) } err = DB.Delete(&course, course.ID).Error if err != nil { - log.WithError(err).Error("Can't delete course") + logger.Error("Can't delete course", "err", err) } } diff --git a/dao/dao_logger.go b/dao/dao_logger.go new file mode 100644 index 000000000..63eb896b4 --- /dev/null +++ b/dao/dao_logger.go @@ -0,0 +1,10 @@ +package dao + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "dao") diff --git a/dao/video-seek.go b/dao/video-seek.go index 4cc7200ed..165650cc0 100644 --- a/dao/video-seek.go +++ b/dao/video-seek.go @@ -3,7 +3,6 @@ package dao import ( "errors" "github.com/TUM-Dev/gocast/model" - log "github.com/sirupsen/logrus" "gorm.io/gorm" "gorm.io/gorm/clause" ) @@ -32,7 +31,7 @@ func (d videoSeekDao) Add(streamID string, pos float64) error { } if (pos / float64(stream.Duration.Int32)) > 1 { - log.Error("position is bigger than stream duration") + logger.Error("position is bigger than stream duration") return errors.New("position is bigger than stream duration") } diff --git a/go.mod b/go.mod index dd030c58c..1206996fa 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/TUM-Dev/gocast -go 1.18 +go 1.21 require ( github.com/RBG-TUM/CAMPUSOnline v0.0.0-20230412070523-8db58ed5c0b4 @@ -30,7 +30,7 @@ require ( google.golang.org/grpc v1.57.0 google.golang.org/protobuf v1.31.0 gorm.io/driver/mysql v1.5.1 - gorm.io/gorm v1.25.3 + gorm.io/gorm v1.25.5 mvdan.cc/xurls/v2 v2.5.0 ) @@ -50,6 +50,7 @@ require ( github.com/asticode/go-astisub v0.26.0 github.com/matthiasreumann/gomino v0.0.2 github.com/meilisearch/meilisearch-go v0.25.0 + github.com/orandin/slog-gorm v1.0.1 ) require ( diff --git a/go.sum b/go.sum index 1b9e9cfab..04b5da18a 100644 --- a/go.sum +++ b/go.sum @@ -126,6 +126,7 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= @@ -145,6 +146,7 @@ github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SU github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -155,6 +157,7 @@ github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSz github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= @@ -175,7 +178,9 @@ github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= +github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= @@ -271,13 +276,17 @@ github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= +github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= @@ -323,11 +332,13 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/meilisearch/meilisearch-go v0.25.0 h1:xIp+8YWterHuDvpdYlwQ4Qp7im3JlRHmSKiP0NvjyXs= github.com/meilisearch/meilisearch-go v0.25.0/go.mod h1:SxuSqDcPBIykjWz1PX+KzsYzArNLSCadQodWs8extS0= github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= github.com/microsoft/go-mssqldb v0.21.0 h1:p2rpHIL7TlSv1QrbXJUAcbyRKnIT0C9rRkH2E4OjLn8= +github.com/microsoft/go-mssqldb v0.21.0/go.mod h1:+4wZTUnz/SV6nffv+RRRB/ss8jPng5Sho2SmM1l2ts4= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= @@ -344,11 +355,14 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/olahol/melody v0.0.0-20180227134253-7bd65910e5ab/go.mod h1:3lo03f1jM3KFUG/rsujuLB1rBmlvIzVM3SCqbuHqsBU= +github.com/orandin/slog-gorm v1.0.1 h1:Hyhaajes1rXsgwbH59+qS2JaN31PNEBzMywiFsa2Eiw= +github.com/orandin/slog-gorm v1.0.1/go.mod h1:QLR+9XefjS+lz7Xw3ZXkDkT5U59h7/0c8TZlMZPqXpI= github.com/panjf2000/ants/v2 v2.4.2/go.mod h1:f6F0NZVFsGCp5A7QW/Zj/m92atWwOkY0OIhFxRNFr4A= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -367,6 +381,7 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russellhaering/goxmldsig v1.2.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= github.com/russellhaering/goxmldsig v1.4.0 h1:8UcDh/xGyQiyrW+Fq5t8f+l2DLB1+zlhYzkPUJ7Qhys= github.com/russellhaering/goxmldsig v1.4.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw= @@ -803,11 +818,14 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= +gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= gorm.io/driver/sqlite v1.5.1 h1:hYyrLkAWE71bcarJDPdZNTLWtr8XrSjOWyjUYI6xdL4= +gorm.io/driver/sqlite v1.5.1/go.mod h1:7MZZ2Z8bqyfSQA1gYEV6MagQWj3cpUkJj9Z+d1HEMEQ= gorm.io/driver/sqlserver v1.5.0 h1:zol7ePfY1XiPfjEvjjBh4VatIF3kycNcPE0EMCXznHY= +gorm.io/driver/sqlserver v1.5.0/go.mod h1:tBAqioK34BHl0Iiez+BFfG5/K9nDAlhLxRkgc2qy3+4= gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -gorm.io/gorm v1.25.3 h1:zi4rHZj1anhZS2EuEODMhDisGy+Daq9jtPrNGgbQYD8= -gorm.io/gorm v1.25.3/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= +gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E= diff --git a/go.work b/go.work index 74bb747de..d1d9a8d2f 100644 --- a/go.work +++ b/go.work @@ -1,9 +1,9 @@ -go 1.21.1 +go 1.21.0 use ( . ./worker ./worker/edge - runner vod-service + ./runner ) diff --git a/go.work.sum b/go.work.sum index b3668fae9..519278e27 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,3 +1,4 @@ +cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= cloud.google.com/go v0.110.6 h1:8uYAkj3YHTP/1iwReuHPxLSbdcyc+dSBbzFMrVwDR6Q= @@ -34,6 +35,7 @@ cloud.google.com/go/batch v1.3.1 h1:uE0Q//W7FOGPjf7nuPiP0zoE8wOT3ngoIO2HIet0ilY= cloud.google.com/go/batch v1.3.1/go.mod h1:VguXeQKXIYaeeIYbuozUmBR13AfL4SJP7IltNPS+A4A= cloud.google.com/go/beyondcorp v1.0.0 h1:VPg+fZXULQjs8LiMeWdLaB5oe8G9sEoZ0I0j6IMiG1Q= cloud.google.com/go/beyondcorp v1.0.0/go.mod h1:YhxDWw946SCbmcWo3fAhw3V4XZMSpQ/VYfcKGAEU8/4= +cloud.google.com/go/bigquery v1.8.0 h1:PQcPefKFdaIzjQFbiyOgAqyx8q5djaE7x9Sqe712DPA= cloud.google.com/go/bigquery v1.53.0 h1:K3wLbjbnSlxhuG5q4pntHv5AEbQM1QqHKGYgwFIqOTg= cloud.google.com/go/bigquery v1.53.0/go.mod h1:3b/iXjRQGU4nKa87cXeg6/gogLjO8C6PmuM8i5Bi/u4= cloud.google.com/go/billing v1.16.0 h1:1iktEAIZ2uA6KpebC235zi/rCXDdDYQ0bTXTNetSL80= @@ -51,6 +53,7 @@ cloud.google.com/go/clouddms v1.6.1/go.mod h1:Ygo1vL52Ov4TBZQquhz5fiw2CQ58gvu+Pl cloud.google.com/go/cloudtasks v1.12.1 h1:cMh9Q6dkvh+Ry5LAPbD/U2aw6KAqdiU6FttwhbTo69w= cloud.google.com/go/cloudtasks v1.12.1/go.mod h1:a9udmnou9KO2iulGscKR0qBYjreuX8oHwpmFsKspEvM= cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= +cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg= cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= @@ -81,6 +84,7 @@ cloud.google.com/go/dataproc/v2 v2.0.1 h1:4OpSiPMMGV3XmtPqskBU/RwYpj3yMFjtMLj/ex cloud.google.com/go/dataproc/v2 v2.0.1/go.mod h1:7Ez3KRHdFGcfY7GcevBbvozX+zyWGcwLJvvAMwCaoZ4= cloud.google.com/go/dataqna v0.8.1 h1:ITpUJep04hC9V7C+gcK390HO++xesQFSUJ7S4nSnF3U= cloud.google.com/go/dataqna v0.8.1/go.mod h1:zxZM0Bl6liMePWsHA8RMGAfmTG34vJMapbHAxQ5+WA8= +cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ= cloud.google.com/go/datastore v1.13.0 h1:ktbC66bOQB3HJPQe8qNI1/aiQ77PMu7hD4mzE6uxe3w= cloud.google.com/go/datastore v1.13.0/go.mod h1:KjdB88W897MRITkvWWJrg2OUtrR5XVj1EoLgSp6/N70= cloud.google.com/go/datastream v1.10.0 h1:ra/+jMv36zTAGPfi8TRne1hXme+UsKtdcK4j6bnqQiw= @@ -105,6 +109,7 @@ cloud.google.com/go/eventarc v1.13.0 h1:xIP3XZi0Xawx8DEfh++mE2lrIi5kQmCr/KcWhJ1q cloud.google.com/go/eventarc v1.13.0/go.mod h1:mAFCW6lukH5+IZjkvrEss+jmt2kOdYlN8aMx3sRJiAI= cloud.google.com/go/filestore v1.7.1 h1:Eiz8xZzMJc5ppBWkuaod/PUdUZGCFR8ku0uS+Ah2fRw= cloud.google.com/go/filestore v1.7.1/go.mod h1:y10jsorq40JJnjR/lQ8AfFbbcGlw3g+Dp8oN7i7FjV4= +cloud.google.com/go/firestore v1.9.0 h1:IBlRyxgGySXu5VuW0RgGFlTtLukSnNkpDiEOMkQkmpA= cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= cloud.google.com/go/firestore v1.11.0 h1:PPgtwcYUOXV2jFe1bV3nda3RCrOa8cvBjTOn2MQVfW8= cloud.google.com/go/firestore v1.11.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4= @@ -141,6 +146,7 @@ cloud.google.com/go/lifesciences v0.9.1 h1:axkANGx1wiBXHiPcJZAE+TDjjYoJRIDzbHC/W cloud.google.com/go/lifesciences v0.9.1/go.mod h1:hACAOd1fFbCGLr/+weUKRAJas82Y4vrL3O5326N//Wc= cloud.google.com/go/logging v1.7.0 h1:CJYxlNNNNAMkHp9em/YEXcfJg+rPDg7YfwoRpMU+t5I= cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc= cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tErFDWI= @@ -181,6 +187,7 @@ cloud.google.com/go/policytroubleshooter v1.8.0 h1:XTMHy31yFmXgQg57CB3w9YQX8US7i cloud.google.com/go/policytroubleshooter v1.8.0/go.mod h1:tmn5Ir5EToWe384EuboTcVQT7nTag2+DuH3uHmKd1HU= cloud.google.com/go/privatecatalog v0.9.1 h1:B/18xGo+E0EMS9LOEQ0zXz7F2asMgmVgTYGSI89MHOA= cloud.google.com/go/privatecatalog v0.9.1/go.mod h1:0XlDXW2unJXdf9zFz968Hp35gl/bhF4twwpXZAW50JA= +cloud.google.com/go/pubsub v1.3.1 h1:ukjixP1wl0LpnZ6LWtZJ0mX5tBmjp1f8Sqer8Z2OMUU= cloud.google.com/go/pubsub v1.33.0 h1:6SPCPvWav64tj0sVX/+npCBKhUi/UjJehy9op/V3p2g= cloud.google.com/go/pubsub v1.33.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= cloud.google.com/go/pubsublite v1.8.1 h1:pX+idpWMIH30/K7c0epN6V703xpIcMXWRjKJsz0tYGY= @@ -217,6 +224,7 @@ cloud.google.com/go/spanner v1.47.0 h1:aqiMP8dhsEXgn9K5EZBWxPG7dxIiyM2VaikqeU4it cloud.google.com/go/spanner v1.47.0/go.mod h1:IXsJwVW2j4UKs0eYDqodab6HgGuA1bViSqW4uH9lfUI= cloud.google.com/go/speech v1.19.0 h1:MCagaq8ObV2tr1kZJcJYgXYbIn8Ai5rp42tyGYw9rls= cloud.google.com/go/speech v1.19.0/go.mod h1:8rVNzU43tQvxDaGvqOhpDqgkJTFowBpDvCJ14kGlJYo= +cloud.google.com/go/storage v1.14.0 h1:6RRlFMv1omScs6iq2hfE3IvgE+l6RfJPampq8UZc5TU= cloud.google.com/go/storage v1.30.1 h1:uOdMxAs8HExqBlnLtnQyP0YkvbiDpdGShGKtx6U/oNM= cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7BiccwkR7+P7gN8E= cloud.google.com/go/storagetransfer v1.10.0 h1:+ZLkeXx0K0Pk5XdDmG0MnUVqIR18lllsihU/yq39I8Q= @@ -310,9 +318,11 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/djherbis/atime v1.1.0 h1:rgwVbP/5by8BvvjBNrbh64Qz33idKT3pSnMSJsxhi0g= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f h1:7T++XKzy4xg7PKy+bM+Sa9/oe1OC88yz2hXQUISoXfA= github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM= github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g= +github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8= github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= @@ -320,8 +330,6 @@ github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw= -github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= @@ -330,7 +338,6 @@ github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNV github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk= -github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= @@ -339,8 +346,6 @@ github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA= github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= -github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= @@ -349,14 +354,17 @@ github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6 github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= +github.com/google/martian/v3 v3.1.0 h1:wCKgOCHuUEVfsaQLpPSJb7VdYCdTVZQAuOdYm1yc/60= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= +github.com/google/s2a-go v0.1.3 h1:FAgZmpLl/SXurPEZyCMPBIiiYeTbqfjlbdnCNTAkbGE= github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc= github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4= github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= @@ -400,10 +408,6 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH github.com/iris-contrib/httpexpect/v2 v2.3.1 h1:A69ilxKGW1jDRKK5UAhjTL4uJYh3RjD4qzt9vNZ7fpY= github.com/iris-contrib/jade v1.1.4 h1:WoYdfyJFfZIUgqNAeOyRfTNQZOksSlZ6+FnXR3AEpX0= github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= @@ -439,9 +443,7 @@ github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2 h1:JAEbJn3j/FrhdWA9jW8 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mediocregopher/radix/v3 v3.8.0 h1:HI8EgkaM7WzsrFpYAkOXIgUKbjNonb2Ne7K6Le61Pmg= -github.com/microsoft/go-mssqldb v0.21.0/go.mod h1:+4wZTUnz/SV6nffv+RRRB/ss8jPng5Sho2SmM1l2ts4= github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 h1:AMFGa4R4MiIpspGNG7Z948v4n35fFGB3RR3G/ry4FWs= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= @@ -481,8 +483,6 @@ github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5 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/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= -github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f h1:UFr9zpz4xgTnIE5yIMtWAMngCdZ9p/+q6lTbgelo80M= github.com/sagikazarmark/crypt v0.10.0 h1:96E1qrToLBU6fGzo+PRRz7KGOc9FkYFiPnR3/zf8Smg= @@ -556,6 +556,7 @@ golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= @@ -570,13 +571,14 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/api v0.122.0 h1:zDobeejm3E7pEG1mNHvdxvjs5XJoCMzyNH+CmwL94Es= google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= google.golang.org/api v0.126.0 h1:q4GJq+cAdMAC7XP7njvQ4tvohGLiSlytuL4BQxbIZ+o= google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= @@ -585,6 +587,7 @@ google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:O9kGHb51 google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= +google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9 h1:m8v1xLLLzMe1m5P+gCTF8nJB9epwZQUBERm20Oy1poQ= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= @@ -605,10 +608,6 @@ google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= -gorm.io/driver/sqlite v1.5.1/go.mod h1:7MZZ2Z8bqyfSQA1gYEV6MagQWj3cpUkJj9Z+d1HEMEQ= -gorm.io/driver/sqlserver v1.5.0/go.mod h1:tBAqioK34BHl0Iiez+BFfG5/K9nDAlhLxRkgc2qy3+4= gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64= honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8= diff --git a/model/course.go b/model/course.go index e902bba18..65c3524f8 100755 --- a/model/course.go +++ b/model/course.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" "gorm.io/gorm" "log" "time" @@ -148,7 +147,7 @@ func (c Course) CanUseSource(lectureHallID uint, sourceType string) bool { func (c *Course) SetSourcePreference(pref []SourcePreference) { pBytes, err := json.Marshal(pref) if err != nil { - logrus.WithError(err).Error("Could not marshal source preference") + logger.Error("Could not marshal source preference", "err", err) return } c.SourcePreferences = string(pBytes) diff --git a/model/model_logger.go b/model/model_logger.go new file mode 100644 index 000000000..2464568ee --- /dev/null +++ b/model/model_logger.go @@ -0,0 +1,10 @@ +package model + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "model") diff --git a/model/stream.go b/model/stream.go index 6fac079af..35de2d675 100755 --- a/model/stream.go +++ b/model/stream.go @@ -323,6 +323,18 @@ func (s Stream) getJson(lhs []LectureHall, course Course) gin.H { } } + var videoSections []gin.H + for _, section := range s.VideoSections { + videoSections = append(videoSections, gin.H{ + "id": section.ID, + "description": section.Description, + "startHours": section.StartHours, + "startMinutes": section.StartMinutes, + "startSeconds": section.StartSeconds, + "fileID": section.FileID, + }) + } + return gin.H{ "lectureId": s.Model.ID, "courseId": s.CourseID, @@ -346,6 +358,7 @@ func (s Stream) getJson(lhs []LectureHall, course Course) gin.H { "courseSlug": course.Slug, "private": s.Private, "downloadableVods": s.GetVodFiles(), + "videoSections": videoSections, } } diff --git a/model/user.go b/model/user.go index 5856e127f..b526b010f 100755 --- a/model/user.go +++ b/model/user.go @@ -9,6 +9,7 @@ import ( "encoding/json" "errors" "fmt" + "sort" "strings" "time" @@ -54,6 +55,7 @@ const ( PreferredName UserSettingType = iota + 1 Greeting CustomPlaybackSpeeds + UserDefinedSpeeds ) type UserSetting struct { @@ -79,6 +81,8 @@ type PlaybackSpeedSetting struct { Enabled bool `json:"enabled"` } +type CustomSpeeds []float32 + type PlaybackSpeedSettings []PlaybackSpeedSetting func (s PlaybackSpeedSettings) GetEnabled() (res []float32) { @@ -90,6 +94,19 @@ func (s PlaybackSpeedSettings) GetEnabled() (res []float32) { return res } +func (u *User) GetEnabledPlaybackSpeeds() (res []float32) { + if u == nil { + return []float32{1} + } + // Possibly, this could be collapsed into a single line, but readibility suffers. + res = append(res, u.GetPlaybackSpeeds().GetEnabled()...) + res = append(res, u.GetCustomSpeeds()...) + sort.SliceStable(res, func(i, j int) bool { + return res[i] < res[j] + }) + return res +} + var defaultPlaybackSpeeds = PlaybackSpeedSettings{ {0.25, false}, {0.5, true}, @@ -120,6 +137,22 @@ func (u *User) GetPlaybackSpeeds() (speeds PlaybackSpeedSettings) { return defaultPlaybackSpeeds } +func (u *User) GetCustomSpeeds() (speeds CustomSpeeds) { + if u == nil { + return []float32{} + } + for _, setting := range u.Settings { + if setting.Type == UserDefinedSpeeds { + err := json.Unmarshal([]byte(setting.Value), &speeds) + if err != nil { + break + } + return speeds + } + } + return []float32{} +} + // GetPreferredGreeting returns the preferred greeting of the user if set, otherwise Moin func (u User) GetPreferredGreeting() string { for _, setting := range u.Settings { diff --git a/runner/go.mod b/runner/go.mod index 1887bf32e..568825353 100644 --- a/runner/go.mod +++ b/runner/go.mod @@ -5,6 +5,7 @@ go 1.21.0 toolchain go1.21.3 require ( + github.com/TUM-Dev/gocast/worker v0.0.0-20231228141131-d74a55aa1eee github.com/caarlos0/env v3.5.0+incompatible github.com/dusted-go/logging v1.1.1 github.com/ghodss/yaml v1.0.0 @@ -16,25 +17,27 @@ require ( github.com/sirupsen/logrus v1.9.3 golang.org/x/sync v0.3.0 google.golang.org/grpc v1.58.2 - google.golang.org/protobuf v1.31.0 + google.golang.org/protobuf v1.32.0 ) require ( - github.com/go-ole/go-ole v1.2.6 // indirect - github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect - github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/getsentry/sentry-go v0.23.0 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect + github.com/makasim/sentryhook v0.4.2 // indirect + github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/stretchr/testify v1.8.4 // indirect - github.com/tidwall/gjson v1.14.1 // indirect + github.com/tidwall/gjson v1.16.0 // indirect github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/pretty v1.2.1 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect - golang.org/x/image v0.7.0 // indirect - golang.org/x/net v0.12.0 // indirect + golang.org/x/image v0.11.0 // indirect + golang.org/x/net v0.14.0 // indirect golang.org/x/sys v0.15.0 // indirect - golang.org/x/text v0.11.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect + golang.org/x/text v0.12.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230814215434-ca7cfce7776a // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/runner/go.sum b/runner/go.sum index 2f4f75435..3c640edd3 100644 --- a/runner/go.sum +++ b/runner/go.sum @@ -1,88 +1,698 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= +github.com/CloudyKit/jet/v6 v6.1.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= +github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= +github.com/TUM-Dev/gocast/worker v0.0.0-20231228141131-d74a55aa1eee h1:m/QHUAkLA9/CZeyr25zqJlkWwfqMlYVwo4xqnLu2l0Y= +github.com/TUM-Dev/gocast/worker v0.0.0-20231228141131-d74a55aa1eee/go.mod h1:KD0M4s/B3tmlberGJvPEKrGz3VUIKTseTIH+7/SfLI0= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/caarlos0/env v3.5.0+incompatible h1:Yy0UN8o9Wtr/jGHZDpCBLpNrzcFLLM2yixi/rBrKyJs= github.com/caarlos0/env v3.5.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= +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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= +github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE= github.com/dusted-go/logging v1.1.1 h1:x1aSyarDh2iq7MIhCZkjbepsZD9FmAURK93jRFm2Oco= github.com/dusted-go/logging v1.1.1/go.mod h1:Lim3Rk6x2MYwpvPZ6XzPk6ZeX4Wgz9lVOptrL7ngr5w= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/getsentry/sentry-go v0.17.0/go.mod h1:B82dxtBvxG0KaPD8/hfSV+VcHD+Lg/xUS4JuQn1P4cM= +github.com/getsentry/sentry-go v0.23.0 h1:dn+QRCeJv4pPt9OjVXiMcGIBIefaTJPw/h0bZWO05nE= +github.com/getsentry/sentry-go v0.23.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= +github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 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 v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= +github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/icza/gox v0.0.0-20230924165045-adcb03233bb5 h1:K7KEFpKgVcjj98jOu2Z3xMBTtTwfYVT90Zmo3ZuWmbE= github.com/icza/gox v0.0.0-20230924165045-adcb03233bb5/go.mod h1:VbcN86fRkkUMPX2ufM85Um8zFndLZswoIW1eYtpAcVk= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= +github.com/iris-contrib/httpexpect/v2 v2.3.1/go.mod h1:ICTf89VBKSD3KB0fsyyHviKF8G8hyepP0dOXJPWz3T0= +github.com/iris-contrib/jade v1.1.4/go.mod h1:EDqR+ur9piDl6DUgs6qRrlfzmlx/D5UybogqrXvJTBE= +github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA= github.com/joschahenningsen/thumbgen v0.1.2 h1:sHIxmvZkuPaiiCjRvKcFNqTmH5IN4kiQiVt+wpAPC8A= github.com/joschahenningsen/thumbgen v0.1.2/go.mod h1:h8bDlQ2Bq3U/I/VlN8IRA48P7tHW8SHChVXmUWrG3bU= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kataras/blocks v0.0.6/go.mod h1:UK+Iwk0Oxpc0GdoJja7sEildotAUKK1LYeYcVF0COWc= +github.com/kataras/blocks v0.0.7/go.mod h1:UJIU97CluDo0f+zEjbnbkeMRlvYORtmc1304EeyXf4I= +github.com/kataras/golog v0.1.7/go.mod h1:jOSQ+C5fUqsNSwurB/oAHq1IFSb0KI3l6GMa7xB6dZA= +github.com/kataras/iris/v12 v12.2.0-beta5/go.mod h1:q26aoWJ0Knx/00iPKg5iizDK7oQQSPjbD8np0XDh6dc= +github.com/kataras/jwt v0.1.8/go.mod h1:Q5j2IkcIHnfwy+oNY3TVWuEBJNw0ADgCcXK9CaZwV4o= +github.com/kataras/neffos v0.0.20/go.mod h1:srdvC/Uo8mgrApWW0AYtiiLgMbyNPf69qPsd2FhE6MQ= +github.com/kataras/pio v0.0.10/go.mod h1:gS3ui9xSD+lAUpbYnjOGiQyY7sUMJO+EHpiRzhtZ5no= +github.com/kataras/pio v0.0.11/go.mod h1:38hH6SWH6m4DKSYmRhlrCJ5WItwWgCVrTNU62XZyUvI= +github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIRwuj5jA4= +github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.14.4/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= +github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a h1:N9zuLhTvBSRt0gWSiJswwQ2HqDmtX/ZCDJURnKUt1Ik= +github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailgun/raymond/v2 v2.0.46/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/makasim/sentryhook v0.4.2 h1:rqx637SCMMV5mAd9PpSg0OUIpZZaQOQZ6JHONOpUlRI= +github.com/makasim/sentryhook v0.4.2/go.mod h1:AlAU2qjpS3R9bmpfVNcCVQw1tKkH8/lOPa2RQTk8Bzw= +github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mediocregopher/radix/v3 v3.8.0/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= +github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50= +github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/nats-io/jwt/v2 v2.2.1-0.20220330180145-442af02fd36a/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= +github.com/nats-io/jwt/v2 v2.3.0/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= +github.com/nats-io/nats-server/v2 v2.8.4/go.mod h1:8zZa+Al3WsESfmgSs98Fi06dRWLH5Bnq90m5bKD/eT4= +github.com/nats-io/nats.go v1.15.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= +github.com/nats-io/nats.go v1.16.0/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w= +github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig= +github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shirou/gopsutil/v3 v3.22.8/go.mod h1:s648gW4IywYzUfE/KjXxUsqrqx/T2xO5VqOXxONeRfI= github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ= github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/assertions v1.13.0/go.mod h1:wDmR7qL282YbGsPy6H/yAsesrxfxaaSlJazyFLYVFx8= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +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.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tdewolff/minify/v2 v2.12.1/go.mod h1:p5pwbvNs1ghbFED/ZW1towGsnnWwzvM8iz8l0eURi9g= +github.com/tdewolff/minify/v2 v2.12.4/go.mod h1:h+SRvSIX3kwgwTFOpSckvSxgax3uy8kZTSF1Ojrr3bk= +github.com/tdewolff/parse/v2 v2.6.3/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs= +github.com/tdewolff/parse/v2 v2.6.4/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs= +github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo= github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.16.0 h1:SyXa+dsSPpUlcwEDuKuEBJEz5vzTvOea+9rjyYodQFg= +github.com/tidwall/gjson v1.16.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw= golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg= +golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo= +golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= @@ -93,30 +703,231 @@ golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230814215434-ca7cfce7776a h1:5rTPHLf5eLPfqGvw3fLpEmUpko2Ky91ft14LxGs5BZc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230814215434-ca7cfce7776a/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I= google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/runner/runner.go b/runner/runner.go index 3d992afa8..c029aa1db 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -32,7 +32,7 @@ type envConfig struct { RecPath string `env:"REC_PATH" envDefault:"storage/rec"` GocastServer string `env:"GOCAST_SERVER" envDefault:"localhost:50056"` Hostname string `env:"REALHOST" envDefault:"localhost"` - Version string `env:"VERSION" envDefault:"v0.0.0"` + Version string `env:"VERSION" envDefault:"dev"` } type Runner struct { diff --git a/tools/bot/bot.go b/tools/bot/bot.go index 572e448e8..87272a37a 100644 --- a/tools/bot/bot.go +++ b/tools/bot/bot.go @@ -1,11 +1,10 @@ package bot import ( - "github.com/getsentry/sentry-go" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" + "github.com/getsentry/sentry-go" "github.com/microcosm-cc/bluemonday" - log "github.com/sirupsen/logrus" "strings" "time" ) @@ -147,7 +146,7 @@ func hasPrio(streamID uint, statsDao dao.StatisticsDao) bool { liveViewers, err := statsDao.GetStreamNumLiveViews(streamID) if err != nil { sentry.CaptureException(err) - log.WithError(err).Error("Failed to get current live viewers") + logger.Error("Failed to get current live viewers", "err", err) return false } diff --git a/tools/bot/bot_logger.go b/tools/bot/bot_logger.go new file mode 100644 index 000000000..8af169b64 --- /dev/null +++ b/tools/bot/bot_logger.go @@ -0,0 +1,10 @@ +package bot + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "bot") diff --git a/tools/bot/matrix.go b/tools/bot/matrix.go index 0bd8e8e2d..f1e81f7ed 100644 --- a/tools/bot/matrix.go +++ b/tools/bot/matrix.go @@ -5,9 +5,8 @@ import ( "encoding/json" "errors" "fmt" - "github.com/getsentry/sentry-go" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" "io" "math/rand" "net/http" @@ -74,14 +73,14 @@ func (m *Matrix) getClientUrl() string { func (m *Matrix) SendBotMessage(message Message) error { err := m.sendMessageToRoom(tools.Cfg.Alerts.Matrix.LogRoomID, message) if err != nil { - log.WithError(err).Error("Failed to send message to matrix log room") + logger.Error("Failed to send message to matrix log room", "err", err) sentry.CaptureException(err) return err } if message.Prio { err = m.sendMessageToRoom(tools.Cfg.Alerts.Matrix.AlertRoomID, message) if err != nil { - log.WithError(err).Error("Failed to send message to matrix alert room") + logger.Error("Failed to send message to matrix alert room", "err", err) sentry.CaptureException(err) } } diff --git a/tools/branding.go b/tools/branding.go index 644e4c349..5abd222c9 100644 --- a/tools/branding.go +++ b/tools/branding.go @@ -2,7 +2,6 @@ package tools import ( "fmt" - log "github.com/sirupsen/logrus" "github.com/spf13/viper" ) @@ -38,7 +37,7 @@ func InitBranding() { err := v.ReadInConfig() if err == nil { err = v.Unmarshal(&branding) - log.Info("Using branding.yaml.") + logger.Info("Using branding.yaml.") if err != nil { panic(fmt.Errorf("fatal error branding file: %v", err)) } diff --git a/tools/camera/camera_logger.go b/tools/camera/camera_logger.go new file mode 100644 index 000000000..ba5b22c5d --- /dev/null +++ b/tools/camera/camera_logger.go @@ -0,0 +1,10 @@ +package camera + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "camera") diff --git a/tools/camera/panasonic.go b/tools/camera/panasonic.go index 65864c6d7..27c0ab10a 100644 --- a/tools/camera/panasonic.go +++ b/tools/camera/panasonic.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/TUM-Dev/gocast/model" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" ) /** @@ -18,21 +17,21 @@ import ( const panasonicBaseUrl = "http://%s/cgi-bin" -//PanasonicCam represents Panasonic IP cameras the TUM uses +// PanasonicCam represents Panasonic IP cameras the TUM uses type PanasonicCam struct { Ip string Auth *string // currently unused as our cams have auth deactivated for PTZ operation } -//NewPanasonicCam Acts as a constructor for cameras. -//ip: the ip address of the camera -//auth: username and password of the camera (e.g. "user:password") +// NewPanasonicCam Acts as a constructor for cameras. +// ip: the ip address of the camera +// auth: username and password of the camera (e.g. "user:password") func NewPanasonicCam(ip string, auth *string) *PanasonicCam { return &PanasonicCam{Ip: ip, Auth: auth} } func (c PanasonicCam) TakeSnapshot(outDir string) (filename string, err error) { - log.Info(fmt.Sprintf("%s/view.cgi?action=snapshot", fmt.Sprintf(panasonicBaseUrl, c.Ip))) + logger.Info(fmt.Sprintf("%s/view.cgi?action=snapshot", fmt.Sprintf(panasonicBaseUrl, c.Ip))) resp, err := makeAuthenticatedRequest(c.Auth, "GET", "", fmt.Sprintf("%s/view.cgi?action=snapshot", fmt.Sprintf(panasonicBaseUrl, c.Ip))) if err != nil { return "", err @@ -45,13 +44,13 @@ func (c PanasonicCam) TakeSnapshot(outDir string) (filename string, err error) { return filename, nil } -//SetPreset tells the camera to use a preset specified by presetId +// SetPreset tells the camera to use a preset specified by presetId func (c PanasonicCam) SetPreset(presetId int) error { _, err := makeAuthenticatedRequest(c.Auth, "GET", "", fmt.Sprintf("%s/camctrl?preset=%d", fmt.Sprintf(panasonicBaseUrl, c.Ip), presetId)) return err } -//GetPresets fetches all presets stored on the camera +// GetPresets fetches all presets stored on the camera func (c PanasonicCam) GetPresets() ([]model.CameraPreset, error) { // panasonic cameras come with 100 slots for presets. These are always present but usually only a few are configured. // we therefore just return 10 stubs here. diff --git a/tools/config.go b/tools/config.go index c7639690f..145fd3cad 100644 --- a/tools/config.go +++ b/tools/config.go @@ -9,7 +9,6 @@ import ( "fmt" "github.com/meilisearch/meilisearch-go" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "github.com/spf13/viper" "os" "time" @@ -23,7 +22,7 @@ func LoadConfig() { var err error Loc, err = time.LoadLocation("Europe/Berlin") if err != nil { - log.WithError(err).Error("tools.config.LoadConfig: can't get time.location") + logger.Error("tools.config.LoadConfig: can't get time.location", "err", err) } initConfig() } @@ -39,12 +38,12 @@ func initConfig() { err := viper.ReadInConfig() if err != nil { if errors.Is(err, viper.ConfigFileNotFoundError{}) { - log.WithError(err).Warn("tools.config.LoadConfig: can't find config file") + logger.Warn("tools.config.LoadConfig: can't find config file", "err", err) } else { panic(fmt.Errorf("fatal error config file: %v", err)) } } - log.Info("Using Config file ", viper.ConfigFileUsed()) + logger.Info("Using Config file " + viper.ConfigFileUsed()) err = viper.Unmarshal(&Cfg) if err != nil { panic(fmt.Errorf("fatal error config file: %v", err)) @@ -56,14 +55,14 @@ func initConfig() { viper.Set("workerToken", Cfg.WorkerToken) err = viper.WriteConfig() if err != nil { - log.Warn("Can't write out config ", err) + logger.Warn("Can't write out config ", "err", err) } } if Cfg.JWTKey == nil { - log.Info("Generating new JWT key") + logger.Info("Generating new JWT key") JWTKey, err := rsa.GenerateKey(rand.Reader, rsaKeySize) if err != nil { - log.WithError(err).Fatal("Can't generate JWT key") + logger.Error("Can't generate JWT key", "err", err) } armoured := string(pem.EncodeToMemory( &pem.Block{ @@ -74,14 +73,14 @@ func initConfig() { viper.Set("jwtKey", armoured) err = viper.WriteConfig() if err != nil { - log.Warn("Can't write out config ", err) + logger.Warn("Can't write out config ", "err", err) } jwtKey = JWTKey } else { k, _ := pem.Decode([]byte(*Cfg.JWTKey)) key, err := x509.ParsePKCS1PrivateKey(k.Bytes) if err != nil { - log.WithError(err).Fatal("Can't parse JWT key") + logger.Error("Can't parse JWT key", "err", err) return } jwtKey = key diff --git a/tools/email.go b/tools/email.go index 02700d7e9..270f959f1 100644 --- a/tools/email.go +++ b/tools/email.go @@ -5,7 +5,6 @@ import ( "context" "fmt" "github.com/TUM-Dev/gocast/dao" - "log" "net/smtp" "os/exec" "strings" @@ -33,7 +32,7 @@ func (m *Mailer) Run() { lastRun = time.Now() emails, err := m.Dao.EmailDao.GetDue(context.Background(), m.MaxMailsPerMinute) if err != nil { - log.Printf("error getting due emails: %v", err) + logger.Error("error getting due emails", "err", err) continue } for _, email := range emails { @@ -47,7 +46,7 @@ func (m *Mailer) Run() { } err = m.Dao.EmailDao.Save(context.Background(), &email) if err != nil { - log.Printf("error saving email: %v", err) + logger.Error("error saving email", "err", err) } sleepDur := time.Duration(1000 * (60 / m.MaxMailsPerMinute)) @@ -57,7 +56,7 @@ func (m *Mailer) Run() { } func (m *Mailer) sendMail(addr, from, subject, body string, to []string) error { - log.Printf("sending mail to %v, subject: %s body:\n%s", to, subject, body) + logger.Info("sending mail", "to", to, "subject", subject, "body", body) r := strings.NewReplacer("\r\n", "", "\r", "", "\n", "", "%0a", "", "%0d", "") signed, err := openssl([]byte(body), "smime", "-text", "-sign", "-signer", Cfg.Mail.SMIMECert, "-inkey", Cfg.Mail.SMIMEKey) diff --git a/tools/meiliExporter.go b/tools/meiliExporter.go index 2fbd595e6..d72da9833 100644 --- a/tools/meiliExporter.go +++ b/tools/meiliExporter.go @@ -3,10 +3,9 @@ package tools import ( "errors" "fmt" - "github.com/asticode/go-astisub" "github.com/TUM-Dev/gocast/dao" + "github.com/asticode/go-astisub" "github.com/meilisearch/meilisearch-go" - log "github.com/sirupsen/logrus" "strings" ) @@ -39,7 +38,7 @@ func NewMeiliExporter(d dao.DaoWrapper) *MeiliExporter { if err != nil && errors.Is(err, ErrMeiliNotConfigured) { return nil } else if err != nil { - log.WithError(err).Error("could not get meili client") + logger.Error("could not get meili client", "err", err) return nil } @@ -53,7 +52,7 @@ func (m *MeiliExporter) Export() { index := m.c.Index("STREAMS") _, err := m.c.Index("SUBTITLES").DeleteAllDocuments() if err != nil { - log.WithError(err).Warn("could not delete all old subtitles") + logger.Warn("could not delete all old subtitles", "err", err) } m.d.StreamsDao.ExecAllStreamsWithCoursesAndSubtitles(func(streams []dao.StreamWithCourseAndSubtitles) { @@ -75,7 +74,7 @@ func (m *MeiliExporter) Export() { vtt, err := astisub.ReadFromWebVTT(strings.NewReader(stream.Subtitles)) if err != nil { - log.WithError(err).Warn("could not parse subtitles") + logger.Warn("could not parse subtitles", "err", err) continue } for i, _ := range vtt.Items { @@ -96,14 +95,14 @@ func (m *MeiliExporter) Export() { if len(meiliSubtitles) > 0 { _, err := m.c.Index("SUBTITLES").AddDocuments(&meiliSubtitles, "ID") if err != nil { - log.WithError(err).Error("issue adding subtitles to meili") + logger.Error("issue adding subtitles to meili", "err", err) } } } } _, err := index.AddDocuments(&meilistreams, "ID") if err != nil { - log.WithError(err).Error("issue adding documents to meili") + logger.Error("issue adding documents to meili", "err", err) } }) @@ -120,7 +119,7 @@ func (m *MeiliExporter) SetIndexSettings() { } _, err := index.UpdateSynonyms(&synonyms) if err != nil { - log.WithError(err).Error("could not set synonyms for meili index STREAMS") + logger.Error("could not set synonyms for meili index STREAMS", "err", err) } _, err = m.c.Index("SUBTITLES").UpdateSettings(&meilisearch.Settings{ @@ -129,6 +128,6 @@ func (m *MeiliExporter) SetIndexSettings() { SortableAttributes: []string{"timestamp"}, }) if err != nil { - log.WithError(err).Warn("could not set settings for meili index SUBTITLES") + logger.Warn("could not set settings for meili index SUBTITLES", "err", err) } } diff --git a/tools/meiliSearch.go b/tools/meiliSearch.go index 9b3b8a035..4770dfae1 100644 --- a/tools/meiliSearch.go +++ b/tools/meiliSearch.go @@ -3,7 +3,6 @@ package tools import ( "fmt" "github.com/meilisearch/meilisearch-go" - log "github.com/sirupsen/logrus" ) func SearchSubtitles(q string, streamID uint) *meilisearch.SearchResponse { @@ -16,7 +15,7 @@ func SearchSubtitles(q string, streamID uint) *meilisearch.SearchResponse { Limit: 10, }) if err != nil { - log.WithError(err).Error("could not search meili") + logger.Error("could not search meili", "err", err) return nil } return response diff --git a/tools/middlewares.go b/tools/middlewares.go index b523ba213..dee069940 100644 --- a/tools/middlewares.go +++ b/tools/middlewares.go @@ -2,13 +2,12 @@ package tools import ( "errors" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" - "github.com/golang-jwt/jwt/v4" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools/realtime" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" + "github.com/golang-jwt/jwt/v4" "net/http" "net/url" "strconv" @@ -50,13 +49,13 @@ func InitContext(daoWrapper dao.DaoWrapper) gin.HandlerFunc { return key, nil }) if err != nil { - log.Info("JWT parsing error: ", err) + logger.Info("JWT parsing error: ", "err", err) c.Set("TUMLiveContext", TUMLiveContext{}) c.SetCookie("jwt", "", -1, "/", "", false, true) return } if !token.Valid { - log.Info("JWT token is not valid") + logger.Info("JWT token is not valid") c.Set("TUMLiveContext", TUMLiveContext{}) c.SetCookie("jwt", "", -1, "/", "", false, true) return @@ -90,7 +89,7 @@ func RenderErrorPage(c *gin.Context, status int, message string) { Branding: BrandingCfg, }) if err != nil { - log.Error(err) + logger.Error("Error on executing template error.gohtml", "err", err) } c.Abort() } @@ -371,7 +370,7 @@ func AdminToken(daoWrapper dao.DaoWrapper) gin.HandlerFunc { } err = daoWrapper.TokenDao.TokenUsed(t) if err != nil { - log.WithError(err).Warn("error marking token as used") + logger.Warn("error marking token as used", "err", err) return } } diff --git a/tools/presets.go b/tools/presets.go index 317725ec0..b0d3f8647 100644 --- a/tools/presets.go +++ b/tools/presets.go @@ -3,11 +3,10 @@ package tools import ( "context" "errors" - "github.com/getsentry/sentry-go" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools/camera" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" "time" ) @@ -39,7 +38,7 @@ func (p presetUtility) ProvideCamera(ctype model.CameraType, ip string) (camera. return nil, errors.New("invalid camera type") } -//FetchCameraPresets Queries all cameras of lecture halls for their camera presets and saves them to the database +// FetchCameraPresets Queries all cameras of lecture halls for their camera presets and saves them to the database func (p presetUtility) FetchCameraPresets(ctx context.Context) { span := sentry.StartSpan(ctx, "FetchCameraPresets") defer span.Finish() @@ -53,12 +52,12 @@ func (p presetUtility) FetchLHPresets(lectureHall model.LectureHall) { if lectureHall.CameraIP != "" { cam, err := p.ProvideCamera(lectureHall.CameraType, lectureHall.CameraIP) if err != nil { - log.WithError(err) + logger.Error("Error providing camera", "err", err) return } presets, err := cam.GetPresets() if err != nil { - log.WithError(err).WithField("AxisCam", lectureHall.CameraIP).Warn("FetchCameraPresets: failed to get Presets") + logger.Warn("FetchCameraPresets: failed to get Presets", "err", err, "AxisCam", lectureHall.CameraIP) return } /*for i := range presets { @@ -78,17 +77,17 @@ func (p presetUtility) UsePreset(preset model.CameraPreset) { } cam, err := p.ProvideCamera(lectureHall.CameraType, lectureHall.CameraIP) if err != nil { - log.WithError(err) + logger.Error("Error providing camera", "err", err) return } err = cam.SetPreset(preset.PresetID) if err != nil { - log.WithError(err).Error("UsePreset: unable to set preset for camera") + logger.Error("UsePreset: unable to set preset for camera", "err", err) } } -//TakeSnapshot Creates an image for a preset. Saves it to the disk and database. -//Function is blocking and needs ~20 Seconds to complete! Only call in goroutine. +// TakeSnapshot Creates an image for a preset. Saves it to the disk and database. +// Function is blocking and needs ~20 Seconds to complete! Only call in goroutine. func (p presetUtility) TakeSnapshot(preset model.CameraPreset) { p.UsePreset(preset) time.Sleep(time.Second * 10) @@ -99,18 +98,18 @@ func (p presetUtility) TakeSnapshot(preset model.CameraPreset) { } cam, err := p.ProvideCamera(lectureHall.CameraType, lectureHall.CameraIP) if err != nil { - log.WithError(err) + logger.Error("Error providing camera", "err", err) return } fileName, err := cam.TakeSnapshot(Cfg.Paths.Static) if err != nil { - log.WithField("cam", lectureHall.CameraIP).WithError(err).Error("TakeSnapshot: failed to get camera snapshot") + logger.Error("TakeSnapshot: failed to get camera snapshot", "err", err, "cam", lectureHall.CameraIP) return } preset.Image = fileName err = p.LectureHallDao.SavePreset(preset) if err != nil { - log.WithField("cam", lectureHall.CameraIP).WithError(err).Error("TakeSnapshot: failed to save snapshot file") + logger.Error("TakeSnapshot: failed to save snapshot file", "err", err, "cam", lectureHall.CameraIP) return } } diff --git a/tools/realtime/channel_store.go b/tools/realtime/channel_store.go index 9ed1abf71..eebc67c62 100644 --- a/tools/realtime/channel_store.go +++ b/tools/realtime/channel_store.go @@ -1,7 +1,6 @@ package realtime import ( - log "github.com/sirupsen/logrus" "strings" ) @@ -45,7 +44,7 @@ func (s *ChannelStore) OnMessage(client *Client, message *Message) { return } - log.WithField("channel", message.Channel).Warn("unknown channel on websocket message") + logger.Warn("unknown channel on websocket message", "channel", message.Channel) } func (s *ChannelStore) Subscribe(client *Client, channelPath string) bool { diff --git a/tools/realtime/realtime.go b/tools/realtime/realtime.go index 4b44e3da7..da4372e46 100644 --- a/tools/realtime/realtime.go +++ b/tools/realtime/realtime.go @@ -3,7 +3,6 @@ package realtime import ( "encoding/json" "errors" - log "github.com/sirupsen/logrus" "net/http" ) @@ -86,7 +85,7 @@ func (r *Realtime) messageHandler(c *Client, msg []byte) { var req Message err := json.Unmarshal(msg, &req) if err != nil { - log.WithError(err).Warn("could not unmarshal request") + logger.Warn("could not unmarshal request", "err", err) return } @@ -98,6 +97,6 @@ func (r *Realtime) messageHandler(c *Client, msg []byte) { case MessageTypeChannelMessage: r.channels.OnMessage(c, &req) default: - log.WithField("type", req.Type).Warn("unknown pubsub websocket request type") + logger.Warn("unknown pubsub websocket request type", "type", req.Type) } } diff --git a/tools/realtime/realtime_logger.go b/tools/realtime/realtime_logger.go new file mode 100644 index 000000000..229f391e2 --- /dev/null +++ b/tools/realtime/realtime_logger.go @@ -0,0 +1,10 @@ +package realtime + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "realtime") diff --git a/tools/session.go b/tools/session.go index 9231cc794..2d8112010 100644 --- a/tools/session.go +++ b/tools/session.go @@ -3,8 +3,6 @@ package tools import ( "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v4" - log "github.com/sirupsen/logrus" - "time" ) @@ -16,7 +14,7 @@ type SessionData struct { func StartSession(c *gin.Context, data *SessionData) { token, err := createToken(data.Userid, data.SamlSubjectID) if err != nil { - log.WithError(err).Error("Could not create token") + logger.Error("Could not create token", "err", err) return } c.SetCookie("jwt", token, 60*60*24*7, "/", "", CookieSecure, true) diff --git a/tools/template_executor.go b/tools/template_executor.go index f0aa4e6ad..cfc62c5f4 100644 --- a/tools/template_executor.go +++ b/tools/template_executor.go @@ -2,7 +2,6 @@ package tools import ( "github.com/Masterminds/sprig/v3" - log "github.com/sirupsen/logrus" "html/template" "io" ) @@ -22,14 +21,14 @@ func (e DebugTemplateExecutor) ExecuteTemplate(w io.Writer, name string, data in var t, err = template.New("base").Funcs(sprig.FuncMap()).ParseGlob(e.Patterns[0]) if err != nil { - log.Print("Failed to load pattern: '" + e.Patterns[0] + "'. Error: " + err.Error()) + logger.Error("Failed to load pattern: '"+e.Patterns[0], "err", err.Error()) } for i := 1; i < len(e.Patterns); i++ { pattern := e.Patterns[i] _, err := t.ParseGlob(pattern) if err != nil { - log.Print("Failed to load pattern: '" + pattern + "'. Error: " + err.Error()) + logger.Error("Failed to load pattern: '"+pattern+"'.", "err", err.Error()) } } diff --git a/tools/tools_logger.go b/tools/tools_logger.go new file mode 100644 index 000000000..d5f0d766d --- /dev/null +++ b/tools/tools_logger.go @@ -0,0 +1,10 @@ +package tools + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "tools") diff --git a/tools/tum/campus-online-base.go b/tools/tum/campus-online-base.go index b990327e0..7cb8c63b4 100644 --- a/tools/tum/campus-online-base.go +++ b/tools/tum/campus-online-base.go @@ -4,10 +4,9 @@ import ( "context" "errors" "fmt" - "github.com/antchfx/xmlquery" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/antchfx/xmlquery" ) func GetCourseInformation(courseID string, token string) (CourseInfo, error) { @@ -34,7 +33,7 @@ func FetchCourses(daoWrapper dao.DaoWrapper) func() { y, t := GetCurrentSemester() courses, err := daoWrapper.CoursesDao.GetAllCoursesWithTUMIDFromSemester(context.Background(), y, t) if err != nil { - log.WithError(err).Error("Could not get courses with TUM online identifier:", err) + logger.Error("Could not get courses with TUM online identifier:", "err", err) return } FindStudentsForCourses(courses, daoWrapper.UsersDao) diff --git a/tools/tum/courses.go b/tools/tum/courses.go index 9d0b731e5..93ecc870b 100644 --- a/tools/tum/courses.go +++ b/tools/tum/courses.go @@ -7,7 +7,6 @@ import ( "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model/search" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" "strconv" "strings" ) @@ -17,7 +16,7 @@ func PrefetchCourses(dao dao.DaoWrapper) func() { return func() { client, err := tools.Cfg.GetMeiliClient() if err != nil { - log.Info("Skipping course prefetching, reason: ", err) + logger.Info("Skipping course prefetching, reason: ", "err", err) return } @@ -28,16 +27,16 @@ func PrefetchCourses(dao dao.DaoWrapper) func() { for _, org := range *tools.Cfg.Campus.RelevantOrgs { r, err := getCoursesForOrg(org) if err != nil { - log.Error(err) + logger.Error("Error getting courses for organisation "+org, "err", err) } else { res = append(res, r...) } } index := client.Index("PREFETCHED_COURSES") _, err = index.AddDocuments(&res, "courseID") - log.Info(len(res)) + logger.Info(string(rune(len(res)))) if err != nil { - log.WithError(err).Error("issue adding documents to meili") + logger.Error("issue adding documents to meili", "err", err) } } } diff --git a/tools/tum/events.go b/tools/tum/events.go index f56b83f3b..e61eaab2b 100644 --- a/tools/tum/events.go +++ b/tools/tum/events.go @@ -4,12 +4,11 @@ import ( "context" "errors" "fmt" - "github.com/antchfx/xmlquery" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" + "github.com/antchfx/xmlquery" uuid "github.com/satori/go.uuid" - log "github.com/sirupsen/logrus" "strconv" "strings" "time" @@ -32,12 +31,12 @@ func getEventsForCourse(courseID string, token string) (events map[time.Time]Eve start, timeErr1 := time.ParseInLocation("20060102T150405", xmlquery.FindOne(event, "//cor:attribute[@cor:attrID='dtstart']").InnerText(), tools.Loc) end, timeErr2 := time.ParseInLocation("20060102T150405", xmlquery.FindOne(event, "//cor:attribute[@cor:attrID='dtend']").InnerText(), tools.Loc) if timeErr1 != nil || timeErr2 != nil { - log.WithFields(log.Fields{"timeErr1": timeErr1, "timeErr2": timeErr2}).Warn("getEventsForCourse: couldn't parse time") + logger.Warn("getEventsForCourse: couldn't parse time", "timeErr1", timeErr1, "timeErr2", timeErr2) break } eventID64, err := strconv.Atoi(xmlquery.FindOne(event, "//cor:attribute[@cor:attrID='singleEventID']").InnerText()) if err != nil { - log.WithField("TUMOnlineCourseID", courseID).WithError(err).Error("getEventsForCourse: EventID not an int") + logger.Error("getEventsForCourse: EventID not an int", "err", err, "TUMOnlineCourseID", courseID) break } var eventTypeName, status, roomCode, roomName string @@ -91,7 +90,7 @@ func GetEventsForCourses(courses []model.Course, daoWrapper dao.DaoWrapper) { for _, event := range events { stream, err := daoWrapper.StreamsDao.GetStreamByTumOnlineID(context.Background(), event.SingleEventID) if err != nil { // Lecture does not exist yet - log.Info("Adding course") + logger.Info("Adding course") course.Streams = append(course.Streams, model.Stream{ CourseID: course.ID, Start: event.Start, @@ -114,7 +113,7 @@ func GetEventsForCourses(courses []model.Course, daoWrapper dao.DaoWrapper) { } err = daoWrapper.CoursesDao.UpdateCourse(context.Background(), course) if err != nil { - log.WithError(err).WithField("CourseID", course.ID).Warn("Can't update course") + logger.Warn("Can't update course", "err", err, "CourseID", course.ID) } } } diff --git a/tools/tum/students.go b/tools/tum/students.go index 127cb3bf9..f8def6ff8 100644 --- a/tools/tum/students.go +++ b/tools/tum/students.go @@ -3,11 +3,10 @@ package tum import ( "errors" "fmt" - "github.com/antchfx/xmlquery" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/antchfx/xmlquery" ) func FindStudentsForCourses(courses []model.Course, usersDao dao.UsersDao) { @@ -21,12 +20,12 @@ func FindStudentsForCourses(courses []model.Course, usersDao dao.UsersDao) { } } if err != nil { - log.WithError(err).WithField("TUMOnlineIdentifier", courses[i].TUMOnlineIdentifier).Error("FindStudentsForCourses: Can't get Students for course with id") + logger.Error("FindStudentsForCourses: Can't get Students for course with id", "err", err, "TUMOnlineIdentifier", courses[i].TUMOnlineIdentifier) continue } err = usersDao.AddUsersToCourseByTUMIDs(studentIDs, courses[i].ID) if err != nil { - log.WithError(err).Error("FindStudentsForCourses: Can't add users to course") + logger.Error("FindStudentsForCourses: Can't add users to course", "err", err) } } } diff --git a/tools/tum/tum_logger.go b/tools/tum/tum_logger.go new file mode 100644 index 000000000..a7a83d01d --- /dev/null +++ b/tools/tum/tum_logger.go @@ -0,0 +1,10 @@ +package tum + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "tum") diff --git a/vod-service/internal/internal_logger.go b/vod-service/internal/internal_logger.go new file mode 100644 index 000000000..15ff05489 --- /dev/null +++ b/vod-service/internal/internal_logger.go @@ -0,0 +1,10 @@ +package internal + +import ( + "log/slog" + "os" +) + +var logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, +})).With("service", "internal_vod_service") diff --git a/vod-service/internal/vodService.go b/vod-service/internal/vodService.go index 176a36a76..fdad7827e 100644 --- a/vod-service/internal/vodService.go +++ b/vod-service/internal/vodService.go @@ -3,7 +3,6 @@ package internal import ( "fmt" "io" - "log" "net/http" "os" "os/exec" @@ -22,7 +21,7 @@ type App struct { func NewApp() *App { outputDir := os.Getenv("OUTPUT_DIR") if outputDir == "" { - log.Fatal("OUTPUT_DIR environment variable not set.") + logger.Error("OUTPUT_DIR environment variable not set.") } if !strings.HasSuffix(outputDir, "/") { outputDir += "/" @@ -67,7 +66,7 @@ func (a *App) uploadHandler(w http.ResponseWriter, r *http.Request) { _, err = io.Copy(tempFile, file) if err != nil { - log.Println(err) + logger.Error("Error on io copy", "err", err) return } // write this byte array to our temporary file @@ -82,19 +81,19 @@ func (a *App) packageFile(file, name string) { defer func() { err := os.Remove(file) if err != nil { - log.Printf("Error cleaning up file: %v", err) + logger.Error("Error cleaning up file", "err", err) } }() name = fileNameIllegal.ReplaceAllString(name, "_") // override eventually existing files err := os.RemoveAll(a.config.outputDir + name) if err != nil { - log.Println(err) + logger.Error("Error on removing files", "err", err) // try to continue anyway } err = os.MkdirAll(a.config.outputDir+name, os.ModePerm) if err != nil { - log.Println(err) + logger.Error("Error on creating directories", "err", err) return } c := exec.Command("ffmpeg", diff --git a/web/admin.go b/web/admin.go index 784eda827..804c15a27 100755 --- a/web/admin.go +++ b/web/admin.go @@ -11,7 +11,6 @@ import ( "github.com/TUM-Dev/gocast/tools/tum" "github.com/getsentry/sentry-go" "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" "gorm.io/gorm" "net/http" "regexp" @@ -34,7 +33,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { _ = r.UsersDao.GetAllAdminsAndLecturers(&users) courses, err := r.CoursesDao.GetAdministeredCoursesByUserId(context.Background(), tumLiveContext.User.ID, "", 0) if err != nil { - log.WithError(err).Error("couldn't query courses for user.") + logger.Error("couldn't query courses for user.", "err", err) courses = []model.Course{} } workers, err := r.WorkerDao.GetAllWorkers() @@ -81,7 +80,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { page = "notifications" found, err := r.NotificationsDao.GetAllNotifications() if err != nil { - log.WithError(err).Error("couldn't query notifications") + logger.Error("couldn't query notifications", "err", err) } else { notifications = found } @@ -91,7 +90,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { page = "token" tokens, err = r.TokenDao.GetAllTokens() if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - log.WithError(err).Error("couldn't query tokens") + logger.Error("couldn't query tokens", "err", err) c.AbortWithStatus(http.StatusInternalServerError) } } @@ -100,7 +99,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { page = "info-pages" infopages, err = r.InfoPageDao.GetAll() if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - log.WithError(err).Error("couldn't query texts") + logger.Error("couldn't query texts", "err", err) c.AbortWithStatus(http.StatusInternalServerError) } } @@ -108,7 +107,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { page = "serverStats" streams, err := r.StreamsDao.GetAllStreams() if err != nil { - log.WithError(err).Error("Can't get all streams") + logger.Error("Can't get all streams", "err", err) sentry.CaptureException(err) streams = []model.Stream{} } @@ -123,7 +122,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { if res, err := r.ServerNotificationDao.GetAllServerNotifications(); err == nil { serverNotifications = res } else { - log.WithError(err).Warn("could not get all server notifications") + logger.Warn("could not get all server notifications", "err", err) } } semesters := r.CoursesDao.GetAvailableSemesters(c) @@ -145,7 +144,7 @@ func (r mainRoutes) AdminPage(c *gin.Context) { Runners: RunnersData{Runners: runners}, }) if err != nil { - log.Printf("%v", err) + logger.Error("Error executing template admin.gohtml", "err", err) } } @@ -167,7 +166,7 @@ func (r mainRoutes) LectureCutPage(c *gin.Context) { } tumLiveContext := foundContext.(tools.TUMLiveContext) if err := templateExecutor.ExecuteTemplate(c.Writer, "lecture-cut.gohtml", tumLiveContext); err != nil { - log.Fatalln(err) + logger.Error("Error executing template lecture-cut.gohtml", "err", err) } } @@ -202,7 +201,7 @@ func (r mainRoutes) CourseStatsPage(c *gin.Context) { indexData.TUMLiveContext = tumLiveContext courses, err := r.CoursesDao.GetAdministeredCoursesByUserId(context.Background(), tumLiveContext.User.ID, "", 0) if err != nil { - log.Printf("couldn't query courses for user. %v\n", err) + logger.Error("couldn't query courses for user.", "err", err) courses = []model.Course{} } semesters := r.CoursesDao.GetAvailableSemesters(c) @@ -215,7 +214,7 @@ func (r mainRoutes) CourseStatsPage(c *gin.Context) { CurT: tumLiveContext.Course.TeachingTerm, }) if err != nil { - log.Printf("%v\n", err) + logger.Error("Error getting available semesters", "err", err) } } @@ -230,20 +229,20 @@ func (r mainRoutes) EditCoursePage(c *gin.Context) { lectureHalls := r.LectureHallsDao.GetAllLectureHalls() err := r.CoursesDao.GetInvitedUsersForCourse(tumLiveContext.Course) if err != nil { - log.Printf("%v", err) + logger.Error("Error getting invited users for course", "err", err) } indexData := NewIndexData() indexData.TUMLiveContext = tumLiveContext courses, err := r.CoursesDao.GetAdministeredCoursesByUserId(context.Background(), tumLiveContext.User.ID, "", 0) if err != nil { - log.Printf("couldn't query courses for user. %v\n", err) + logger.Error("couldn't query courses for user.", "err", err) courses = []model.Course{} } semesters := r.CoursesDao.GetAvailableSemesters(c) for i := range tumLiveContext.Course.Streams { err := tools.SetSignedPlaylists(&tumLiveContext.Course.Streams[i], tumLiveContext.User, true) if err != nil { - log.WithError(err).Error("could not set signed playlist for admin page") + logger.Error("could not set signed playlist for admin page", "err", err) } } err = templateExecutor.ExecuteTemplate(c.Writer, "admin.gohtml", AdminPageData{ @@ -256,7 +255,7 @@ func (r mainRoutes) EditCoursePage(c *gin.Context) { EditCourseData: EditCourseData{IndexData: indexData, IngestBase: tools.Cfg.IngestBase, LectureHalls: lectureHalls}, }) if err != nil { - log.Printf("%v\n", err) + logger.Error("Error executing template admin.gohtml", "err", err) } } diff --git a/web/assets/css/main.css b/web/assets/css/main.css index 4e42a218e..56d5f0612 100644 --- a/web/assets/css/main.css +++ b/web/assets/css/main.css @@ -185,6 +185,11 @@ label:has(~ .tl-input), label:has(~.tl-textarea) { background-color: #3070b3 !important; } +/* Ensure that the mouse pointing time is displayed above the playback progress */ +.video-js .vjs-mouse-display { + z-index: 2 !important; +} + .video-js .vjs-big-play-button { @apply absolute top-0 left-0 bottom-0 right-0 m-auto; } diff --git a/web/assets/init-admin.js b/web/assets/init-admin.js index 172d2513d..3230042c6 100644 --- a/web/assets/init-admin.js +++ b/web/assets/init-admin.js @@ -15,6 +15,8 @@ document.addEventListener("alpine:init", () => { 'color' ]; + const nativeEventName = "csupdate"; + const convert = (modifiers, value) => { if (modifiers.includes("int")) { return parseInt(value); @@ -79,7 +81,6 @@ document.addEventListener("alpine:init", () => { Alpine.directive("bind-change-set", (el, { expression, value, modifiers }, { evaluate, cleanup }) => { const changeSet = evaluate(expression); const fieldName = value || el.name; - const nativeEventName = "csupdate"; if (el.type === "file") { const isSingle = modifiers.includes("single") @@ -92,7 +93,7 @@ document.addEventListener("alpine:init", () => { if (!data[fieldName]) { el.value = ""; } - el.dispatchEvent(new CustomEvent(nativeEventName, { detail: data[fieldName] })); + el.dispatchEvent(new CustomEvent(nativeEventName, {detail: {changeSet, value: data[fieldName]}})); }; changeSet.listen(onChangeSetUpdateHandler); @@ -109,7 +110,7 @@ document.addEventListener("alpine:init", () => { const onChangeSetUpdateHandler = (data) => { el.checked = !!data[fieldName]; - el.dispatchEvent(new CustomEvent(nativeEventName, { detail: !!data[fieldName] })); + el.dispatchEvent(new CustomEvent(nativeEventName, {detail: {changeSet, value: !!data[fieldName]}})); }; changeSet.listen(onChangeSetUpdateHandler); @@ -122,26 +123,29 @@ document.addEventListener("alpine:init", () => { }) } else if (el.tagName === "textarea" || textInputTypes.includes(el.type)) { const keyupHandler = (e) => changeSet.patch(fieldName, convert(modifiers, e.target.value)); + const changeHandler = (e) => changeSet.patch(fieldName, convert(modifiers, e.target.value)); const onChangeSetUpdateHandler = (data) => { el.value = `${data[fieldName]}`; - el.dispatchEvent(new CustomEvent(nativeEventName, { detail: data[fieldName] })); + el.dispatchEvent(new CustomEvent(nativeEventName, {detail: {changeSet, value: data[fieldName]}})); }; changeSet.listen(onChangeSetUpdateHandler); - el.addEventListener('keyup', keyupHandler) + el.addEventListener('keyup', keyupHandler); + el.addEventListener('change', changeHandler); el.value = `${changeSet.get()[fieldName]}`; cleanup(() => { changeSet.removeListener(onChangeSetUpdateHandler); el.removeEventListener('keyup', keyupHandler) + el.removeEventListener('change', changeHandler) }) } else { const changeHandler = (e) => changeSet.patch(fieldName, convert(modifiers, e.target.value)); const onChangeSetUpdateHandler = (data) => { el.value = `${data[fieldName]}`; - el.dispatchEvent(new CustomEvent(nativeEventName, { detail: data[fieldName] })); + el.dispatchEvent(new CustomEvent(nativeEventName, {detail: {changeSet, value: data[fieldName]}})); }; changeSet.listen(onChangeSetUpdateHandler); @@ -154,4 +158,94 @@ document.addEventListener("alpine:init", () => { }) } }); + + /** + * Alpine.js directive for dynamically triggering a custom event and updating an element's inner text + * based on changes to a "change set" object's field. + * + * Syntax: + *
    + * + * Parameters: + * - changeSetExpression: The JavaScript expression evaluating to the change set object + * - fieldName: The specific field within the change set to monitor for changes + * + * Modifiers: + * - "text": When provided, the directive will also update the element's innerText. + * + * Custom Events: + * - "csupdate": Custom event triggered when the change set is updated. + * The detail property of the event object contains the new value of the specified field. + */ + Alpine.directive("change-set-listen", (el, {expression, modifiers}, {effect, evaluate, cleanup}) => { + effect(() => { + const [changeSetExpression, fieldName = null] = expression.split("."); + const changeSet = evaluate(changeSetExpression); + + const onChangeSetUpdateHandler = (data) => { + const value = fieldName != null ? data[fieldName] : data; + if (modifiers.includes("text")) { + el.innerText = `${value}`; + } + el.dispatchEvent(new CustomEvent(nativeEventName, {detail: {changeSet, value}})); + }; + + if (!changeSet) { + return; + } + + changeSet.removeListener(onChangeSetUpdateHandler); + onChangeSetUpdateHandler(changeSet.get()); + changeSet.listen(onChangeSetUpdateHandler); + + cleanup(() => { + changeSet.removeListener(onChangeSetUpdateHandler); + }) + }); + }); + + /** + * Alpine.js directive for executing custom logic in response to the "csupdate" event, + * which is usually triggered by changes in a "change set" object's field. + * + * Syntax: + *
    + * + * Parameters: + * - expression: The JavaScript expression to be evaluated when the "csupdate" event is triggered. + * + * Modifiers: + * - "init": When provided, the directive will execute the expression during initialization (no matter if its dirty or clean). + * - "clean": When provided, the directive will only execute if changeSet is not dirty. + * - "dirty": When provided, the directive will only execute if changeSet is dirty. + * + * Example usage: + *
    + *
    + */ + Alpine.directive("on-change-set-update", (el, {expression, modifiers}, {evaluate, evaluateLater, cleanup}) => { + const onUpdate = evaluateLater(expression); + + const onChangeSetUpdateHandler = (e) => { + const isDirty = e.detail.changeSet.isDirty(); + + if (modifiers.includes("clean") && isDirty) { + return; + } + if (modifiers.includes("dirty") && !isDirty) { + return; + } + onUpdate(); + }; + el.addEventListener(nativeEventName, onChangeSetUpdateHandler); + + if (modifiers.includes("init")) { + evaluate(expression); + } + + cleanup(() => { + el.removeEventListener(nativeEventName, onChangeSetUpdateHandler); + }) + }) }); \ No newline at end of file diff --git a/web/course.go b/web/course.go index d6c076790..f9fde23ec 100644 --- a/web/course.go +++ b/web/course.go @@ -8,8 +8,6 @@ import ( "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" - "github.com/getsentry/sentry-go" sentrygin "github.com/getsentry/sentry-go/gin" "github.com/gin-gonic/gin" @@ -52,7 +50,7 @@ func (r mainRoutes) editCourseByTokenPage(c *gin.Context) { err = templateExecutor.ExecuteTemplate(c.Writer, "edit-course-by-token.gohtml", d) if err != nil { - log.Println(err) + logger.Error("Error executing template edit-course-by-token.gohtml", "err", err) } } @@ -90,7 +88,7 @@ func (r mainRoutes) optOutPage(c *gin.Context) { } err = templateExecutor.ExecuteTemplate(c.Writer, "opt-out.gohtml", d) if err != nil { - log.WithError(err).Error("can't render template") + logger.Error("can't render template", "err", err) } } @@ -119,7 +117,7 @@ func (r mainRoutes) HighlightPage(c *gin.Context) { return } else { sentry.CaptureException(err) - log.Printf("%v", err) + logger.Error("Error getting current or next lecture for course", "err", err) } description := "" if indexData.TUMLiveContext.Stream != nil { @@ -133,7 +131,7 @@ func (r mainRoutes) HighlightPage(c *gin.Context) { IsHighlightPage: true, } if err = templateExecutor.ExecuteTemplate(c.Writer, "watch.gohtml", d2); err != nil { - log.Printf("%v", err) + logger.Error("Error executing template watch.gohtml", "err", err) return } } @@ -164,7 +162,7 @@ func (r mainRoutes) CoursePage(c *gin.Context) { streamsWithWatchState, err := r.StreamsDao.GetStreamsWithWatchState((*tumLiveContext.Course).ID, (*tumLiveContext.User).ID) if err != nil { sentry.CaptureException(err) - log.WithError(err).Error("loading streamsWithWatchState and progresses for a given course and user failed") + logger.Error("loading streamsWithWatchState and progresses for a given course and user failed", "err", err) } tumLiveContext.Course.Streams = streamsWithWatchState // Update the course streams to contain the watch state. @@ -172,7 +170,7 @@ func (r mainRoutes) CoursePage(c *gin.Context) { for i := range tumLiveContext.Course.Streams { err = tools.SetSignedPlaylists(&tumLiveContext.Course.Streams[i], tumLiveContext.User, false) if err != nil { - log.WithError(err).Warn("Can't sign playlists") + logger.Warn("Can't sign playlists", "err", err) } } @@ -197,7 +195,7 @@ func (r mainRoutes) CoursePage(c *gin.Context) { encoded, err := json.Marshal(clientWatchState) if err != nil { sentry.CaptureException(err) - log.WithError(err).Error("marshalling watched infos for client failed") + logger.Error("marshalling watched infos for client failed", "err", err) } err = templateExecutor.ExecuteTemplate(c.Writer, "course-overview.gohtml", CoursePageData{IndexData: indexData, Course: *tumLiveContext.Course, WatchedData: string(encoded)}) diff --git a/web/index.go b/web/index.go index fbb2f692e..8179ae34a 100644 --- a/web/index.go +++ b/web/index.go @@ -4,13 +4,12 @@ import ( "context" "errors" "github.com/RBG-TUM/commons" - "github.com/getsentry/sentry-go" - "github.com/gin-gonic/gin" "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" - log "github.com/sirupsen/logrus" + "github.com/getsentry/sentry-go" + "github.com/gin-gonic/gin" "gorm.io/gorm" "html/template" "net/http" @@ -45,7 +44,7 @@ func (r mainRoutes) MainPage(c *gin.Context) { indexData.LoadPinnedCourses() if err := templateExecutor.ExecuteTemplate(c.Writer, "index.gohtml", indexData); err != nil { - log.WithError(err).Errorf("Could not execute template: 'index.gohtml'") + logger.Error("Could not execute template: 'index.gohtml'", "err", err) } } @@ -66,7 +65,7 @@ func (r mainRoutes) InfoPage(id uint, name string) gin.HandlerFunc { text, err := r.InfoPageDao.GetById(id) if err != nil { - log.WithError(err).Error("Could not get text with id") + logger.Error("Could not get text with id", "err", err) c.AbortWithStatus(http.StatusInternalServerError) return } @@ -114,7 +113,7 @@ func NewIndexDataWithContext(c *gin.Context) IndexData { tumLiveContext = tumLiveContextQueried.(tools.TUMLiveContext) indexData.TUMLiveContext = tumLiveContext } else { - log.Warn("could not get TUMLiveContext") + logger.Warn("could not get TUMLiveContext") c.AbortWithStatus(http.StatusInternalServerError) } @@ -139,7 +138,7 @@ func (d *IndexData) LoadCurrentNotifications(serverNoticationDao dao.ServerNotif if notifications, err := serverNoticationDao.GetCurrentServerNotifications(); err == nil { d.ServerNotifications = notifications } else if err != gorm.ErrRecordNotFound { - log.WithError(err).Warn("could not get server notifications") + logger.Warn("could not get server notifications", "err", err) } } @@ -174,7 +173,7 @@ func (d *IndexData) LoadSemesters(spanMain *sentry.Span, coursesDao dao.CoursesD func (d *IndexData) LoadLivestreams(c *gin.Context, daoWrapper dao.DaoWrapper) { streams, err := daoWrapper.GetCurrentLive(context.Background()) if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - log.WithError(err).Error("could not get current live streams") + logger.Error("could not get current live streams", "err", err) c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"message": "Could not load current livestream from database."}) } @@ -203,7 +202,7 @@ func (d *IndexData) LoadLivestreams(c *gin.Context, daoWrapper dao.DaoWrapper) { if tumLiveContext.User != nil && tumLiveContext.User.Role == model.AdminType && stream.LectureHallID != 0 { lh, err := daoWrapper.LectureHallsDao.GetLectureHallByID(stream.LectureHallID) if err != nil { - log.WithError(err).Error(err) + logger.Error("Error getting lecture hall by id", "err", err) } else { lectureHall = &lh } diff --git a/web/popup.go b/web/popup.go index d4c1a8eac..f39f6eb0a 100644 --- a/web/popup.go +++ b/web/popup.go @@ -2,10 +2,9 @@ package web import ( "errors" + "github.com/TUM-Dev/gocast/tools" "github.com/getsentry/sentry-go" "github.com/gin-gonic/gin" - "github.com/TUM-Dev/gocast/tools" - "log" "net/http" ) @@ -26,6 +25,6 @@ func (r mainRoutes) PopOutChat(c *gin.Context) { err := templateExecutor.ExecuteTemplate(c.Writer, "popup-chat.gohtml", data) if err != nil { - log.Printf("couldn't render template: %v\n", err) + logger.Error("couldn't render template popup-chat.gohtml", "err", err) } } diff --git a/web/router.go b/web/router.go index 064d34425..b360edfaf 100755 --- a/web/router.go +++ b/web/router.go @@ -4,7 +4,6 @@ import ( "embed" "fmt" "github.com/getsentry/sentry-go" - log "github.com/sirupsen/logrus" "html/template" "net/http" "os" @@ -200,7 +199,7 @@ func (r mainRoutes) home(c *gin.Context) { indexData := NewIndexDataWithContext(c) if err := templateExecutor.ExecuteTemplate(c.Writer, "home.gohtml", indexData); err != nil { - log.WithError(err).Errorf("Could not execute template: 'home.gohtml'") + logger.Error("Could not execute template: 'home.gohtml'", "err", err) } } diff --git a/web/saml.go b/web/saml.go index b38426f05..338894aff 100644 --- a/web/saml.go +++ b/web/saml.go @@ -9,13 +9,12 @@ import ( "net/url" "strings" - "github.com/crewjam/saml" - "github.com/crewjam/saml/samlsp" - "github.com/gin-gonic/gin" "github.com/TUM-Dev/gocast/dao" "github.com/TUM-Dev/gocast/model" "github.com/TUM-Dev/gocast/tools" - log "github.com/sirupsen/logrus" + "github.com/crewjam/saml" + "github.com/crewjam/saml/samlsp" + "github.com/gin-gonic/gin" ) func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { @@ -27,27 +26,27 @@ func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { // create saml.ServiceProvider keyPair, err := tls.LoadX509KeyPair(tools.Cfg.Saml.Cert, tools.Cfg.Saml.Privkey) if err != nil { - log.WithError(err).Fatal("Could not load SAML keypair") + logger.Error("Could not load SAML keypair", "err", err) } keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0]) if err != nil { - log.WithError(err).Fatal("Could not parse SAML keypair") + logger.Error("Could not parse SAML keypair", "err", err) } idpMetadataURL, err := url.Parse(tools.Cfg.Saml.IdpMetadataURL) if err != nil { - log.WithError(err).Fatal("Could not parse Identity Provider metadata URL") + logger.Error("Could not parse Identity Provider metadata URL", "err", err) } idpMetadata, err := samlsp.FetchMetadata(context.Background(), http.DefaultClient, *idpMetadataURL) if err != nil { - log.WithError(err).Error("Could not load Identity Provider metadata") + logger.Error("Could not load Identity Provider metadata", "err", err) } var samlSPs []*samlsp.Middleware for _, l := range tools.Cfg.Saml.RootURLs { u, err := url.Parse(l) if err != nil { - log.WithError(err).Error("Could not parse Root URL") + logger.Error("Could not parse Root URL", "err", err) continue } samlSP, err := samlsp.New(samlsp.Options{ @@ -59,7 +58,7 @@ func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { AllowIDPInitiated: true, }) if err != nil { - log.WithError(err).Fatal("Could not create SAML Service Provider") + logger.Error("Could not create SAML Service Provider", "err", err) } samlSP.ServiceProvider.AcsURL = *u samlSPs = append(samlSPs, samlSP) @@ -101,7 +100,7 @@ func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { if err != nil { return } - log.Info("Logout request: ", request) + logger.Info("Logout request: " + request.String()) c.Redirect(http.StatusFound, request.String()) } }) @@ -131,12 +130,7 @@ func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { matrNr = extractSamlField(response, "eduPersonPrincipalName") // MWN id if no matrNr s := strings.Split(matrNr, "@") if len(s) == 0 || s[0] == "" { - log.WithFields(log.Fields{ - "LRZ-ID": lrzID, - "firstName": firstName, - "lastName": lastName, - "mwnID": matrNr, - }).Error("Can't extract mwn id") + logger.Error("Can't extract mwn id", "LRZ-ID", lrzID, "firstName", firstName, "lastName", lastName, "mwnID", matrNr) c.AbortWithStatus(http.StatusInternalServerError) } matrNr = s[0] @@ -149,7 +143,7 @@ func configSaml(r *gin.Engine, daoWrapper dao.DaoWrapper) { } err = daoWrapper.UsersDao.UpsertUser(&user) if err != nil { - log.WithError(err).Error("Could not upsert user") + logger.Error("Could not upsert user", "err", err) c.AbortWithStatus(http.StatusInternalServerError) } HandleValidLogin(c, &tools.SessionData{Userid: user.ID, SamlSubjectID: &subjectID}) diff --git a/web/template/admin/admin_tabs/course-import.gohtml b/web/template/admin/admin_tabs/course-import.gohtml index ea3e189e9..c80efb37a 100644 --- a/web/template/admin/admin_tabs/course-import.gohtml +++ b/web/template/admin/admin_tabs/course-import.gohtml @@ -12,7 +12,7 @@

    Semester

    -
    +
    + + @keyup="fetch('/api/searchCourse?q='+searchQuery).then(r=>r.json()).then(r => searchResults=r)" + @focus="isSearchResultVisible = true" + @blur="setTimeout(() => isSearchResultVisible = false, 100)"/>
    -
    +