diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 9c71401..6971470 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -24,9 +24,9 @@ jobs:
with:
go-version: 1.19
- - uses: open-policy-agent/setup-opa@v1
+ - uses: open-policy-agent/setup-opa@v2
with:
- version: 0.45
+ version: 0.46
- name: Build
run: make ci
diff --git a/README.md b/README.md
index 8808a86..ef71616 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ You'll need to set some environment variables to tell pslive how to assign names
- SESSIONS_ENCRYPTION_KEY, which should be set to a session encryption key generated by running pslive without the SESSION_ENCRYPTION_KEY set.
- ORY_KRATOS_SERVER, which should be set to the URL of your Ory Kratos public API (either self-hosted or hosted on Ory Cloud), including the protocol scheme (e.g. `https://project-id.projects.oryapis.com`).
- ORY_ACCESS_TOKEN, which should be set to a personal access token from Ory Cloud for the URL of your Ory Kratos administrative API.
-- TURBOSTREAMS_HASH_KEY, which should be set to an HMAC key generated by running Fluitans without the TURBOSTREAMS_HASH_KEY set.
+- ACTIONCABLE_HASH_KEY, which should be set to an HMAC key generated by running Fluitans without the ACTIONCABLE_HASH_KEY set.
For example, you could generate the session and Turbo Streams hash key using:
```
@@ -42,7 +42,7 @@ which will print a message like:
```
Record this key for future use as SESSIONS_AUTH_KEY: QVG4y5EPPoDZjAzYc6j7I09iJum3w+hXNrB3O4HQvSc=
Record this key for future use as SESSIONS_ENCRYPTION_KEY: Z/47Z2Uf6J68VFf7uAjiTfmum3yKWRuR2KoLVhwVdYA=
-Record this key for future use as TURBOSTREAMS_HASH_KEY: S+daMZsQxsqjmINunGWJhXvvxcgJtqnACba+sFuC4Tc=
+Record this key for future use as ACTIONCABLE_HASH_KEY: S+daMZsQxsqjmINunGWJhXvvxcgJtqnACba+sFuC4Tc=
```
And then you could run the server in development mode using:
@@ -52,7 +52,7 @@ SESSION_AUTH_KEY='QVG4y5EPPoDZjAzYc6j7I09iJum3w+hXNrB3O4HQvSc=' \
SESSIONS_ENCRYPTION_KEY='Z/47Z2Uf6J68VFf7uAjiTfmum3yKWRuR2KoLVhwVdYA=' \
ORY_KRATOS_SERVER='https://project-1234.projects.oryapis.com' \
ORY_ACCESS_TOKEN='ory_pat_12345' \
-TURBOSTREAMS_HASH_KEY='S+daMZsQxsqjmINunGWJhXvvxcgJtqnACba+sFuC4Tc=' \
+ACTIONCABLE_HASH_KEY='S+daMZsQxsqjmINunGWJhXvvxcgJtqnACba+sFuC4Tc=' \
make run
```
@@ -62,7 +62,7 @@ DATABASE_URI='file:db.sqlite3' \
SESSION_AUTH_KEY='QVG4y5EPPoDZjAzYc6j7I09iJum3w+hXNrB3O4HQvSc=' \
ORY_KRATOS_SERVER='https://project-1234.projects.oryapis.com' \
ORY_ACCESS_TOKEN='ory_pat_12345' \
-TURBOSTREAMS_HASH_KEY='S+daMZsQxsqjmINunGWJhXvvxcgJtqnACba+sFuC4Tc=' \
+ACTIONCABLE_HASH_KEY='S+daMZsQxsqjmINunGWJhXvvxcgJtqnACba+sFuC4Tc=' \
./pslive
```
diff --git a/go.mod b/go.mod
index ed3c4db..8a09d05 100644
--- a/go.mod
+++ b/go.mod
@@ -17,7 +17,7 @@ require (
github.com/ory/client-go v0.2.0-alpha.60
github.com/paulbellamy/ratecounter v0.2.0
github.com/pkg/errors v0.9.1
- github.com/sargassum-world/godest v0.4.3
+ github.com/sargassum-world/godest v0.5.0
github.com/unrolled/secure v1.13.0
golang.org/x/image v0.1.0
golang.org/x/sync v0.1.0
@@ -37,6 +37,7 @@ require (
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang/glog v1.0.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
+ github.com/google/flatbuffers v22.11.23+incompatible // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
@@ -45,6 +46,7 @@ require (
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
+ github.com/prometheus/client_golang v1.14.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/rogpeppe/go-internal v1.8.0 // indirect
@@ -59,12 +61,12 @@ require (
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/yashtewari/glob-intersection v0.1.0 // indirect
- golang.org/x/crypto v0.1.0 // indirect
+ golang.org/x/crypto v0.3.0 // indirect
golang.org/x/net v0.2.0 // indirect
- golang.org/x/oauth2 v0.1.0 // indirect
+ golang.org/x/oauth2 v0.2.0 // indirect
golang.org/x/sys v0.2.0 // indirect
golang.org/x/text v0.4.0 // indirect
- golang.org/x/time v0.1.0 // indirect
+ golang.org/x/time v0.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/go.sum b/go.sum
index d4da098..2331d81 100644
--- a/go.sum
+++ b/go.sum
@@ -128,7 +128,8 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
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/flatbuffers v22.10.26+incompatible h1:z1QiaMyPu1x3Z6xf2u1dsLj1ZxicdGSeaLpCuIsQNZM=
+github.com/google/flatbuffers v22.11.23+incompatible h1:334TygA7iuxt0hoamawsM36xoui01YiouEZnr0qeFMI=
+github.com/google/flatbuffers v22.11.23+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
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=
@@ -213,7 +214,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/prometheus/client_golang v1.13.1 h1:3gMjIY2+/hzmqhtUC/aQNYldJA6DtH3CgQvwS+02K1c=
+github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
+github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
@@ -225,8 +227,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qq
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
-github.com/sargassum-world/godest v0.4.3 h1:xPY1hHGm6Z7CxgknBRtlKeoUADNkqln4ISl8p4S6j3Q=
-github.com/sargassum-world/godest v0.4.3/go.mod h1:WP4bplxzGfnRjwhlcfR21FvO/rZDrWA7Kf4pqmHYuS4=
+github.com/sargassum-world/godest v0.5.0 h1:ggwHqedyqRL16p/qZiCrDTDPZbaggIi9Yia70SPBSZE=
+github.com/sargassum-world/godest v0.5.0/go.mod h1:WP4bplxzGfnRjwhlcfR21FvO/rZDrWA7Kf4pqmHYuS4=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@@ -280,8 +282,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
-golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
+golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
+golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
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=
@@ -353,8 +355,8 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr
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-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.1.0 h1:isLCZuhj4v+tYv7eskaN4v/TM+A1begWWgyVJDdl1+Y=
-golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
+golang.org/x/oauth2 v0.2.0 h1:GtQkldQ9m7yvzCL1V+LrYow3Khe0eJH0w7RbX/VbaIU=
+golang.org/x/oauth2 v0.2.0/go.mod h1:Cwn6afJ8jrQwYMxQDTpISoXmXW9I6qF6vDeuuoX3Ibs=
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=
@@ -420,8 +422,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
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.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
-golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE=
+golang.org/x/time v0.2.0/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=
diff --git a/internal/app/pslive/client/globals.go b/internal/app/pslive/client/globals.go
index 0552842..fbe4bf7 100644
--- a/internal/app/pslive/client/globals.go
+++ b/internal/app/pslive/client/globals.go
@@ -34,7 +34,7 @@ type Globals struct {
AuthzChecker *auth.AuthzChecker
ACCancellers *actioncable.Cancellers
- TSSigner turbostreams.Signer
+ ACSigner actioncable.Signer
TSBroker *turbostreams.Broker
Instruments *instruments.Store
@@ -85,11 +85,11 @@ func NewGlobals(
g.AuthzChecker = auth.NewAuthzChecker(g.DB, opc)
g.ACCancellers = actioncable.NewCancellers()
- tssConfig, err := turbostreams.GetSignerConfig()
+ acsConfig, err := actioncable.GetSignerConfig()
if err != nil {
- return nil, errors.Wrap(err, "couldn't set up turbo streams signer config")
+ return nil, errors.Wrap(err, "couldn't set up action cable signer config")
}
- g.TSSigner = turbostreams.NewSigner(tssConfig)
+ g.ACSigner = actioncable.NewSigner(acsConfig)
g.TSBroker = turbostreams.NewBroker(l)
g.Instruments = instruments.NewStore(g.DB)
diff --git a/internal/app/pslive/routes/cable/cable.go b/internal/app/pslive/routes/cable/cable.go
index 38df359..f6d252c 100644
--- a/internal/app/pslive/routes/cable/cable.go
+++ b/internal/app/pslive/routes/cable/cable.go
@@ -2,44 +2,99 @@ package cable
import (
"context"
+ "net/http"
"github.com/gorilla/sessions"
+ "github.com/gorilla/websocket"
"github.com/labstack/echo/v4"
+ "github.com/pkg/errors"
+ "github.com/sargassum-world/godest"
"github.com/sargassum-world/godest/actioncable"
+ "github.com/sargassum-world/godest/handling"
+ "github.com/sargassum-world/godest/session"
"github.com/sargassum-world/godest/turbostreams"
"github.com/sargassum-world/pslive/internal/app/pslive/auth"
+ "github.com/sargassum-world/pslive/internal/clients/videostreams"
)
+func serveWSConn(
+ r *http.Request, wsc *websocket.Conn, sess *sessions.Session,
+ channelFactories map[string]actioncable.ChannelFactory,
+ cc *session.CSRFTokenChecker, acc *actioncable.Cancellers, wsu websocket.Upgrader,
+ l godest.Logger,
+) {
+ conn, err := actioncable.Upgrade(wsc, actioncable.NewChannelDispatcher(
+ channelFactories, make(map[string]actioncable.Channel),
+ actioncable.WithCSRFTokenChecker(func(token string) error {
+ return cc.Check(r, token)
+ }),
+ ))
+ // We can't return errors after the HTTP request is upgraded to a websocket, so we just log them
+ if err != nil {
+ l.Error(errors.Wrapf(
+ err,
+ "couldn't upgrade websocket connection to action cable connection "+
+ "(client requested subprotocols %v, upgrader supports subprotocols %v)",
+ websocket.Subprotocols(r),
+ wsu.Subprotocols,
+ ))
+ if cerr := wsc.Close(); cerr != nil {
+ l.Error(errors.Wrapf(cerr, "couldn't close websocket"))
+ }
+ return
+ }
+
+ ctx, cancel := context.WithCancel(r.Context())
+ acc.Add(sess.ID, cancel)
+ serr := handling.Except(conn.Serve(ctx), context.Canceled)
+ if serr != nil {
+ // We can't return errors after the HTTP request is upgraded to a websocket, so we just log them
+ l.Error(serr)
+ }
+ if cerr := conn.Close(serr); err != nil {
+ // We can't return errors after the HTTP request is upgraded to a websocket, so we just log them
+ l.Error(cerr)
+ }
+}
+
func (h *Handlers) HandleCableGet() auth.HTTPHandlerFuncWithSession {
return func(c echo.Context, _ auth.Auth, sess *sessions.Session) error {
wsc, err := h.wsu.Upgrade(c.Response(), c.Request(), nil)
if err != nil {
- return err
+ return errors.Wrap(err, "couldn't upgrade http request to websocket connection")
}
const wsMaxMessageSize = 512
wsc.SetReadLimit(wsMaxMessageSize)
-
- acc := actioncable.Upgrade(wsc, actioncable.WithChannels(
+ serveWSConn(
+ c.Request(), wsc, sess,
map[string]actioncable.ChannelFactory{
- turbostreams.ChannelName: turbostreams.NewChannelFactory(h.tsb, sess.ID, h.tss.Check),
+ turbostreams.ChannelName: turbostreams.NewChannelFactory(h.tsb, sess.ID, h.acs.Check),
},
- make(map[string]actioncable.Channel),
- actioncable.WithCSRFTokenChecker(func(token string) error {
- return h.cc.Check(c.Request(), token)
- }),
- ))
- ctx, cancel := context.WithCancel(c.Request().Context())
- h.acc.Add(sess.ID, cancel)
- serr := acc.Serve(ctx)
- // We can't return errors after the HTTP request is upgraded to a websocket, so we just log them
- if serr != nil && serr != context.Canceled {
- h.l.Error(serr)
- }
- if err := acc.Close(serr); err != nil {
- h.l.Error(err)
+ h.cc, h.acc, h.wsu, h.l,
+ )
+ return nil
+ }
+}
+
+func (h *Handlers) HandleVideoCableGet() auth.HTTPHandlerFuncWithSession {
+ return func(c echo.Context, _ auth.Auth, sess *sessions.Session) error {
+ wsc, err := h.wsu.Upgrade(c.Response(), c.Request(), nil)
+ if err != nil {
+ return errors.Wrap(err, "couldn't upgrade http request to websocket connection")
}
+
+ const wsMaxMessageSize = 512
+ wsc.SetReadLimit(wsMaxMessageSize)
+ // TODO: make this action cable connection use msgpack instead of json for efficiency reasons
+ serveWSConn(
+ c.Request(), wsc, sess,
+ map[string]actioncable.ChannelFactory{
+ videostreams.ChannelName: videostreams.NewChannelFactory(h.vsb, sess.ID, h.l, h.acs.Check),
+ },
+ h.cc, h.acc, h.wsu, h.l,
+ )
return nil
}
}
diff --git a/internal/app/pslive/routes/cable/routes.go b/internal/app/pslive/routes/cable/routes.go
index 5b7f74c..1b53258 100644
--- a/internal/app/pslive/routes/cable/routes.go
+++ b/internal/app/pslive/routes/cable/routes.go
@@ -11,6 +11,7 @@ import (
"github.com/sargassum-world/godest/turbostreams"
"github.com/sargassum-world/pslive/internal/app/pslive/auth"
+ "github.com/sargassum-world/pslive/internal/clients/videostreams"
)
type Handlers struct {
@@ -20,33 +21,37 @@ type Handlers struct {
cc *session.CSRFTokenChecker
acc *actioncable.Cancellers
- tss turbostreams.Signer
+ acs actioncable.Signer
tsb *turbostreams.Broker
-
- l godest.Logger
+ vsb *videostreams.Broker
wsu websocket.Upgrader
+
+ l godest.Logger
}
func New(
r godest.TemplateRenderer, ss *session.Store, cc *session.CSRFTokenChecker,
- acc *actioncable.Cancellers, tss turbostreams.Signer, tsb *turbostreams.Broker, l godest.Logger,
+ acc *actioncable.Cancellers, acs actioncable.Signer, tsb *turbostreams.Broker,
+ vsb *videostreams.Broker, l godest.Logger,
) *Handlers {
return &Handlers{
r: r,
ss: ss,
cc: cc,
acc: acc,
- tss: tss,
+ acs: acs,
tsb: tsb,
- l: l,
+ vsb: vsb,
wsu: websocket.Upgrader{
- Subprotocols: actioncable.Subprotocols(),
+ Subprotocols: actioncable.SupportedSubprotocols(),
// TODO: add parameters to the upgrader as needed
},
+ l: l,
}
}
func (h *Handlers) Register(er godest.EchoRouter) {
er.GET("/cable", auth.HandleHTTPWithSession(h.HandleCableGet(), h.ss))
+ er.GET("/video-cable", auth.HandleHTTPWithSession(h.HandleVideoCableGet(), h.ss))
}
diff --git a/internal/app/pslive/routes/instruments/camera.go b/internal/app/pslive/routes/instruments/camera.go
index c4466a7..360262d 100644
--- a/internal/app/pslive/routes/instruments/camera.go
+++ b/internal/app/pslive/routes/instruments/camera.go
@@ -68,20 +68,61 @@ const (
)
func newErrorJPEG(width, height int, message string) []byte {
- output, _, err := newErrorFrame(
+ frame, err := newErrorFrame(
width, height, message,
- ).AsJPEG()
+ ).AsJPEGFrame()
if err != nil {
panic(err)
}
- return output
+ return frame.Im
}
-var (
- jpegError = newErrorJPEG(errorWidth, errorHeight, "stream failed")
- frameError = newErrorFrame(errorWidth, errorHeight, "stream failed")
- frameLoading = newErrorFrame(errorWidth, errorHeight, "loading stream...")
-)
+var jpegError = newErrorJPEG(errorWidth, errorHeight, "stream failed")
+
+// Sending helpers
+
+func externalSourceFrameSender(
+ ss *mjpeg.StreamSender, annotated bool, quality int,
+ fpsCounter *ratecounter.RateCounter, fpsPeriod float32,
+) handling.Consumer[videostreams.Frame] {
+ return func(frame videostreams.Frame) (done bool, err error) {
+ if err = frame.Error(); err != nil {
+ if herr := handling.Except(
+ ss.Send(jpegError), context.Canceled, syscall.EPIPE,
+ ); herr != nil {
+ return false, errors.Wrap(err, "couldn't send mjpeg error frame")
+ }
+ return false, err
+ }
+
+ // Generate output
+ // Note: without annotation the frame passes through directly, potentially without any
+ // JPEG decoding/encoding in the pipeline
+ if annotated {
+ fpsCounter.Incr(1)
+ f, err := frame.AsImageFrame()
+ if err != nil {
+ return false, errors.Wrap(err, "couldn't read frame as image")
+ }
+ f.Meta = f.Meta.WithSettings(videostreams.Settings{
+ JPEGEncodeQuality: quality,
+ })
+ metadata := videostreams.AnnotationMetadata{
+ FPSCount: fpsCounter.Rate(),
+ FPSPeriod: fpsPeriod,
+ }.WithFrameData(f)
+ f = f.WithAnnotation(metadata.String(), 1)
+ frame = f
+ }
+ // TODO: implement image resizing
+
+ // Send output
+ if err := handling.Except(ss.SendFrame(frame), context.Canceled, syscall.EPIPE); err != nil {
+ return false, errors.Wrap(err, "couldn't send mjpeg frame")
+ }
+ return false, nil
+ }
+}
// Handlers
@@ -146,58 +187,16 @@ func (h *Handlers) HandleInstrumentCameraFrameGet() echo.HandlerFunc {
frame = f
// Produce output
- jpeg, _, err := frame.AsJPEG()
+ jpeg, err := frame.AsJPEGFrame()
if err != nil {
return errors.Wrap(err, "couldn't jpeg-encode image")
}
- return c.Blob(http.StatusOK, "image/jpeg", jpeg)
- }
-}
-
-func externalSourceFrameSender(
- ss *mjpeg.StreamSender, annotated bool, quality int,
- fpsCounter *ratecounter.RateCounter, fpsPeriod float32,
-) handling.Consumer[videostreams.Frame] {
- return func(frame videostreams.Frame) (done bool, err error) {
- if err = frame.Error(); err != nil {
- if herr := handling.Except(
- ss.SendFrame(frameError), context.Canceled, syscall.EPIPE,
- ); herr != nil {
- return false, errors.Wrap(err, "couldn't send mjpeg error frame")
- }
- return false, err
- }
-
- // Generate output
- // Note: without annotation the frame passes through directly, potentially without any
- // JPEG decoding/encoding in the pipeline
- if annotated {
- fpsCounter.Incr(1)
- f, err := frame.AsImageFrame()
- if err != nil {
- return false, errors.Wrap(err, "couldn't read frame as image")
- }
- f.Meta = f.Meta.WithSettings(videostreams.Settings{
- JPEGEncodeQuality: quality,
- })
- metadata := videostreams.AnnotationMetadata{
- FPSCount: fpsCounter.Rate(),
- FPSPeriod: fpsPeriod,
- }.WithFrameData(f)
- f = f.WithAnnotation(metadata.String(), 1)
- frame = f
- }
- // TODO: implement image resizing
-
- // Send output
- if err := handling.Except(ss.SendFrame(frame), context.Canceled, syscall.EPIPE); err != nil {
- return false, errors.Wrap(err, "couldn't send mjpeg frame")
- }
- return false, nil
+ return c.Blob(http.StatusOK, "image/jpeg", jpeg.Im)
}
}
func (h *Handlers) HandleInstrumentCameraStreamGet() echo.HandlerFunc {
+ jpegLoading := newErrorJPEG(errorWidth, errorHeight, "loading stream...")
return func(c echo.Context) error {
// Parse params
id, err := parseID(c.Param("cameraID"), "camera")
@@ -222,7 +221,7 @@ func (h *Handlers) HandleInstrumentCameraStreamGet() echo.HandlerFunc {
}
}()
if err := handling.Except(
- ss.SendFrame(frameLoading), context.Canceled, syscall.EPIPE,
+ ss.Send(jpegLoading), context.Canceled, syscall.EPIPE,
); err != nil {
return errors.Wrap(err, "couldn't send mjpeg loading frame")
}
@@ -249,3 +248,52 @@ func (h *Handlers) HandleInstrumentCameraStreamGet() echo.HandlerFunc {
return nil
}
}
+
+func (h *Handlers) HandleInstrumentCameraStreamPub() videostreams.HandlerFunc {
+ frameLoading := newErrorFrame(errorWidth, errorHeight, "loading stream...")
+ return func(c *videostreams.Context) error {
+ // Parse params
+ id, err := parseID(c.Param("cameraID"), "camera")
+ if err != nil {
+ return err
+ }
+ // TODO: implement a max framerate
+
+ // Run queries
+ ctx := c.Context()
+ camera, err := h.is.GetCamera(ctx, id)
+ if err != nil {
+ return errors.Wrapf(err, "camera %d not found", id)
+ }
+ sourceURL := camera.URL
+
+ // Set up output stream
+ c.Publish(frameLoading)
+
+ // Subscribe to source stream
+ source := fmt.Sprintf(
+ "/video-streams/external-stream/source.mjpeg?url=%s", url.QueryEscape(sourceURL),
+ )
+ frameBuffer := h.vsb.Subscribe(ctx, source)
+
+ // Post-process and deliver stream
+ if err := handling.Except(
+ handling.Consume(ctx, frameBuffer, func(frame videostreams.Frame) (done bool, err error) {
+ // Since the source stream emits JPEG frames, we can safely assume that no further JPEG
+ // encoding is needed after we call c.Publish - but we check here anyways because it's
+ // cheap to check, and we can ensure that we only perform one JPEG encoding regardless of
+ // the number of Video Streams subscribers (i.e. the number of web browsers).
+ jpegFrame, err := frame.AsJPEGFrame()
+ if err != nil {
+ return false, errors.Wrap(err, "couldn't convert frame to JPEG for action cable")
+ }
+ c.Publish(jpegFrame)
+ return false, nil
+ }),
+ context.Canceled,
+ ); err != nil {
+ c.Logger().Error(errors.Wrapf(err, "failed to proxy stream %s", sourceURL))
+ }
+ return nil
+ }
+}
diff --git a/internal/app/pslive/routes/instruments/routes.go b/internal/app/pslive/routes/instruments/routes.go
index d3d8603..5e3a234 100644
--- a/internal/app/pslive/routes/instruments/routes.go
+++ b/internal/app/pslive/routes/instruments/routes.go
@@ -50,7 +50,7 @@ func New(
}
func (h *Handlers) Register(
- er godest.EchoRouter, tsr turbostreams.Router, ss *session.Store,
+ er godest.EchoRouter, tsr turbostreams.Router, vsr videostreams.Router, ss *session.Store,
) {
hr := auth.NewHTTPRouter(er, ss)
hr.GET("/instruments", h.HandleInstrumentsGet())
@@ -69,6 +69,8 @@ func (h *Handlers) Register(
hr.POST("/instruments/:id/cameras/:cameraID", h.HandleInstrumentCameraPost())
er.GET("/instruments/:id/cameras/:cameraID/frame.jpeg", h.HandleInstrumentCameraFrameGet())
er.GET("/instruments/:id/cameras/:cameraID/stream.mjpeg", h.HandleInstrumentCameraStreamGet())
+ vsr.SUB("/instruments/:id/cameras/:cameraID/stream.mjpeg", videostreams.EmptyHandler)
+ vsr.PUB("/instruments/:id/cameras/:cameraID/stream.mjpeg", h.HandleInstrumentCameraStreamPub())
hr.POST("/instruments/:id/controllers", h.HandleInstrumentControllersPost())
hr.POST("/instruments/:id/controllers/:controllerID", h.HandleInstrumentControllerPost())
tsr.SUB("/instruments/:id/controllers/:controllerID/pump", turbostreams.EmptyHandler)
diff --git a/internal/app/pslive/routes/routes.go b/internal/app/pslive/routes/routes.go
index 4f15b91..03c003a 100644
--- a/internal/app/pslive/routes/routes.go
+++ b/internal/app/pslive/routes/routes.go
@@ -46,11 +46,11 @@ func (h *Handlers) Register(
assets.RegisterStatic(er, em)
assets.NewTemplated(h.r).Register(er)
cable.New(
- h.r, ss, h.globals.CSRFChecker, acc, h.globals.TSSigner, h.globals.TSBroker, l,
+ h.r, ss, h.globals.CSRFChecker, acc, h.globals.ACSigner, h.globals.TSBroker, vsb, l,
).Register(er)
home.New(h.r, oc, is, ps).Register(er, ss)
auth.New(h.r, ss, oc, acc, ps, l).Register(er)
- instruments.New(h.r, oc, azc, tsh, is, h.globals.Planktoscopes, ps, cs, vsb).Register(er, tsr, ss)
+ instruments.New(h.r, oc, azc, tsh, is, h.globals.Planktoscopes, ps, cs, vsb).Register(er, tsr, vsr, ss)
privatechat.New(h.r, oc, azc, tsh, ps, cs).Register(er, tsr, ss)
users.New(h.r, oc, azc, tsh, is, ps, cs).Register(er, tsr, ss)
videostreams.New(vsb).Register(er, vsr)
diff --git a/internal/app/pslive/routes/videostreams/generated.go b/internal/app/pslive/routes/videostreams/generated.go
index 2bc5a82..c40be67 100644
--- a/internal/app/pslive/routes/videostreams/generated.go
+++ b/internal/app/pslive/routes/videostreams/generated.go
@@ -151,11 +151,11 @@ func (h *Handlers) HandleAnimatedColorFrameGet() echo.HandlerFunc {
f.Meta.Settings.JPEGEncodeQuality = quality
// Produce output
- frameJPEG, _, err := f.AsJPEG()
+ jpeg, err := f.AsJPEGFrame()
if err != nil {
return errors.Wrap(err, "couldn't jpeg-encode image")
}
- return c.Blob(http.StatusOK, "image/jpeg", frameJPEG)
+ return c.Blob(http.StatusOK, "image/jpeg", jpeg.Im)
}
}
diff --git a/internal/app/pslive/routes/videostreams/proxied.go b/internal/app/pslive/routes/videostreams/proxied.go
index f36996f..4483599 100644
--- a/internal/app/pslive/routes/videostreams/proxied.go
+++ b/internal/app/pslive/routes/videostreams/proxied.go
@@ -71,11 +71,11 @@ func (h *Handlers) HandleExternalSourceFrameGet() echo.HandlerFunc {
frame = f
// Produce output
- jpeg, _, err := frame.AsJPEG()
+ jpeg, err := frame.AsJPEGFrame()
if err != nil {
return errors.Wrap(err, "couldn't jpeg-encode image")
}
- return c.Blob(http.StatusOK, "image/jpeg", jpeg)
+ return c.Blob(http.StatusOK, "image/jpeg", jpeg.Im)
}
}
@@ -164,15 +164,15 @@ func (h *Handlers) HandleExternalSourceStreamGet() echo.HandlerFunc {
func (h *Handlers) HandleExternalSourcePub() videostreams.HandlerFunc {
return func(c *videostreams.Context) error {
// Parse params from topic
- query, err := c.Query()
+ query, err := c.QueryParams()
if err != nil {
err = errors.Wrap(err, "couldn't parse topic query params")
- c.Publish(mjpeg.NewErrorFrame(err))
+ c.Publish(videostreams.NewErrorFrame(err))
return err
}
source, err := parseURLParam(query.Get("url"))
if err != nil {
- c.Publish(mjpeg.NewErrorFrame(err))
+ c.Publish(videostreams.NewErrorFrame(err))
return err
}
@@ -181,7 +181,7 @@ func (h *Handlers) HandleExternalSourcePub() videostreams.HandlerFunc {
r, err := mjpeg.NewReceiverFromURL(ctx, h.hc, source)
if err != nil {
err = errors.Wrapf(err, "couldn't start mjpeg receiver for %s", source)
- c.Publish(mjpeg.NewErrorFrame(err))
+ c.Publish(videostreams.NewErrorFrame(err))
return err
}
defer r.Close()
diff --git a/internal/app/pslive/routes/videostreams/random-color.go b/internal/app/pslive/routes/videostreams/random-color.go
index bee3525..403b9ae 100644
--- a/internal/app/pslive/routes/videostreams/random-color.go
+++ b/internal/app/pslive/routes/videostreams/random-color.go
@@ -98,13 +98,13 @@ func (h *Handlers) HandleRandomColorFrameGet() echo.HandlerFunc {
// Generate data
frame := newCurrentFrame(newUniformImage(width, height, newRandomColor()))
frame.Meta.Settings.JPEGEncodeQuality = quality
- jpeg, _, err := frame.AsJPEG()
+ jpeg, err := frame.AsJPEGFrame()
if err != nil {
return errors.Wrap(err, "couldn't jpeg-encode image")
}
// Produce output
- return c.Blob(http.StatusOK, "image/jpeg", jpeg)
+ return c.Blob(http.StatusOK, "image/jpeg", jpeg.Im)
}
}
@@ -121,7 +121,7 @@ func (h *Handlers) HandleRandomColorStreamGet() echo.HandlerFunc {
return errors.Wrap(err, "couldn't parse image quality query parameter")
}
- frames := make(chan mjpeg.JPEGEncodable)
+ frames := make(chan videostreams.Frame)
// TODO: also make it dependent on the server's context!
eg, egctx := errgroup.WithContext(c.Request().Context())
eg.Go(func() error {
@@ -136,7 +136,7 @@ func (h *Handlers) HandleRandomColorStreamGet() echo.HandlerFunc {
})
eg.Go(func() error {
// Produce output
- return mjpeg.SendStream(egctx, c.Response().Writer, frames)
+ return mjpeg.SendFrameStream(egctx, c.Response().Writer, frames)
})
if err := handling.Except(eg.Wait(), context.Canceled, syscall.EPIPE); err != nil {
return err
diff --git a/internal/app/pslive/server.go b/internal/app/pslive/server.go
index 0f341d6..9c12cc6 100644
--- a/internal/app/pslive/server.go
+++ b/internal/app/pslive/server.go
@@ -68,7 +68,7 @@ func NewServer(logger godest.Logger) (s *Server, err error) {
if s.Renderer, err = godest.NewTemplateRenderer(
s.Embeds, s.Inlines, sprig.FuncMap(), tmplfunc.FuncMap(
tmplfunc.NewHashedNamers(assets.AppURLPrefix, assets.StaticURLPrefix, s.Embeds),
- s.Globals.TSSigner.Sign,
+ s.Globals.ACSigner.Sign,
),
); err != nil {
return nil, errors.Wrap(err, "couldn't make template renderer")
@@ -282,6 +282,9 @@ func (s *Server) Run(e *echo.Echo) error {
}
func (s *Server) Shutdown(ctx context.Context, e *echo.Echo) (err error) {
+ // FIXME: e.Shutdown calls e.Server.Shutdown, which doesn't wait for WebSocket connections. When
+ // starting Echo, we need to call e.Server.RegisterOnShutdown with a function to gracefully close
+ // WebSocket connections!
if errEcho := e.Shutdown(ctx); errEcho != nil {
s.Globals.Logger.Error(errors.Wrap(errEcho, "couldn't shut down http server"))
err = errEcho
diff --git a/internal/app/pslive/tmplfunc/funcs.go b/internal/app/pslive/tmplfunc/funcs.go
index 724772f..1471182 100644
--- a/internal/app/pslive/tmplfunc/funcs.go
+++ b/internal/app/pslive/tmplfunc/funcs.go
@@ -18,5 +18,6 @@ func FuncMap(h HashedNamers, tss TurboStreamSigner) template.FuncMap {
"appHashed": h.AppHashed,
"staticHashed": h.StaticHashed,
"signTurboStream": tss,
+ "signVideoStream": tss,
}
}
diff --git a/internal/clients/mjpeg/http-receiver.go b/internal/clients/mjpeg/http-receiver.go
index 5687904..9ea504b 100644
--- a/internal/clients/mjpeg/http-receiver.go
+++ b/internal/clients/mjpeg/http-receiver.go
@@ -1,11 +1,9 @@
-// Package mjpeg provides receiving and sending of MJPEG streams over HTTP
+// Package mjpeg provides functionality for receiving and sending MJPEG streams over HTTP
package mjpeg
import (
"bytes"
"context"
- "image"
- "image/jpeg"
"io"
"mime"
"mime/multipart"
@@ -18,52 +16,6 @@ import (
"github.com/sargassum-world/pslive/internal/clients/videostreams"
)
-// JPEG Frame
-
-type JPEGFrame struct {
- jpeg []byte
- metadata *videostreams.Metadata
- err error
-}
-
-func NewErrorFrame(err error) *JPEGFrame {
- return &JPEGFrame{
- err: err,
- }
-}
-
-func (f *JPEGFrame) AsImage() (image.Image, videostreams.Operation, error) {
- im, err := jpeg.Decode(bytes.NewReader(f.jpeg))
- if err != nil {
- return nil, videostreams.Nop, err
- }
- return im, "decode JPEG", nil
-}
-
-func (f *JPEGFrame) AsImageFrame() (*videostreams.ImageFrame, error) {
- im, op, err := f.AsImage()
- if err != nil {
- return nil, err
- }
- return &videostreams.ImageFrame{
- Im: im,
- Meta: f.Metadata().WithOp(op),
- Err: f.err,
- }, nil
-}
-
-func (f *JPEGFrame) AsJPEG() ([]byte, videostreams.Operation, error) {
- return f.jpeg, videostreams.Nop, f.err
-}
-
-func (f *JPEGFrame) Metadata() *videostreams.Metadata {
- return f.metadata
-}
-
-func (f *JPEGFrame) Error() error {
- return f.err
-}
-
// Receiver
type Receiver struct {
@@ -85,7 +37,7 @@ func NewReceiverFromResponse(res *http.Response) (*Receiver, error) {
if !strings.HasPrefix(contentType, "multipart/") {
return nil, errors.Errorf("unexpected stream content type %s", contentType)
}
- receiver := NewReceiver(res.Body, param["boundary"])
+ receiver := NewReceiver(res.Body, strings.TrimPrefix(param["boundary"], "--"))
receiver.closer = res.Body.Close
return receiver, nil
}
@@ -118,7 +70,7 @@ func (r *Receiver) Close() {
}
}
-func (r *Receiver) Receive() (frame *JPEGFrame, err error) {
+func (r *Receiver) Receive() (frame *videostreams.JPEGFrame, err error) {
part, err := r.reader.NextPart()
if err == io.EOF {
return nil, err
@@ -135,9 +87,9 @@ func (r *Receiver) Receive() (frame *JPEGFrame, err error) {
if _, err = io.Copy(buffer, part); err != nil {
return nil, errors.Wrap(err, "couldn't jpeg-decode stream part")
}
- frame = &JPEGFrame{
- jpeg: buffer.Bytes(),
- metadata: &videostreams.Metadata{
+ frame = &videostreams.JPEGFrame{
+ Im: buffer.Bytes(),
+ Meta: &videostreams.Metadata{
FromSource: make(map[string][]string),
ReceiveTime: time.Now(),
Operations: &videostreams.OpChain{
@@ -151,7 +103,7 @@ func (r *Receiver) Receive() (frame *JPEGFrame, err error) {
if key == "Content-Type" {
continue
}
- frame.metadata.FromSource[key] = values
+ frame.Meta.FromSource[key] = values
}
return frame, err
}
diff --git a/internal/clients/mjpeg/http-sender.go b/internal/clients/mjpeg/http-sender.go
index 5e15546..aba3905 100644
--- a/internal/clients/mjpeg/http-sender.go
+++ b/internal/clients/mjpeg/http-sender.go
@@ -13,12 +13,6 @@ import (
"github.com/sargassum-world/pslive/internal/clients/videostreams"
)
-// JPEGEncodable
-
-type JPEGEncodable interface {
- AsJPEG() ([]byte, videostreams.Operation, error)
-}
-
// Sender
type StreamSender struct {
@@ -35,19 +29,23 @@ func StartStream(w http.ResponseWriter) *StreamSender {
}
}
-func (ss *StreamSender) SendFrame(frame JPEGEncodable) error {
- data, _, err := frame.AsJPEG()
+func (ss *StreamSender) SendFrame(frame videostreams.Frame) error {
+ jpeg, err := frame.AsJPEGFrame()
if err != nil {
return errors.Wrap(err, "couldn't jpeg-encode frame")
}
+ return ss.Send(jpeg.Im)
+}
+
+func (ss *StreamSender) Send(frame []byte) error {
h := textproto.MIMEHeader{}
h.Set("Content-Type", "image/jpeg")
- h.Set("Content-Length", strconv.Itoa(len(data)))
+ h.Set("Content-Length", strconv.Itoa(len(frame)))
pw, err := ss.mw.CreatePart(h)
if err != nil {
return err
}
- if _, err := pw.Write(data); err != nil {
+ if _, err := pw.Write(frame); err != nil {
return err
}
if f, ok := ss.w.(http.Flusher); ok {
@@ -60,8 +58,8 @@ func (ss *StreamSender) Close() error {
return ss.mw.Close()
}
-func SendStream(
- ctx context.Context, w http.ResponseWriter, frames <-chan JPEGEncodable,
+func SendFrameStream(
+ ctx context.Context, w http.ResponseWriter, frames <-chan videostreams.Frame,
) (err error) {
ss := StartStream(w)
defer func() {
@@ -71,7 +69,23 @@ func SendStream(
}
}()
- return handling.Consume(ctx, frames, func(frame JPEGEncodable) (bool, error) {
+ return handling.Consume(ctx, frames, func(frame videostreams.Frame) (bool, error) {
return false, ss.SendFrame(frame)
})
}
+
+func SendStream(
+ ctx context.Context, w http.ResponseWriter, frames <-chan []byte,
+) (err error) {
+ ss := StartStream(w)
+ defer func() {
+ cerr := ss.mw.Close()
+ if err == nil && cerr != nil {
+ err = cerr
+ }
+ }()
+
+ return handling.Consume(ctx, frames, func(frame []byte) (bool, error) {
+ return false, ss.Send(frame)
+ })
+}
diff --git a/internal/clients/videostreams/actioncable-channel.go b/internal/clients/videostreams/actioncable-channel.go
new file mode 100644
index 0000000..425a8a8
--- /dev/null
+++ b/internal/clients/videostreams/actioncable-channel.go
@@ -0,0 +1,109 @@
+package videostreams
+
+import (
+ "context"
+ "encoding/json"
+
+ "github.com/pkg/errors"
+ "github.com/sargassum-world/godest/actioncable"
+ "github.com/sargassum-world/godest/handling"
+ "github.com/sargassum-world/godest/pubsub"
+)
+
+// ChannelName is the name of the Action Cable channel for Video Streams.
+const ChannelName = "Video::StreamsChannel"
+
+// subscriber creates a subscription for the channel, to integrate [Channel] with [Broker].
+type subscriber func(ctx context.Context, topic string) <-chan Frame
+
+// Channel represents an Action Cable channel for a Video Streams stream.
+type Channel struct {
+ identifier string
+ streamName string
+ h *pubsub.Hub[[]Frame]
+ subscriber subscriber
+ sessionID string
+ logger pubsub.Logger
+}
+
+// parseStreamName parses the Video Streams stream name from the Action Cable subscription
+// identifier.
+func parseStreamName(identifier string) (string, error) {
+ var i struct {
+ Name string `json:"name"`
+ }
+ if err := json.Unmarshal([]byte(identifier), &i); err != nil {
+ return "", errors.Wrap(
+ err, "couldn't parse stream name from action cable subscription identifier",
+ )
+ }
+ return i.Name, nil
+}
+
+// NewChannel checks the identifier with the specified checkers and returns a new Channel instance.
+func NewChannel(
+ identifier string, h *pubsub.Hub[[]Frame], subscriber subscriber, sessionID string,
+ checkers []actioncable.IdentifierChecker, logger pubsub.Logger,
+) (*Channel, error) {
+ name, err := parseStreamName(identifier)
+ if err != nil {
+ return nil, err
+ }
+ for _, checker := range checkers {
+ if err := checker(identifier); err != nil {
+ return nil, errors.Wrap(err, "action cable subscription identifier failed checks")
+ }
+ }
+ return &Channel{
+ identifier: identifier,
+ streamName: name,
+ h: h,
+ subscriber: subscriber,
+ sessionID: sessionID,
+ logger: logger,
+ }, nil
+}
+
+// Subscribe handles an Action Cable subscribe command from the client with the provided
+// [actioncable.Subscription].
+func (c *Channel) Subscribe(ctx context.Context, sub *actioncable.Subscription) error {
+ if sub.Identifier() != c.identifier {
+ return errors.Errorf(
+ "channel identifier %+v does not match subscription identifier %+v",
+ c.identifier, sub.Identifier(),
+ )
+ }
+
+ frames := c.subscriber(ctx, c.streamName)
+ go func() {
+ for frame := range frames {
+ encoded, err := frame.AsJPEGFrame()
+ if err != nil {
+ c.logger.Error(errors.Wrap(err, "couldn't jpeg-encode frame to send over action cable"))
+ break
+ }
+ // TODO: attach metadata to the frame data (may need struct tags for marshaling)
+ if err := handling.Except(sub.SendBytes(ctx, encoded.Im), context.Canceled); err != nil {
+ c.logger.Error(errors.Wrap(err, "couldn't send turbo streams messages over action cable"))
+ break
+ }
+ }
+ sub.Close()
+ }()
+ return nil
+}
+
+// Perform handles an Action Cable action command from the client.
+func (c *Channel) Perform(data string) error {
+ return errors.New("video streams channel cannot perform any actions")
+}
+
+// NewChannelFactory creates an [actioncable.ChannelFactory] for Turbo Streams to create channels
+// for different Video Streams streams as needed.
+func NewChannelFactory(
+ b *Broker, sessionID string, logger pubsub.Logger, checkers ...actioncable.IdentifierChecker,
+) actioncable.ChannelFactory {
+ return func(identifier string) (actioncable.Channel, error) {
+ return NewChannel(identifier, b.Hub(), b.Subscribe, sessionID, checkers, logger)
+ }
+}
diff --git a/internal/clients/videostreams/pubsub.go b/internal/clients/videostreams/pubsub.go
index 8d62811..25a7e5a 100644
--- a/internal/clients/videostreams/pubsub.go
+++ b/internal/clients/videostreams/pubsub.go
@@ -51,6 +51,10 @@ func NewBroker(logger pubsub.Logger) *Broker {
}
}
+func (b *Broker) Hub() *Hub {
+ return b.broker.Hub()
+}
+
func (b *Broker) PUB(topic string, h HandlerFunc, m ...MiddlewareFunc) *Route {
return b.broker.Add(pubsub.MethodPub, topic, h, m...)
}
@@ -67,11 +71,11 @@ func (b *Broker) Use(middleware ...MiddlewareFunc) {
b.broker.Use(middleware...)
}
-type BroadcastReceiver func(ctx context.Context, frames []Frame) (ok bool)
+type BroadcastReceiver func(ctx context.Context, frames []Frame) error
func (b *Broker) subscribe(
ctx context.Context, topic string, broadcastHandler BroadcastReceiver,
-) (unsubscriber func(), finished <-chan struct{}) {
+) (finished <-chan struct{}) {
// we keep this private because we're handling frames and we don't want a slow consumer to block
// every other consumer; the public Subscribe method drops frames for busy consumers
return b.broker.Subscribe(
@@ -87,8 +91,8 @@ func (b *Broker) subscribe(
func (b *Broker) Subscribe(ctx context.Context, topic string) <-chan Frame {
buffer := make(chan Frame, 1)
wg := sync.WaitGroup{}
- unsubscribe, finished := b.subscribe(
- ctx, topic, func(ctx context.Context, frames []Frame) (ok bool) {
+ finished := b.subscribe(
+ ctx, topic, func(ctx context.Context, frames []Frame) error {
wg.Add(1)
select {
case buffer <- frames[len(frames)-1]:
@@ -97,15 +101,11 @@ func (b *Broker) Subscribe(ctx context.Context, topic string) <-chan Frame {
// TODO: update a frames-dropped-per-sec counter
}
wg.Done()
- return true
+ return nil
},
)
go func() {
- select {
- case <-ctx.Done():
- case <-finished:
- }
- unsubscribe()
+ <-finished
wg.Wait() // prevent closing channel with pending sends, which is a data race
close(buffer)
}()
diff --git a/internal/clients/videostreams/stream.go b/internal/clients/videostreams/stream.go
index 20e143e..f5484d3 100644
--- a/internal/clients/videostreams/stream.go
+++ b/internal/clients/videostreams/stream.go
@@ -49,7 +49,7 @@ func (m *Metadata) WithSettings(settings Settings) *Metadata {
type Frame interface {
AsImageFrame() (*ImageFrame, error)
- AsJPEG() ([]byte, Operation, error)
+ AsJPEGFrame() (*JPEGFrame, error)
Error() error
}
@@ -71,22 +71,25 @@ func (f *ImageFrame) AsImageFrame() (*ImageFrame, error) {
return f, errors.Wrap(f.Err, "stream error")
}
-func (f *ImageFrame) AsJPEG() ([]byte, Operation, error) {
+func (f *ImageFrame) AsJPEGFrame() (*JPEGFrame, error) {
if f.Meta == nil {
- return nil, Nop, errors.Errorf("unspecified jpeg quality due to missing metadata")
+ return nil, errors.Errorf("unspecified jpeg quality due to missing metadata")
}
quality := f.Meta.Settings.JPEGEncodeQuality
if quality < 1 || quality > 100 {
- return nil, Nop, errors.Errorf("invalid jpeg quality %d", quality)
+ return nil, errors.Errorf("invalid jpeg quality %d", quality)
}
buf := new(bytes.Buffer)
if err := jpeg.Encode(buf, f.Im, &jpeg.Options{
Quality: quality,
}); err != nil {
- return nil, Nop, errors.Wrap(err, "couldn't jpeg-encode image")
+ return nil, errors.Wrap(err, "couldn't jpeg-encode image")
}
- return buf.Bytes(), Operationf("encode JPEG with quality %d", quality), nil
+ return &JPEGFrame{
+ Im: buf.Bytes(),
+ Meta: f.Meta.WithOp(Operationf("encode as JPEG with quality %d", quality)),
+ }, nil
}
func (f *ImageFrame) Error() error {
@@ -108,3 +111,31 @@ func (f *ImageFrame) WithAnnotation(annotations string, lines int) *ImageFrame {
Meta: f.Meta.WithOp(Operationf("annotate")),
}
}
+
+// JPEG Frame
+
+type JPEGFrame struct {
+ Im []byte
+ Meta *Metadata
+ Err error
+}
+
+func (f *JPEGFrame) AsImageFrame() (*ImageFrame, error) {
+ im, err := jpeg.Decode(bytes.NewReader(f.Im))
+ if err != nil {
+ return nil, err
+ }
+ return &ImageFrame{
+ Im: im,
+ Meta: f.Meta.WithOp("decode JPEG"),
+ Err: f.Err,
+ }, nil
+}
+
+func (f *JPEGFrame) AsJPEGFrame() (*JPEGFrame, error) {
+ return f, f.Err
+}
+
+func (f *JPEGFrame) Error() error {
+ return f.Err
+}
diff --git a/tools/go.mod b/tools/go.mod
index fceda4d..80a8afa 100644
--- a/tools/go.mod
+++ b/tools/go.mod
@@ -3,30 +3,31 @@ module github.com/sargassum-world/pslive/build
go 1.19
require (
- github.com/deepmap/oapi-codegen v1.12.2
+ github.com/deepmap/oapi-codegen v1.12.3
github.com/golangci/golangci-lint v1.50.1
- github.com/goreleaser/goreleaser v1.12.3
+ github.com/goreleaser/goreleaser v1.13.0
github.com/hairyhenderson/gomplate/v3 v3.11.3
- github.com/open-policy-agent/opa v0.45.0
+ github.com/open-policy-agent/opa v0.46.1
mvdan.cc/gofumpt v0.4.0
)
require (
4d63.com/gochecknoglobals v0.1.0 // indirect
- cloud.google.com/go v0.104.0 // indirect
- cloud.google.com/go/compute v1.11.0 // indirect
- cloud.google.com/go/iam v0.6.0 // indirect
- cloud.google.com/go/kms v1.5.0 // indirect
- cloud.google.com/go/storage v1.27.0 // indirect
+ cloud.google.com/go v0.107.0 // indirect
+ cloud.google.com/go/compute v1.12.1 // indirect
+ cloud.google.com/go/compute/metadata v0.2.1 // indirect
+ cloud.google.com/go/iam v0.7.0 // indirect
+ cloud.google.com/go/kms v1.6.0 // indirect
+ cloud.google.com/go/storage v1.28.0 // indirect
code.gitea.io/sdk/gitea v0.15.1 // indirect
github.com/Abirdcfly/dupword v0.0.7 // indirect
github.com/AlekSi/pointer v1.2.0 // indirect
github.com/Antonboom/errname v0.1.7 // indirect
github.com/Antonboom/nilnil v0.1.1 // indirect
- github.com/Azure/azure-sdk-for-go v67.0.0+incompatible // indirect
- github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 // indirect
- github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect
- github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect
+ github.com/Azure/azure-sdk-for-go v67.1.0+incompatible // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.2.0 // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0 // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
@@ -50,7 +51,7 @@ require (
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/OpenPeeDeeP/depguard v1.1.1 // indirect
- github.com/ProtonMail/go-crypto v0.0.0-20220930113650-c6815a8c17ad // indirect
+ github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 // indirect
github.com/Shopify/ejson v1.3.3 // indirect
github.com/acomagu/bufpipe v1.0.3 // indirect
github.com/agnivade/levenshtein v1.1.1 // indirect
@@ -62,13 +63,13 @@ require (
github.com/ashanbrown/forbidigo v1.3.0 // indirect
github.com/ashanbrown/makezero v1.1.1 // indirect
github.com/atc0005/go-teams-notify/v2 v2.6.1 // indirect
- github.com/aws/aws-sdk-go v1.44.123 // indirect
+ github.com/aws/aws-sdk-go v1.44.146 // indirect
github.com/aws/aws-sdk-go-v2 v1.17.1 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 // indirect
- github.com/aws/aws-sdk-go-v2/config v1.17.10 // indirect
- github.com/aws/aws-sdk-go-v2/credentials v1.12.23 // indirect
+ github.com/aws/aws-sdk-go-v2/config v1.18.3 // indirect
+ github.com/aws/aws-sdk-go-v2/credentials v1.13.3 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 // indirect
- github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.37 // indirect
+ github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.42 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 // indirect
@@ -77,11 +78,11 @@ require (
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.20 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 // indirect
- github.com/aws/aws-sdk-go-v2/service/kms v1.18.15 // indirect
- github.com/aws/aws-sdk-go-v2/service/s3 v1.29.1 // indirect
+ github.com/aws/aws-sdk-go-v2/service/kms v1.18.18 // indirect
+ github.com/aws/aws-sdk-go-v2/service/s3 v1.29.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect
- github.com/aws/aws-sdk-go-v2/service/sts v1.17.1 // indirect
+ github.com/aws/aws-sdk-go-v2/service/sts v1.17.5 // indirect
github.com/aws/smithy-go v1.13.4 // indirect
github.com/aymanbagabas/go-osc52 v1.2.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
@@ -100,31 +101,32 @@ require (
github.com/caarlos0/log v0.1.10 // indirect
github.com/cavaliergopher/cpio v1.0.1 // indirect
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
- github.com/cenkalti/backoff/v4 v4.1.3 // indirect
+ github.com/cenkalti/backoff/v4 v4.2.0 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/charithe/durationcheck v0.0.9 // indirect
github.com/charmbracelet/lipgloss v0.6.1-0.20220911181249-6304a734e792 // indirect
github.com/chavacava/garif v0.0.0-20220630083739-93517212f375 // indirect
- github.com/cloudflare/circl v1.2.0 // indirect
- github.com/containerd/containerd v1.6.8 // indirect
+ github.com/cloudflare/circl v1.3.0 // indirect
+ github.com/containerd/containerd v1.6.10 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/curioswitch/go-reassign v0.2.0 // indirect
github.com/daixiang0/gci v0.8.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/denis-tingaikin/go-header v0.4.3 // indirect
- github.com/dghubble/go-twitter v0.0.0-20221024160433-0cc1e72ed6d8 // indirect
+ github.com/dghubble/go-twitter v0.0.0-20221104224141-912508c3888b // indirect
github.com/dghubble/oauth1 v0.7.1 // indirect
github.com/dghubble/sling v1.4.0 // indirect
- github.com/dgraph-io/badger/v3 v3.2103.3 // indirect
+ github.com/dgraph-io/badger/v3 v3.2103.4 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
- github.com/disgoorg/disgo v0.13.20 // indirect
+ github.com/disgoorg/disgo v0.13.22 // indirect
+ github.com/disgoorg/json v1.0.0 // indirect
github.com/disgoorg/log v1.2.0 // indirect
github.com/disgoorg/snowflake/v2 v2.0.1 // indirect
- github.com/docker/cli v20.10.20+incompatible // indirect
+ github.com/docker/cli v20.10.21+incompatible // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
- github.com/docker/docker v20.10.20+incompatible // indirect
+ github.com/docker/docker v20.10.21+incompatible // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-metrics v0.0.1 // indirect
@@ -178,18 +180,18 @@ require (
github.com/golangci/misspell v0.3.5 // indirect
github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 // indirect
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect
- github.com/google/flatbuffers v22.9.29+incompatible // indirect
+ github.com/google/flatbuffers v22.11.23+incompatible // indirect
github.com/google/go-cmp v0.5.9 // indirect
- github.com/google/go-github/v48 v48.0.0 // indirect
+ github.com/google/go-github/v48 v48.1.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/google/wire v0.5.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
- github.com/googleapis/gax-go/v2 v2.6.0 // indirect
+ github.com/googleapis/gax-go/v2 v2.7.0 // indirect
github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 // indirect
github.com/goreleaser/chglog v0.2.2 // indirect
github.com/goreleaser/fileglob v1.3.0 // indirect
- github.com/goreleaser/nfpm/v2 v2.20.0 // indirect
+ github.com/goreleaser/nfpm/v2 v2.22.1 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/gosimple/slug v1.12.0 // indirect
@@ -198,7 +200,7 @@ require (
github.com/gostaticanalysis/comment v1.4.2 // indirect
github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect
github.com/gostaticanalysis/nilerr v0.1.1 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0 // indirect
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.14.0 // indirect
github.com/hairyhenderson/go-fsimpl v0.0.0-20220919132154-dc606beb8e19 // indirect
github.com/hairyhenderson/toml v0.4.2-0.20210923231440-40456b8e66cf // indirect
github.com/hairyhenderson/yaml v0.0.0-20220618171115-2d35fca545ce // indirect
@@ -224,11 +226,11 @@ require (
github.com/hashicorp/vault/sdk v0.6.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
- github.com/huandu/xstrings v1.3.2 // indirect
+ github.com/huandu/xstrings v1.3.3 // indirect
github.com/iancoleman/orderedmap v0.2.0 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
- github.com/invopop/jsonschema v0.6.0 // indirect
+ github.com/invopop/jsonschema v0.7.0 // indirect
github.com/invopop/yaml v0.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jgautheron/goconst v1.5.1 // indirect
@@ -242,7 +244,7 @@ require (
github.com/kisielk/errcheck v1.6.2 // indirect
github.com/kisielk/gotool v1.0.0 // indirect
github.com/kkHAIKE/contextcheck v1.1.3 // indirect
- github.com/klauspost/compress v1.15.11 // indirect
+ github.com/klauspost/compress v1.15.12 // indirect
github.com/klauspost/pgzip v1.2.5 // indirect
github.com/kulti/thelper v0.6.3 // indirect
github.com/kunwardeep/paralleltest v1.0.6 // indirect
@@ -262,8 +264,9 @@ require (
github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
+ github.com/mattn/go-mastodon v0.0.6 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
- github.com/matttproud/golang_protobuf_extensions v1.0.2 // indirect
+ github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mbilski/exhaustivestruct v1.2.0 // indirect
github.com/mgechev/revive v1.2.4 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
@@ -272,7 +275,7 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/locker v1.0.1 // indirect
- github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect
+ github.com/moby/term v0.0.0-20221128092401-c43b287e0e0f // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/moricho/tparallel v0.2.1 // indirect
github.com/morikuni/aec v1.0.0 // indirect
@@ -299,7 +302,7 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/polyfloyd/go-errorlint v1.0.5 // indirect
- github.com/prometheus/client_golang v1.13.0 // indirect
+ github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
@@ -308,7 +311,7 @@ require (
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
- github.com/rivo/uniseg v0.4.2 // indirect
+ github.com/rivo/uniseg v0.4.3 // indirect
github.com/rs/zerolog v1.28.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/ryancurrah/gomodguard v1.2.4 // indirect
@@ -325,7 +328,7 @@ require (
github.com/sivchari/containedctx v1.0.2 // indirect
github.com/sivchari/nosnakecase v1.7.0 // indirect
github.com/sivchari/tenv v1.7.0 // indirect
- github.com/slack-go/slack v0.11.3 // indirect
+ github.com/slack-go/slack v0.11.4 // indirect
github.com/sonatard/noctx v0.0.1 // indirect
github.com/sourcegraph/go-diff v0.6.1 // indirect
github.com/spf13/afero v1.9.2 // indirect
@@ -347,6 +350,7 @@ require (
github.com/timonwong/loggercheck v0.9.3 // indirect
github.com/tomarrell/wrapcheck/v2 v2.7.0 // indirect
github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect
+ github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect
github.com/ugorji/go/codec v1.2.7 // indirect
github.com/ulikunitz/xz v0.5.10 // indirect
github.com/ultraware/funlen v0.0.3 // indirect
@@ -355,8 +359,8 @@ require (
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1 // indirect
- github.com/xanzy/go-gitlab v0.73.1 // indirect
- github.com/xanzy/ssh-agent v0.3.2 // indirect
+ github.com/xanzy/go-gitlab v0.76.0 // indirect
+ github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/yagipy/maintidx v1.0.0 // indirect
@@ -366,8 +370,8 @@ require (
gitlab.com/bosi/decorder v0.2.3 // indirect
gitlab.com/digitalxero/go-conventional-commit v1.0.7 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
- go.opencensus.io v0.23.0 // indirect
- go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.3 // indirect
+ go.opencensus.io v0.24.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 // indirect
go.opentelemetry.io/otel v1.11.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.1 // indirect
@@ -383,23 +387,23 @@ require (
go4.org/intern v0.0.0-20220617035311-6925f38cc365 // indirect
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 // indirect
gocloud.dev v0.27.0 // indirect
- golang.org/x/crypto v0.1.0 // indirect
+ golang.org/x/crypto v0.3.0 // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91 // indirect
- golang.org/x/mod v0.6.0 // indirect
- golang.org/x/net v0.1.0 // indirect
- golang.org/x/oauth2 v0.1.0 // indirect
+ golang.org/x/mod v0.7.0 // indirect
+ golang.org/x/net v0.2.0 // indirect
+ golang.org/x/oauth2 v0.2.0 // indirect
golang.org/x/sync v0.1.0 // indirect
- golang.org/x/sys v0.1.0 // indirect
- golang.org/x/term v0.1.0 // indirect
+ golang.org/x/sys v0.2.0 // indirect
+ golang.org/x/term v0.2.0 // indirect
golang.org/x/text v0.4.0 // indirect
- golang.org/x/time v0.1.0 // indirect
- golang.org/x/tools v0.2.0 // indirect
+ golang.org/x/time v0.2.0 // indirect
+ golang.org/x/tools v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
- google.golang.org/api v0.101.0 // indirect
+ google.golang.org/api v0.103.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71 // indirect
- google.golang.org/grpc v1.50.1 // indirect
+ google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect
+ google.golang.org/grpc v1.51.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
diff --git a/tools/go.sum b/tools/go.sum
index 5ae50d9..5b1a2f2 100644
--- a/tools/go.sum
+++ b/tools/go.sum
@@ -38,8 +38,8 @@ cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w9
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU=
cloud.google.com/go v0.103.0/go.mod h1:vwLx1nqLrzLX/fpwSMOXmFIqBOyHsvHbnAdbGSJ+mKk=
-cloud.google.com/go v0.104.0 h1:gSmWO7DY1vOm0MVU6DNXM11BWHHsTUmsC5cv1fuW5X8=
-cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=
+cloud.google.com/go v0.107.0 h1:qkj22L7bgkl6vIeZDlOY2po43Mx/TIa2Wsa7VR+PEww=
+cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I=
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=
@@ -52,19 +52,22 @@ cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6m
cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
-cloud.google.com/go/compute v1.11.0 h1:0Xy75Dbf7s/nRAfAXwmunQ/ZFzfxd+bq/Z/WykCFa/M=
-cloud.google.com/go/compute v1.11.0/go.mod h1:nTnVHEoJMqp3oVjDINEiIcg/4nbiCcX77sSObqhsUyg=
+cloud.google.com/go/compute v1.12.1 h1:gKVJMEyqV5c/UnpzjjQbo3Rjvvqpr9B1DFSbJC4OXr0=
+cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU=
+cloud.google.com/go/compute/metadata v0.2.1 h1:efOwf5ymceDhK6PKMnnrTHP4pppY5L22mle96M1yP48=
+cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
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/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY=
cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c=
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
-cloud.google.com/go/iam v0.6.0 h1:nsqQC88kT5Iwlm4MeNGTpfMWddp6NB/UOLFTH6m1QfQ=
-cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc=
+cloud.google.com/go/iam v0.7.0 h1:k4MuwOsS7zGJJ+QfZ5vBK8SgHBAvYN/23BWsiihJ1vs=
+cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg=
cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA=
-cloud.google.com/go/kms v1.5.0 h1:uc58n3b/n/F2yDMJzHMbXORkJSh3fzO4/+jju6eR7Zg=
-cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg=
+cloud.google.com/go/kms v1.6.0 h1:OWRZzrPmOZUzurjI2FBGtgY2mB1WaJkqhw6oIwSj0Yg=
+cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0=
+cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs=
cloud.google.com/go/monitoring v1.1.0/go.mod h1:L81pzz7HKn14QCMaCs6NTQkdBnE87TElyanS95vIcl4=
cloud.google.com/go/monitoring v1.5.0/go.mod h1:/o9y8NYX5j91JjD/JvGLYbi86kL11OjyJXq2XziLJu4=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
@@ -82,8 +85,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc=
cloud.google.com/go/storage v1.24.0/go.mod h1:3xrJEFMXBsQLgxwThyjuD3aYlroL0TMRec1ypGUQ0KE=
-cloud.google.com/go/storage v1.27.0 h1:YOO045NZI9RKfCj1c5A/ZtuuENUc8OAW+gHdGnDgyMQ=
-cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s=
+cloud.google.com/go/storage v1.28.0 h1:DLrIZ6xkeZX6K70fU/boWx5INJumt6f+nwwWSHXzzGY=
+cloud.google.com/go/storage v1.28.0/go.mod h1:qlgZML35PXA3zoEnIkiPLY4/TOkUleufRlu6qmcf7sI=
cloud.google.com/go/trace v1.0.0/go.mod h1:4iErSByzxkyHWzzlAj63/Gmjz0NH1ASqhJguHpGcr6A=
cloud.google.com/go/trace v1.2.0/go.mod h1:Wc8y/uYyOhPy12KEnXG9XGrvfMz5F5SrYecQlbW1rwM=
code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8=
@@ -108,21 +111,21 @@ github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9mo
github.com/Azure/azure-sdk-for-go v63.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v65.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v66.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go v67.0.0+incompatible h1:SVBwznSETB0Sipd0uyGJr7khLhJOFRUEUb+0JgkCvDo=
-github.com/Azure/azure-sdk-for-go v67.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/azure-sdk-for-go v67.1.0+incompatible h1:oziYcaopbnIKfM69DL05wXdypiqfrUKdxUKrKpynJTw=
+github.com/Azure/azure-sdk-for-go v67.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4 h1:pqrAR74b6EoR4kcxF7L7Wg2B8Jgil9UUZtMvxhEFqWo=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.4/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.2.0 h1:sVW/AFBTGyJxDaMYlq0ct3jUXTtj12tQ6zE2GZUgVQw=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.2.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0/go.mod h1:+6sju8gk8FRmSajX3Oz4G5Gm7P+mbqE9FVaXXFYTkCM=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0 h1:t/W5MYAuQy81cvM8VUNfRLzhtKpXhVUAN7Cd7KVbTyc=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0/go.mod h1:NBanQUfSWiWn3QEpWDTCU0IjBECKOYvl2R8xdRtMtiM=
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 h1:XUNQ4mw+zJmaA2KXzP9JlQiecy1SI+Eog7xVkPiqIbg=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.1 h1:Oj853U9kG+RLTCQXpjvOnrv0WaZHxgmZz1TlLywgOPY=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.1.1/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.0.2/go.mod h1:LH9XQnMr2ZYxQdVdCrzLO9mxeDyrDFa6wbSI3x5zCZk=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1 h1:QSdcrd/UFJv6Bp/CfoVf2SrENpFn9P6Yh8yb+xNhYMM=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1/go.mod h1:eZ4g6GUvXiGulfIbbhh1Xr4XwUYaYaWMqzGD/284wCA=
@@ -215,7 +218,7 @@ github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwT
github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
-github.com/Microsoft/hcsshim v0.9.4 h1:mnUj0ivWy6UzbB1uLFqKR6F+ZyiDc7j4iGgHTpO+5+I=
+github.com/Microsoft/hcsshim v0.9.5 h1:AbV+VPfTrIVffukazHcpxmz/sRiE6YaMDzHWR9BXZHo=
github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
@@ -226,8 +229,8 @@ github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdII
github.com/OpenPeeDeeP/depguard v1.1.1 h1:TSUznLjvp/4IUP+OQ0t/4jF4QUyxIcVX8YnghZdunyA=
github.com/OpenPeeDeeP/depguard v1.1.1/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT9jnRVsohBKpc=
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
-github.com/ProtonMail/go-crypto v0.0.0-20220930113650-c6815a8c17ad h1:QeeqI2zxxgZVe11UrYFXXx6gVxPVF40ygekjBzEg4XY=
-github.com/ProtonMail/go-crypto v0.0.0-20220930113650-c6815a8c17ad/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8=
+github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4 h1:ra2OtmuW0AE5csawV4YXMNGNQQXvLRps3z2Z59OPO+I=
+github.com/ProtonMail/go-crypto v0.0.0-20221026131551-cf6655e29de4/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8=
github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f h1:CGq7OieOz3wyQJ1fO8S0eO9TCW1JyvLrf8fhzz1i8ko=
github.com/ProtonMail/gopenpgp/v2 v2.2.2 h1:u2m7xt+CZWj88qK1UUNBoXeJCFJwJCZ/Ff4ymGoxEXs=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
@@ -299,8 +302,8 @@ github.com/aws/aws-sdk-go v1.43.11/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4
github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.45/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.68/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
-github.com/aws/aws-sdk-go v1.44.123 h1:+vVGJ7+vQU6/wRcgRwSBBrIuG/lLL/0LB3HlN5jFv3c=
-github.com/aws/aws-sdk-go v1.44.123/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
+github.com/aws/aws-sdk-go v1.44.146 h1:7YdGgPxDPRJu/yYffzZp/H7yHzQ6AqmuNFZPYraaN8I=
+github.com/aws/aws-sdk-go v1.44.146/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/aws/aws-sdk-go-v2 v1.16.8/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4eAf4RcEyuw=
github.com/aws/aws-sdk-go-v2 v1.17.1 h1:02c72fDJr87N8RAC2s3Qu0YuvMRZKNZJ9F+lAehCazk=
@@ -309,17 +312,17 @@ github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3/go.mod h1:gNsR5CaXK
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 h1:RKci2D7tMwpvGpDNZnGQw9wk6v7o/xSwFcUAuNPoB8k=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9/go.mod h1:vCmV1q1VK8eoQJ5+aYE7PkK1K6v41qJ5pJdK3ggCDvg=
github.com/aws/aws-sdk-go-v2/config v1.15.15/go.mod h1:A1Lzyy/o21I5/s2FbyX5AevQfSVXpvvIDCoVFD0BC4E=
-github.com/aws/aws-sdk-go-v2/config v1.17.10 h1:zBy5QQ/mkvHElM1rygHPAzuH+sl8nsdSaxSWj0+rpdE=
-github.com/aws/aws-sdk-go-v2/config v1.17.10/go.mod h1:/4np+UiJJKpWHN7Q+LZvqXYgyjgeXm5+lLfDI6TPZao=
+github.com/aws/aws-sdk-go-v2/config v1.18.3 h1:3kfBKcX3votFX84dm00U8RGA1sCCh3eRMOGzg5dCWfU=
+github.com/aws/aws-sdk-go-v2/config v1.18.3/go.mod h1:BYdrbeCse3ZnOD5+2/VE/nATOK8fEUpBtmPMdKSyhMU=
github.com/aws/aws-sdk-go-v2/credentials v1.12.10/go.mod h1:g5eIM5XRs/OzIIK81QMBl+dAuDyoLN0VYaLP+tBqEOk=
-github.com/aws/aws-sdk-go-v2/credentials v1.12.23 h1:LctvcJMIb8pxvk5hQhChpCu0WlU6oKQmcYb1HA4IZSA=
-github.com/aws/aws-sdk-go-v2/credentials v1.12.23/go.mod h1:0awX9iRr/+UO7OwRQFpV1hNtXxOVuehpjVEzrIAYNcA=
+github.com/aws/aws-sdk-go-v2/credentials v1.13.3 h1:ur+FHdp4NbVIv/49bUjBW+FE7e57HOo03ELodttmagk=
+github.com/aws/aws-sdk-go-v2/credentials v1.13.3/go.mod h1:/rOMmqYBcFfNbRPU0iN9IgGqD5+V2yp3iWNmIlz0wI4=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.9/go.mod h1:KDCCm4ONIdHtUloDcFvK2+vshZvx4Zmj7UMDfusuz5s=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 h1:E3PXZSI3F2bzyj6XxUXdTIfvp425HHhwKsFvmzBwHgs=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19/go.mod h1:VihW95zQpeKQWVPGkwT+2+WJNQV8UXFfMTWdU6VErL8=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.21/go.mod h1:iIYPrQ2rYfZiB/iADYlhj9HHZ9TTi6PqKQPAqygohbE=
-github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.37 h1:e1VtTBo+cLNjres0wTlMkmwCGGRjDEkkrz3frxxcaCs=
-github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.37/go.mod h1:kdAV1UMnCkyG6tZJUC4mHbPoRjPA3dIK0L8mnsHERiM=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.42 h1:bxgBYvvBh+W1RnNYP4ROXEB8N+HSSucDszfE7Rb+kfU=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.42/go.mod h1:LHOsygMiW/14CkFxdXxvzKyMh3jbk/QfZVaDtCbLkl8=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.15/go.mod h1:pWrr2OoHlT7M/Pd2y4HV3gJyPb3qj5qMmnPkKSNPYK4=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 h1:nBO/RFxeq/IS5G9Of+ZrgucRciie2qpLy++3UGZ+q2E=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25/go.mod h1:Zb29PYkf42vVYQY6pvSyJCJcFHlPIiY+YKdPtwnvMkY=
@@ -345,11 +348,11 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.9/go.mod h1:Rc5+wn2
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 h1:piDBAaWkaxkkVV3xJJbTehXCZRXYs49kvpi/LG6LR2o=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19/go.mod h1:BmQWRVkLTmyNzYPFAZgon53qKLWBNSvonugD1MrSWUs=
github.com/aws/aws-sdk-go-v2/service/kms v1.18.1/go.mod h1:4PZMUkc9rXHWGVB5J9vKaZy3D7Nai79ORworQ3ASMiM=
-github.com/aws/aws-sdk-go-v2/service/kms v1.18.15 h1:hWPFd4GjCZLTb9Nvw+GuzZ4qTnvWoaqcLcrgofQGkhw=
-github.com/aws/aws-sdk-go-v2/service/kms v1.18.15/go.mod h1:kZodDPTQjSH/qM6/OvyTfM5mms5JHB/EKYp5dhn/vI4=
+github.com/aws/aws-sdk-go-v2/service/kms v1.18.18 h1:VEj0VdYbmx12y3GKWSXm8hB/mPuSaYHnECRhokHy4Wo=
+github.com/aws/aws-sdk-go-v2/service/kms v1.18.18/go.mod h1:kZodDPTQjSH/qM6/OvyTfM5mms5JHB/EKYp5dhn/vI4=
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.2/go.mod h1:u+566cosFI+d+motIz3USXEh6sN8Nq4GrNXSg2RXVMo=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.29.1 h1:/EMdFPW/Ppieh0WUtQf1+qCGNLdsq5UWUyevBQ6vMVc=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.29.1/go.mod h1:/NHbqPRiwxSPVOB2Xr+StDEH+GWV/64WwnUjv4KYzV0=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.29.4 h1:QgmmWifaYZZcpaw3y1+ccRlgH6jAvLm4K/MBGUc7cNM=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.29.4/go.mod h1:/NHbqPRiwxSPVOB2Xr+StDEH+GWV/64WwnUjv4KYzV0=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.14/go.mod h1:xakbH8KMsQQKqzX87uyyzTHshc/0/Df8bsTneTS5pFU=
github.com/aws/aws-sdk-go-v2/service/sns v1.17.10/go.mod h1:uITsRNVMeCB3MkWpXxXw0eDz8pW4TYLzj+eyQtbhSxM=
github.com/aws/aws-sdk-go-v2/service/sqs v1.19.1/go.mod h1:A94o564Gj+Yn+7QO1eLFeI7UVv3riy/YBFOfICVqFvU=
@@ -360,8 +363,8 @@ github.com/aws/aws-sdk-go-v2/service/sso v1.11.25/go.mod h1:IARHuzTXmj1C0KS35vbo
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 h1:jcw6kKZrtNfBPJkaHrscDOZoe5gvi9wjudnxvozYFJo=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8/go.mod h1:er2JHN+kBY6FcMfcBBKNGCT3CarImmdFzishsqBmSRI=
github.com/aws/aws-sdk-go-v2/service/sts v1.16.10/go.mod h1:cftkHYN6tCDNfkSasAmclSfl4l7cySoay8vz7p/ce0E=
-github.com/aws/aws-sdk-go-v2/service/sts v1.17.1 h1:KRAix/KHvjGODaHAMXnxRk9t0D+4IJVUuS/uwXxngXk=
-github.com/aws/aws-sdk-go-v2/service/sts v1.17.1/go.mod h1:bXcN3koeVYiJcdDU89n3kCYILob7Y34AeLopUbZgLT4=
+github.com/aws/aws-sdk-go-v2/service/sts v1.17.5 h1:60SJ4lhvn///8ygCzYy2l53bFW/Q15bVfyjyAWo6zuw=
+github.com/aws/aws-sdk-go-v2/service/sts v1.17.5/go.mod h1:bXcN3koeVYiJcdDU89n3kCYILob7Y34AeLopUbZgLT4=
github.com/aws/smithy-go v1.12.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/aws/smithy-go v1.13.4 h1:/RN2z1txIJWeXeOkzX+Hk/4Uuvv7dWtCjbmVJcrskyk=
github.com/aws/smithy-go v1.13.4/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
@@ -408,7 +411,6 @@ github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3k
github.com/butuzov/ireturn v0.1.1 h1:QvrO2QF2+/Cx1WA/vETCIYBKtRjc30vesdoPUNo1EbY=
github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc=
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
-github.com/bwesterb/go-ristretto v1.2.1/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/bytecodealliance/wasmtime-go v1.0.0 h1:9u9gqaUiaJeN5IoD1L7egD8atOnTGyJcNp8BhkL9cUU=
github.com/bytecodealliance/wasmtime-go v1.0.0/go.mod h1:jjlqQbWUfVSbehpErw3UoWFndBXRRMvfikYH6KsCwOg=
github.com/caarlos0/ctrlc v1.2.0 h1:AtbThhmbeYx1WW3WXdWrd94EHKi+0NPRGS4/4pzrjwk=
@@ -433,8 +435,9 @@ github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTx
github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
-github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4=
github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
+github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4=
+github.com/cenkalti/backoff/v4 v4.2.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
@@ -471,8 +474,8 @@ github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
-github.com/cloudflare/circl v1.2.0 h1:NheeISPSUcYftKlfrLuOo4T62FkmD4t4jviLfFFYaec=
-github.com/cloudflare/circl v1.2.0/go.mod h1:Ch2UgYr6ti2KTtlejELlROl0YIYj7SLjAC8M+INXlMk=
+github.com/cloudflare/circl v1.3.0 h1:Anq00jxDtoyX3+aCaYUZ0vXC5r4k4epberfWGDXV1zE=
+github.com/cloudflare/circl v1.3.0/go.mod h1:+CauBF6R70Jqcyl8N2hC8pAXYbWkGIezuSbuGLtRhnw=
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=
@@ -528,8 +531,8 @@ github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTV
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s=
github.com/containerd/containerd v1.6.1/go.mod h1:1nJz5xCZPusx6jJU8Frfct988y0NpumIq9ODB0kLtoE=
-github.com/containerd/containerd v1.6.8 h1:h4dOFDwzHmqFEP754PgfgTeVXFnLiRc6kiqC7tplDJs=
-github.com/containerd/containerd v1.6.8/go.mod h1:By6p5KqPK0/7/CgO/A6t/Gz+CUYUu2zf1hUaaymVXB0=
+github.com/containerd/containerd v1.6.10 h1:8aiav7I2ZyQLbTlNMcBXyAU1FtFvp6VuyuW13qSd6Hk=
+github.com/containerd/containerd v1.6.10/go.mod h1:CVqfxdJ95PDgORwA219AwwLrREZgrTFybXu2HfMKRG0=
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@@ -631,22 +634,22 @@ github.com/daixiang0/gci v0.8.1/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+M
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/deepmap/oapi-codegen v1.12.2 h1:F7SMEn0UMpJV6kWwDYqfDmnnOYHIcU7ETV8qTVFdyI0=
-github.com/deepmap/oapi-codegen v1.12.2/go.mod h1:ao2aFwsl/muMHbez870+KelJ1yusV01RznwAFFrVjDc=
+github.com/deepmap/oapi-codegen v1.12.3 h1:+DDYKeIwlKChzHjhVtlISegatFevDDazBhtk/dnp4V4=
+github.com/deepmap/oapi-codegen v1.12.3/go.mod h1:ao2aFwsl/muMHbez870+KelJ1yusV01RznwAFFrVjDc=
github.com/denis-tingaikin/go-header v0.4.3 h1:tEaZKAlqql6SKCY++utLmkPLd6K8IBM20Ha7UVm+mtU=
github.com/denis-tingaikin/go-header v0.4.3/go.mod h1:0wOCWuN71D5qIgE2nz9KrKmuYBAC2Mra5RassOIQ2/c=
github.com/denisenkom/go-mssqldb v0.12.2/go.mod h1:lnIw1mZukFRZDJYQ0Pb833QS2IaC3l5HkEfra2LJ+sk=
github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA=
github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
-github.com/dghubble/go-twitter v0.0.0-20221024160433-0cc1e72ed6d8 h1:ZrkR0vW8jXGy3wxfyEc20au8lqNJU8yn6g19I4AdzfQ=
-github.com/dghubble/go-twitter v0.0.0-20221024160433-0cc1e72ed6d8/go.mod h1:B0/qdW5XUupJvcsx40hnVbfjzz9He5YpYXx6eVVdiSY=
+github.com/dghubble/go-twitter v0.0.0-20221104224141-912508c3888b h1:XQu6o3AwJx/jsg9LZ41uIeUdXK5be099XFfFn6H9ikk=
+github.com/dghubble/go-twitter v0.0.0-20221104224141-912508c3888b/go.mod h1:B0/qdW5XUupJvcsx40hnVbfjzz9He5YpYXx6eVVdiSY=
github.com/dghubble/oauth1 v0.7.1 h1:JjbOVSVVkms9A4h/sTQy5Jb2nFuAAVb2qVYgenJPyrE=
github.com/dghubble/oauth1 v0.7.1/go.mod h1:0eEzON0UY/OLACQrmnjgJjmvCGXzjBCsZqL1kWDXtF0=
github.com/dghubble/sling v1.4.0 h1:/n8MRosVTthvMbwlNZgLx579OGVjUOy3GNEv5BIqAWY=
github.com/dghubble/sling v1.4.0/go.mod h1:0r40aNsU9EdDUVBNhfCstAtFgutjgJGYbO1oNzkMoM8=
-github.com/dgraph-io/badger/v3 v3.2103.3 h1:s63J1pisDhKpzWslXFe+ChuthuZptpwTE6qEKoczPb4=
-github.com/dgraph-io/badger/v3 v3.2103.3/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw=
+github.com/dgraph-io/badger/v3 v3.2103.4 h1:WE1B07YNTTJTtG9xjBcSW2wn0RJLyiV99h959RKZqM4=
+github.com/dgraph-io/badger/v3 v3.2103.4/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw=
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
@@ -661,8 +664,10 @@ github.com/digitalocean/godo v1.78.0/go.mod h1:GBmu8MkjZmNARE7IXRPmkbbnocNN8+uBm
github.com/digitalocean/godo v1.81.0/go.mod h1:BPCqvwbjbGqxuUnIKB4EvS/AX7IDnNmt5fwvIkWo+ew=
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
-github.com/disgoorg/disgo v0.13.20 h1:8TJndGmgF6ZdbMxlkjWPBDpMMFp5jCfMNgZwesQKwGA=
-github.com/disgoorg/disgo v0.13.20/go.mod h1:Cyip4bCYHD3rHgDhBPT9cLo81e9AMbDe8ocM50UNRM4=
+github.com/disgoorg/disgo v0.13.22 h1:Vf49TkfC5djuMTbS9qdg/pr/pCNUxHQtx8/dMPu3aWI=
+github.com/disgoorg/disgo v0.13.22/go.mod h1:YiVpXSmyXLRalYQHTHUFWEQvolCNzw0zh6nfug07b/M=
+github.com/disgoorg/json v1.0.0 h1:kDhSM661fgIuNoZF3BO5/odaR5NSq80AWb937DH+Pdo=
+github.com/disgoorg/json v1.0.0/go.mod h1:BHDwdde0rpQFDVsRLKhma6Y7fTbQKub/zdGO5O9NqqA=
github.com/disgoorg/log v1.2.0 h1:sqlXnu/ZKAlIlHV9IO+dbMto7/hCQ474vlIdMWk8QKo=
github.com/disgoorg/log v1.2.0/go.mod h1:3x1KDG6DI1CE2pDwi3qlwT3wlXpeHW/5rVay+1qDqOo=
github.com/disgoorg/snowflake/v2 v2.0.1 h1:CuUxGLwggUxEswZOmZ+mZ5i0xSumQdXW9tXW7uGqe+0=
@@ -673,8 +678,8 @@ github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
-github.com/docker/cli v20.10.20+incompatible h1:lWQbHSHUFs7KraSN2jOJK7zbMS2jNCHI4mt4xUFUVQ4=
-github.com/docker/cli v20.10.20+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/cli v20.10.21+incompatible h1:qVkgyYUnOLQ98LtXBrwd/duVqPT2X4SHndOuGsfwyhU=
+github.com/docker/cli v20.10.21+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
@@ -683,8 +688,8 @@ github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4Kfc
github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.14+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker v20.10.20+incompatible h1:kH9tx6XO+359d+iAkumyKDc5Q1kOwPuAUaeri48nD6E=
-github.com/docker/docker v20.10.20+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v20.10.21+incompatible h1:UTLdBmHk3bEY+w8qeO5KttOhy6OmXWsl/FEet9Uswog=
+github.com/docker/docker v20.10.21+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
@@ -1021,8 +1026,8 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
-github.com/google/flatbuffers v22.9.29+incompatible h1:3UBb679lq3V/O9rgzoJmnkP1jJzmC9OdFzITUBkLU/A=
-github.com/google/flatbuffers v22.9.29+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
+github.com/google/flatbuffers v22.11.23+incompatible h1:334TygA7iuxt0hoamawsM36xoui01YiouEZnr0qeFMI=
+github.com/google/flatbuffers v22.11.23+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
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=
@@ -1041,8 +1046,8 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
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-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0=
-github.com/google/go-github/v48 v48.0.0 h1:9H5fWVXFK6ZsRriyPbjtnFAkJnoj0WKFtTYfpCRrTm8=
-github.com/google/go-github/v48 v48.0.0/go.mod h1:dDlehKBDo850ZPvCTK0sEqTCVWcrGl2LcDiajkYi89Y=
+github.com/google/go-github/v48 v48.1.0 h1:nqPqq+0oRY2AMR/SRskGrrP4nnewPB7e/m2+kbT/UvM=
+github.com/google/go-github/v48 v48.1.0/go.mod h1:dDlehKBDo850ZPvCTK0sEqTCVWcrGl2LcDiajkYi89Y=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
@@ -1100,8 +1105,8 @@ github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
-github.com/googleapis/gax-go/v2 v2.6.0 h1:SXk3ABtQYDT/OH8jAyvEOQ58mgawq5C4o/4/89qN2ZU=
-github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY=
+github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ=
+github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
@@ -1117,10 +1122,10 @@ github.com/goreleaser/chglog v0.2.2 h1:V7nf07baXtGAgGevvqgW2MM4kZ6gOr12vKNSAU3VI
github.com/goreleaser/chglog v0.2.2/go.mod h1:2s5JwtCOWjZa8AIneL+xdUl9SRuigCjRHNHsX30dupE=
github.com/goreleaser/fileglob v1.3.0 h1:/X6J7U8lbDpQtBvGcwwPS6OpzkNVlVEsFUVRx9+k+7I=
github.com/goreleaser/fileglob v1.3.0/go.mod h1:Jx6BoXv3mbYkEzwm9THo7xbr5egkAraxkGorbJb4RxU=
-github.com/goreleaser/goreleaser v1.12.3 h1:sTJXdkGQO9eAP6pwEUazaD6ERJewZ7yzQexWEGPUVg4=
-github.com/goreleaser/goreleaser v1.12.3/go.mod h1:eBdKNaOsGUZWcSgXdMQliud+CiQhhO0m4cgSjb+S1ms=
-github.com/goreleaser/nfpm/v2 v2.20.0 h1:Q/CrX54KUMluz6+M/pjTbknFd5Dao8qXi0C6ZuFCtfY=
-github.com/goreleaser/nfpm/v2 v2.20.0/go.mod h1:/Fh6XfwT/T+D4qtNC2iXmHSD/1UT20JkvBXyJ6nFmOY=
+github.com/goreleaser/goreleaser v1.13.0 h1:wg7KX6osE+qm0ydBw/B00LQGqXD7qbGXPNDTyBPe/p4=
+github.com/goreleaser/goreleaser v1.13.0/go.mod h1:JFjB/kuTGFwpL3o9ix09K1ctGpABCk/xGIdoVDr0AJw=
+github.com/goreleaser/nfpm/v2 v2.22.1 h1:S5ShUIQYIB4uUiJmBy7S0w5SvZ2CwqBOvXNvRGnO6XE=
+github.com/goreleaser/nfpm/v2 v2.22.1/go.mod h1:c5/coiBdrKNdXXgKnSCrqSk8OtltpGwJ2woU/8EtHD4=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
@@ -1165,8 +1170,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.2/go.mod h1:chrfS3YoLAlKTRE5cFWvCbt8uGAjshktT4PveTUpsFQ=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0 h1:kr3j8iIMR4ywO/O0rvksXaJvauGGCMg2zAZIiNZ9uIQ=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0/go.mod h1:ummNFgdgLhhX7aIiy35vVmQNS0rWXknfPE0qe6fmFXg=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.14.0 h1:t7uX3JBHdVwAi3G7sSSdbsk8NfgA+LnUS88V/2EKaA0=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.14.0/go.mod h1:4OGVnY4qf2+gw+ssiHbW+pq4mo2yko94YxxMmXZ7jCA=
github.com/hairyhenderson/go-fsimpl v0.0.0-20220919132154-dc606beb8e19 h1:xR+VCv9O7oed+CEG+2cR+awTfKdl6S40xjB24V8OiUE=
github.com/hairyhenderson/go-fsimpl v0.0.0-20220919132154-dc606beb8e19/go.mod h1:LJFs5aPge/vPrwmUugi+uNrGpJGMLZtyl1S6zU8ssXo=
github.com/hairyhenderson/gomplate/v3 v3.11.3 h1:ovdPnPzn+T4AfIK7ulpCz6j0MRC+07lvH0A6Eh0tc9Q=
@@ -1276,8 +1281,8 @@ github.com/hetznercloud/hcloud-go v1.35.0/go.mod h1:mepQwR6va27S3UQthaEPGS86jtzS
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
-github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
+github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
github.com/iancoleman/orderedmap v0.2.0 h1:sq1N/TFpYH++aViPcaKjys3bDClUEU7s5B+z6jq8pNA=
@@ -1299,8 +1304,8 @@ github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7P
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ=
-github.com/invopop/jsonschema v0.6.0 h1:8e+xY8ZEn8gDHUYylSlLHy22P+SLeIRIHv3nM3hCbmY=
-github.com/invopop/jsonschema v0.6.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0=
+github.com/invopop/jsonschema v0.7.0 h1:2vgQcBz1n256N+FpX3Jq7Y17AjYt46Ig3zIWyy770So=
+github.com/invopop/jsonschema v0.7.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0=
github.com/invopop/yaml v0.1.0 h1:YW3WGUoJEXYfzWBjn00zIlrw7brGVD0fUKRYDPAPhrc=
github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
github.com/ionos-cloud/sdk-go/v6 v6.1.0/go.mod h1:Ox3W0iiEz0GHnfY9e5LmAxwklsxguuNFEUSu0gVRTME=
@@ -1408,8 +1413,8 @@ github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdY
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
-github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c=
-github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
+github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM=
+github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/kolo/xmlrpc v0.0.0-20201022064351-38db28db192b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM=
@@ -1509,6 +1514,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-mastodon v0.0.6 h1:lqU1sOeeIapaDsDUL6udDZIzMb2Wqapo347VZlaOzf0=
+github.com/mattn/go-mastodon v0.0.6/go.mod h1:cg7RFk2pcUfHZw/IvKe1FUzmlq5KnLFqs7eV2PHplV8=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
@@ -1523,8 +1530,8 @@ github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lL
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
-github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM=
-github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
+github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
github.com/mbilski/exhaustivestruct v1.2.0 h1:wCBmUnSYufAHO6J4AVWY6ff+oxWxsVFrwgOdMUQePUo=
github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc=
@@ -1575,8 +1582,8 @@ github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
-github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI=
-github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
+github.com/moby/term v0.0.0-20221128092401-c43b287e0e0f h1:J/7hjLaHLD7epG0m6TBMGmp4NQ+ibBYLfeyJWdAIFLA=
+github.com/moby/term v0.0.0-20221128092401-c43b287e0e0f/go.mod h1:15ce4BGCFxt7I5NQKT+HV0yEDxmf6fSysfEDiVo3zFM=
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=
@@ -1665,8 +1672,8 @@ github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDs
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
-github.com/open-policy-agent/opa v0.45.0 h1:P5nuhVRtR+e58fk3CMMbiqr6ZFyWQPNOC3otsorGsFs=
-github.com/open-policy-agent/opa v0.45.0/go.mod h1:/OnsYljNEWJ6DXeFOOnoGn8CvwZGMUS4iRqzYdJvmBI=
+github.com/open-policy-agent/opa v0.46.1 h1:iG998SLK0rzalex7Hyekeq17b9WtUexM0AuyHrQ7fCc=
+github.com/open-policy-agent/opa v0.46.1/go.mod h1:DY9ZkCyz+DKoWI5gDuLw5rGC2RSb37QUeEf+9VjsWkI=
github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -1771,8 +1778,8 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
-github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
-github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
+github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
+github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
@@ -1839,8 +1846,9 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5X
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-github.com/rivo/uniseg v0.4.2 h1:YwD0ulJSJytLpiaWua0sBDusfsCZohxjxzVTYjwxfV8=
github.com/rivo/uniseg v0.4.2/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
+github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@@ -1919,8 +1927,8 @@ github.com/sivchari/nosnakecase v1.7.0 h1:7QkpWIRMe8x25gckkFd2A5Pi6Ymo0qgr4JrhGt
github.com/sivchari/nosnakecase v1.7.0/go.mod h1:CwDzrzPea40/GB6uynrNLiorAlgFRvRbFSgJx2Gs+QY=
github.com/sivchari/tenv v1.7.0 h1:d4laZMBK6jpe5PWepxlV9S+LC0yXqvYHiq8E6ceoVVE=
github.com/sivchari/tenv v1.7.0/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg=
-github.com/slack-go/slack v0.11.3 h1:GN7revxEMax4amCc3El9a+9SGnjmBvSUobs0QnO6ZO8=
-github.com/slack-go/slack v0.11.3/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
+github.com/slack-go/slack v0.11.4 h1:ojSa7KlPm3PqY2AomX4VTxEsK5eci5JaxCjlzGV5zoM=
+github.com/slack-go/slack v0.11.4/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
@@ -2031,6 +2039,8 @@ github.com/tomarrell/wrapcheck/v2 v2.7.0 h1:J/F8DbSKJC83bAvC6FoZaRjZiZ/iKoueSdrE
github.com/tomarrell/wrapcheck/v2 v2.7.0/go.mod h1:ao7l5p0aOlUNJKI0qVwB4Yjlqutd0IvAB9Rdwyilxvg=
github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw=
github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw=
+github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y=
+github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
@@ -2070,11 +2080,11 @@ github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1 h1:+dBg5k7nuTE38VVdoroRsT0Z88fmvdYrI2EjzJst35I=
github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1/go.mod h1:nmuySobZb4kFgFy6BptpXp/BBw+xFSyvVPP6auoJB4k=
-github.com/xanzy/go-gitlab v0.73.1 h1:UMagqUZLJdjss1SovIC+kJCH4k2AZWXl58gJd38Y/hI=
-github.com/xanzy/go-gitlab v0.73.1/go.mod h1:d/a0vswScO7Agg1CZNz15Ic6SSvBG9vfw8egL99t4kA=
+github.com/xanzy/go-gitlab v0.76.0 h1:mkmuB27RDVZY/iXR61pEUfIqJ15Iivfu1kc3KZtBICI=
+github.com/xanzy/go-gitlab v0.76.0/go.mod h1:d/a0vswScO7Agg1CZNz15Ic6SSvBG9vfw8egL99t4kA=
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
-github.com/xanzy/ssh-agent v0.3.2 h1:eKj4SX2Fe7mui28ZgnFW5fmTz1EIr7ugo5s6wDxdHBM=
-github.com/xanzy/ssh-agent v0.3.2/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
+github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
+github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
@@ -2142,16 +2152,17 @@ 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 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0/go.mod h1:PFmBsWbldL1kiWZk9+0LBZz2brhByaGsvp6pRICMlPE=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.32.0/go.mod h1:5eCOqeGphOyz6TsY3ZDNjE33SM/TFAK3RGuCL2naTgY=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.3 h1:SGz6Fnp7blR+sskRZkyuFDb3qI1d8I0ygLh13F+sw6I=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.3/go.mod h1:+OXcluxum2GicWQ9lMXLQkLkOWoaw20OrVbYq6kkPks=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 h1:aUEBEdCa6iamGzg6fuYxDA8ThxvOG240mAvWDU+XLio=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4/go.mod h1:l2MdsbKTocpPS5nQZscqTR9jd8u96VYZdcpF8Sye7mA=
go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs=
go.opentelemetry.io/otel v1.6.0/go.mod h1:bfJD2DZVw0LBxghOTlgnlI0CV3hLDu9XF/QKOUXMTQQ=
@@ -2275,12 +2286,11 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
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-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
-golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
+golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
+golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
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=
@@ -2325,8 +2335,8 @@ golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
-golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
+golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
+golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
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=
@@ -2405,8 +2415,9 @@ golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220802222814-0bcc04d9c69b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
-golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
+golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
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=
@@ -2432,8 +2443,8 @@ golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7Lm
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
golang.org/x/oauth2 v0.0.0-20220628200809-02e64fa58f26/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
-golang.org/x/oauth2 v0.1.0 h1:isLCZuhj4v+tYv7eskaN4v/TM+A1begWWgyVJDdl1+Y=
-golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
+golang.org/x/oauth2 v0.2.0 h1:GtQkldQ9m7yvzCL1V+LrYow3Khe0eJH0w7RbX/VbaIU=
+golang.org/x/oauth2 v0.2.0/go.mod h1:Cwn6afJ8jrQwYMxQDTpISoXmXW9I6qF6vDeuuoX3Ibs=
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=
@@ -2585,7 +2596,6 @@ golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/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-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/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-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -2604,15 +2614,17 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
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=
@@ -2636,8 +2648,8 @@ golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220609170525-579cf78fd858/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.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
-golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE=
+golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -2748,8 +2760,8 @@ golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
-golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
+golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM=
+golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -2809,8 +2821,8 @@ google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6F
google.golang.org/api v0.86.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
google.golang.org/api v0.91.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
-google.golang.org/api v0.101.0 h1:lJPPeEBIRxGpGLwnBTam1NPEM8Z2BmmXEd3z812pjwM=
-google.golang.org/api v0.101.0/go.mod h1:CjxAAWWt3A3VrUE2IGDY2bgK5qhoG/OkyWVlYcP05MY=
+google.golang.org/api v0.103.0 h1:9yuVqlu2JCvcLg9p8S3fcFLZij8EPSyvODIY1rkMizQ=
+google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -2921,8 +2933,8 @@ google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljW
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
google.golang.org/genproto v0.0.0-20220802133213-ce4fa296bf78/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=
-google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71 h1:GEgb2jF5zxsFJpJfg9RoDDWm7tiwc/DDSTE2BtLUkXU=
-google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
+google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 h1:a2S6M0+660BgMNl++4JPlcAO/CjkqYItDEZwkoDQK7c=
+google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -2964,8 +2976,8 @@ google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY=
-google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
+google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U=
+google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
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=
diff --git a/web/app/package.json b/web/app/package.json
index ef6af3e..8b551cf 100644
--- a/web/app/package.json
+++ b/web/app/package.json
@@ -10,16 +10,16 @@
"lint:fix": "prettier --write ./src/**/*.{js,svelte,html} --no-error-on-unmatched-pattern && eslint --fix src/**/*.{js,svelte} --no-error-on-unmatched-pattern"
},
"devDependencies": {
- "@rollup/plugin-commonjs": "^23.0.2",
+ "@rollup/plugin-commonjs": "^23.0.3",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-replace": "^5.0.1",
"@sargassum-world/styles": "^0.2.2",
"bulma": "^0.9.4",
- "eslint": "^8.27.0",
+ "eslint": "^8.28.0",
"eslint-plugin-import": "^2.24.2",
"eslint-plugin-svelte3": "^4.0.0",
- "prettier": "^2.7.1",
- "prettier-plugin-svelte": "^2.8.0",
+ "prettier": "^2.8.0",
+ "prettier-plugin-svelte": "^2.8.1",
"purify-css": "^1.2.5",
"rollup": "^2.79.0",
"rollup-plugin-copy": "^3.4.0",
@@ -27,8 +27,8 @@
"rollup-plugin-scss": "^3.0.0",
"rollup-plugin-svelte": "^7.0.0",
"rollup-plugin-terser": "^7.0.0",
- "sass": "^1.56.0",
- "svelte": "^3.52.0",
+ "sass": "^1.56.1",
+ "svelte": "^3.53.1",
"svelte-check": "^2.9.2",
"svelte-dark-mode": "^2.0.0",
"svelte-preprocess": "^4.10.7"
@@ -36,9 +36,9 @@
"dependencies": {
"@fontsource/atkinson-hyperlegible": "^4.5.10",
"@fontsource/oxygen-mono": "^4.5.10",
- "@hotwired/stimulus": "^3.1.1",
+ "@hotwired/stimulus": "^3.2.0",
"@hotwired/turbo": "^7.2.2",
- "@sargassum-world/stimulated": "^0.4.5",
+ "@sargassum-world/stimulated": "^0.5.0",
"workbox-expiration": "^6.5.4",
"workbox-recipes": "^6.5.4",
"workbox-routing": "^6.5.4",
diff --git a/web/app/src/main-deferred.js b/web/app/src/main-deferred.js
index 0165466..2d7f508 100644
--- a/web/app/src/main-deferred.js
+++ b/web/app/src/main-deferred.js
@@ -3,6 +3,7 @@ import {
DefaultScrollableController,
FormSubmissionController,
HideableController,
+ ImageAutoreloadController,
LoadFocusController,
LoadScrollController,
NavigationLinkController,
@@ -10,10 +11,10 @@ import {
ThemeController,
TurboCableStreamSourceElement,
TurboCacheController,
- ImageAutoreloadController,
Turbo,
} from '@sargassum-world/stimulated';
import { Application } from '@hotwired/stimulus';
+import { VideoCablePlayerElement } from './sprinkles';
Turbo.session.drive = true;
@@ -21,6 +22,9 @@ customElements.define(
'turbo-cable-stream-source',
TurboCableStreamSourceElement,
);
+customElements.define('video-cable-player', VideoCablePlayerElement, {
+ extends: 'canvas',
+});
const Stimulus = Application.start();
Stimulus.register('csrf', CSRFController);
@@ -39,4 +43,10 @@ if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js');
}
+// Prevent noscript elements from being processed. Refer to
+// https://discuss.hotwired.dev/t/turbo-processes-noscript-children-when-merging-head/2552
+document.addEventListener('turbo:before-render', function (event) {
+ event.detail.newBody.querySelectorAll('noscript').forEach((e) => e.remove());
+});
+
export {};
diff --git a/web/app/src/sprinkles/index.js b/web/app/src/sprinkles/index.js
new file mode 100644
index 0000000..8c757a5
--- /dev/null
+++ b/web/app/src/sprinkles/index.js
@@ -0,0 +1 @@
+export { default as VideoCablePlayerElement } from './video-cable-player.element';
diff --git a/web/app/src/sprinkles/video-cable-player.element.js b/web/app/src/sprinkles/video-cable-player.element.js
new file mode 100644
index 0000000..4c66708
--- /dev/null
+++ b/web/app/src/sprinkles/video-cable-player.element.js
@@ -0,0 +1,48 @@
+import {
+ getActionCableConsumer,
+ attachCSRFToken,
+ makeWebSocketURL,
+} from '@sargassum-world/stimulated';
+
+export default class VideoCablePlayerElement extends HTMLCanvasElement {
+ async connectedCallback() {
+ if (document.documentElement.hasAttribute('data-turbo-preview')) {
+ return;
+ }
+ await attachCSRFToken(this);
+
+ // Initialize channel
+ const channel = {
+ channel: this.getAttribute('channel'),
+ name: this.getAttribute('name'),
+ integrity: this.getAttribute('integrity'),
+ };
+ if (this.hasAttribute('csrf-token')) {
+ channel.csrfToken = this.getAttribute('csrf-token');
+ }
+
+ // Subscribe
+ const consumer = getActionCableConsumer(
+ makeWebSocketURL(this.getAttribute('cable-route')),
+ // Warning: VideoCablePlayerElement assumes the use of a format which can serialize byte
+ // arrays, such as MessagePack - but not JSON!
+ this.getAttribute('websocket-subprotocol'),
+ );
+ this.subscription = consumer.subscriptions.create(channel, {
+ received: this.dispatchMessageEvent.bind(this),
+ });
+ }
+
+ disconnectedCallback() {
+ if (this.subscription) this.subscription.unsubscribe();
+ }
+
+ async dispatchMessageEvent(data) {
+ const bitmap = await createImageBitmap(
+ new Blob([data], { type: 'image/jpeg' }),
+ );
+ this.width = bitmap.width;
+ this.height = bitmap.height;
+ this.getContext('2d').drawImage(bitmap, 0, 0);
+ }
+}
diff --git a/web/app/yarn.lock b/web/app/yarn.lock
index b50e7ee..0194a01 100644
--- a/web/app/yarn.lock
+++ b/web/app/yarn.lock
@@ -2,6 +2,28 @@
# yarn lockfile v1
+"@anycable/core@^0.5.0":
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/@anycable/core/-/core-0.5.7.tgz#815460c4d7ed4cb9ca5a96afa13303b5d8e8d3e6"
+ integrity sha512-CWdr4eMrR3j+VOrVR97lvPywX4tvc7PiW5z7hl1GxhtPMojE36LTid+BQyHvEpQS7eA201W+By8jYNoJ0KpmMw==
+ dependencies:
+ nanoevents "^6.0.0"
+
+"@anycable/msgpack-encoder@^0.2.0":
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/@anycable/msgpack-encoder/-/msgpack-encoder-0.2.0.tgz#47166acd8c731b8273159ee5964d94d2496e3317"
+ integrity sha512-HUf7tXyqNZ23uwxgtHyNa9Pi984lTPpdZBdSWf7bep3a0PQ4W/YC3UIEGhGW3jvZwf0qO0/AwDECwWOa8Xc14A==
+ dependencies:
+ "@anycable/core" "^0.5.0"
+ "@ygoe/msgpack" "^1.0.0"
+
+"@anycable/web@^0.5.2":
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/@anycable/web/-/web-0.5.2.tgz#bfdb0ae925bd6017052eca0f713ec06fa1fb5d63"
+ integrity sha512-GveeZMBGpeSF//BB7NAnV6BJUj0DCVO2ORTxr1cun3z7WSHdd0MG6NPICb6EOKrFDbar5YpTq2eRoADnSpXA8g==
+ dependencies:
+ "@anycable/core" "^0.5.0"
+
"@babel/code-frame@^7.10.4":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789"
@@ -48,11 +70,16 @@
resolved "https://registry.yarnpkg.com/@fontsource/oxygen-mono/-/oxygen-mono-4.5.10.tgz#498362304a9dbcb04343bd562618e97f781a3e74"
integrity sha512-+SLEZx+WVbCRnJ3OpzXvjCm+VfbIkl0kOByUpjvT8bYqRegUxdWzSbXG95e8XPGMdK/tLS7gHcddN/1OV/R4SQ==
-"@hotwired/stimulus@3.1.1", "@hotwired/stimulus@^3.1.1":
+"@hotwired/stimulus@3.1.1":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.1.1.tgz#652f08a8e1d5edcb407340e58818fcff463b5848"
integrity sha512-e0JpzIaYLsRRXevRDVs0yevabiCvieIWWCwh7VqVXjXM5AOHdjb7AjaKIj34zYFmY1N6HIRRfk915WVMYlHnDA==
+"@hotwired/stimulus@^3.2.0":
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.2.0.tgz#257272f1348b1f7beb1a8510be88b80aec6c4c5b"
+ integrity sha512-uAIIdg049qId0lBhyjuMBfcC5uV8JwbhNLoxEyi9vxM3MW6h+mM97G9rNT4ZZMiqnKK9XUHp9SQUrd9rSLEmpQ==
+
"@hotwired/turbo@^7.0.1", "@hotwired/turbo@^7.2.2":
version "7.2.4"
resolved "https://registry.yarnpkg.com/@hotwired/turbo/-/turbo-7.2.4.tgz#0d35541be32cfae3b4f78c6ab9138f5b21f28a21"
@@ -138,15 +165,10 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
-"@rails/actioncable@^7.0.3-1":
- version "7.0.4"
- resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-7.0.4.tgz#70a3ca56809f7aaabb80af2f9c01ae51e1a8ed41"
- integrity sha512-tz4oM+Zn9CYsvtyicsa/AwzKZKL+ITHWkhiu7x+xF77clh2b4Rm+s6xnOgY/sGDWoFWZmtKsE95hxBPkgQQNnQ==
-
-"@rollup/plugin-commonjs@^23.0.2":
- version "23.0.2"
- resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-23.0.2.tgz#3a3a5b7b1b1cb29037eb4992edcaae997d7ebd92"
- integrity sha512-e9ThuiRf93YlVxc4qNIurvv+Hp9dnD+4PjOqQs5vAYfcZ3+AXSrcdzXnVjWxcGQOa6KGJFcRZyUI3ktWLavFjg==
+"@rollup/plugin-commonjs@^23.0.3":
+ version "23.0.3"
+ resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-23.0.3.tgz#442cd8ccca1b7563a503da86fc84a1a7112b54bb"
+ integrity sha512-31HxrT5emGfTyIfAs1lDQHj6EfYxTXcwtX5pIIhq+B/xZBNIqQ179d/CkYxlpYmFCxT78AeU4M8aL8Iv/IBxFA==
dependencies:
"@rollup/pluginutils" "^5.0.1"
commondir "^1.0.1"
@@ -184,14 +206,15 @@
estree-walker "^2.0.2"
picomatch "^2.3.1"
-"@sargassum-world/stimulated@^0.4.5":
- version "0.4.5"
- resolved "https://registry.yarnpkg.com/@sargassum-world/stimulated/-/stimulated-0.4.5.tgz#41d178fc08e670e9d039fba12aadf18d4bef0990"
- integrity sha512-VMIbGonCKParTHHxmBLWGaU07mU+n7+Tj6FuRodhX1bOgXG/TcNwgzlNDwyEjLq2df7Uhwfd/fzajsK9ItEflw==
+"@sargassum-world/stimulated@^0.5.0":
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/@sargassum-world/stimulated/-/stimulated-0.5.0.tgz#605ea76f487149f9a671d5153c05616873905aa2"
+ integrity sha512-KnH5ICBc/pzu9poqmrmVq3GjYmje+xWkUNBny+VQl5pTE3oyPUyfKaqo1DBL0ArCXS8jRB8Eopw2MFgzL6t31g==
dependencies:
+ "@anycable/msgpack-encoder" "^0.2.0"
+ "@anycable/web" "^0.5.2"
"@hotwired/stimulus" "3.1.1"
"@hotwired/turbo" "^7.0.1"
- "@rails/actioncable" "^7.0.3-1"
async-mutex "0.4.0"
"@sargassum-world/styles@^0.2.2":
@@ -256,6 +279,11 @@
dependencies:
"@types/node" "*"
+"@ygoe/msgpack@^1.0.0":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@ygoe/msgpack/-/msgpack-1.0.3.tgz#3889f4c0c2d68b2be83e1f6f4444efab02d6f257"
+ integrity sha512-Sjp0O/sNgOJxTOO1c2Zuu7nsHRIGu2iGPYyhUedKKbcHyUl73jbCaomEFJZHNb/6i94B+ZNZHVnFgpo0ENSXxQ==
+
acorn-jsx@^5.3.2:
version "5.3.2"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
@@ -765,10 +793,10 @@ eslint-visitor-keys@^3.3.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
-eslint@^8.27.0:
- version "8.27.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.27.0.tgz#d547e2f7239994ad1faa4bb5d84e5d809db7cf64"
- integrity sha512-0y1bfG2ho7mty+SiILVf9PfuRA49ek4Nc60Wmmu62QlobNR+CeXa4xXIJgcuwSQgZiWaPH+5BDsctpIW0PR/wQ==
+eslint@^8.28.0:
+ version "8.28.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.28.0.tgz#81a680732634677cc890134bcdd9fdfea8e63d6e"
+ integrity sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==
dependencies:
"@eslint/eslintrc" "^1.3.3"
"@humanwhocodes/config-array" "^0.11.6"
@@ -1540,6 +1568,11 @@ ms@^2.1.1:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+nanoevents@^6.0.0:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/nanoevents/-/nanoevents-6.0.2.tgz#3824031c7beab754b04ae5a17936c0fc7b6a183c"
+ integrity sha512-FRS2otuFcPPYDPYViNWQ42+1iZqbXydinkRHTHFxrF4a1CpBfmydR9zkI44WSXAXCyPrkcGtPk5CnpW6Y3lFKQ==
+
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
@@ -1743,15 +1776,15 @@ prelude-ls@^1.2.1:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
-prettier-plugin-svelte@^2.8.0:
- version "2.8.0"
- resolved "https://registry.yarnpkg.com/prettier-plugin-svelte/-/prettier-plugin-svelte-2.8.0.tgz#e5681d9867c4ab584c0ccbe43c3684d132b389f2"
- integrity sha512-QlXv/U3bUszks3XYDPsk1fsaQC+fo2lshwKbcbO+lrSVdJ+40mB1BfL8OCAk1W9y4pJxpqO/4gqm6NtF3zNGCw==
+prettier-plugin-svelte@^2.8.1:
+ version "2.8.1"
+ resolved "https://registry.yarnpkg.com/prettier-plugin-svelte/-/prettier-plugin-svelte-2.8.1.tgz#5b7df5bd0d953b133281607295a3e5131052bb8b"
+ integrity sha512-KA3K1J3/wKDnCxW7ZDRA/QL2Q67N7Xs3gOERqJ5X1qFjq1DdnN3K1R29scSKwh+kA8FF67pXbYytUpvN/i3iQw==
-prettier@^2.7.1:
- version "2.7.1"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64"
- integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==
+prettier@^2.8.0:
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.0.tgz#c7df58393c9ba77d6fba3921ae01faf994fb9dc9"
+ integrity sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==
pseudomap@^1.0.2:
version "1.0.2"
@@ -1971,10 +2004,10 @@ sander@^0.5.0:
mkdirp "^0.5.1"
rimraf "^2.5.2"
-sass@^1.56.0:
- version "1.56.0"
- resolved "https://registry.yarnpkg.com/sass/-/sass-1.56.0.tgz#134032075a3223c8d49cb5c35e091e5ba1de8e0a"
- integrity sha512-WFJ9XrpkcnqZcYuLRJh5qiV6ibQOR4AezleeEjTjMsCocYW59dEG19U3fwTTXxzi2Ed3yjPBp727hbbj53pHFw==
+sass@^1.56.1:
+ version "1.56.1"
+ resolved "https://registry.yarnpkg.com/sass/-/sass-1.56.1.tgz#94d3910cd468fd075fa87f5bb17437a0b617d8a7"
+ integrity sha512-VpEyKpyBPCxE7qGDtOcdJ6fFbcpOM+Emu7uZLxVrkX8KVU/Dp5UF7WLvzqRuUhB6mqqQt1xffLoG+AndxTZrCQ==
dependencies:
chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0"
@@ -2241,10 +2274,10 @@ svelte-preprocess@^4.0.0, svelte-preprocess@^4.10.7:
sorcery "^0.10.0"
strip-indent "^3.0.0"
-svelte@^3.52.0:
- version "3.52.0"
- resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.52.0.tgz#08259eff20904c63882b66a5d409a55e8c6743b8"
- integrity sha512-FxcnEUOAVfr10vDU5dVgJN19IvqeHQCS1zfe8vayTfis9A2t5Fhx+JDe5uv/C3j//bB1umpLJ6quhgs9xyUbCQ==
+svelte@^3.53.1:
+ version "3.53.1"
+ resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.53.1.tgz#db9d7df7a8f570e8e22547444c149208b1914442"
+ integrity sha512-Q4/hHkktZogGhN5iqxqSi9sjEVoe/NbIxX4hXEHoasTxj+TxEQVAq66LnDMdAZxjmsodkoI5F3slqsS68U7FNw==
terser@^5.0.0:
version "5.15.0"
diff --git a/web/policies/cable/routes.rego b/web/policies/cable/routes.rego
index db8293c..29944a6 100644
--- a/web/policies/cable/routes.rego
+++ b/web/policies/cable/routes.rego
@@ -10,6 +10,10 @@ in_scope if {
"/cable" == input.resource.path
}
+in_scope if {
+ "/video-cable" == input.resource.path
+}
+
# Policy Result & Error
allow if {
diff --git a/web/policies/instruments/routes.gen.rego b/web/policies/instruments/routes.gen.rego
index 660841b..144b5e9 100644
--- a/web/policies/instruments/routes.gen.rego
+++ b/web/policies/instruments/routes.gen.rego
@@ -226,6 +226,29 @@ allow if {
allow_camera_get(id, camera_id)
}
+matching_routes contains route if {
+ "SUB" == input.operation.method
+ ["instruments", id, "cameras", camera_id, "stream.mjpeg"] = split(trim_prefix(input.resource.path, "/"), "/")
+ route := "SUB /instruments/:id/cameras/:camera_id/stream.mjpeg"
+}
+
+allow if {
+ "SUB" == input.operation.method
+ ["instruments", id, "cameras", camera_id, "stream.mjpeg"] = split(trim_prefix(input.resource.path, "/"), "/")
+ allow_camera_get(id, camera_id)
+}
+
+matching_routes contains route if {
+ "UNSUB" == input.operation.method
+ ["instruments", id, "cameras", camera_id, "stream.mjpeg"] = split(trim_prefix(input.resource.path, "/"), "/")
+ route := "UNSUB /instruments/:id/cameras/:camera_id/stream.mjpeg"
+}
+
+allow if {
+ "UNSUB" == input.operation.method
+ ["instruments", id, "cameras", camera_id, "stream.mjpeg"] = split(trim_prefix(input.resource.path, "/"), "/")
+}
+
matching_routes contains route if {
"POST" == input.operation.method
["instruments", id, "controllers"] = split(trim_prefix(input.resource.path, "/"), "/")
diff --git a/web/policies/instruments/routes.rego.tmpl b/web/policies/instruments/routes.rego.tmpl
index b3370a2..7e89847 100644
--- a/web/policies/instruments/routes.rego.tmpl
+++ b/web/policies/instruments/routes.rego.tmpl
@@ -53,6 +53,13 @@ in_scope if {
coll.Slice "GET" "/instruments/:id/cameras/:camera_id/stream.mjpeg"
"allow_camera_get(id, camera_id)"
)
+ (
+ coll.Slice "SUB" "/instruments/:id/cameras/:camera_id/stream.mjpeg"
+ "allow_camera_get(id, camera_id)"
+ )
+ (
+ coll.Slice "UNSUB" "/instruments/:id/cameras/:camera_id/stream.mjpeg"
+ )
(coll.Slice "POST" "/instruments/:id/controllers" "allow_instrument_post(input.subject, id)")
(
coll.Slice "POST" "/instruments/:id/controllers/:controller_id"
diff --git a/web/policies/policies.gen.rego b/web/policies/policies.gen.rego
index bafb5f7..e945b5a 100644
--- a/web/policies/policies.gen.rego
+++ b/web/policies/policies.gen.rego
@@ -26,7 +26,7 @@ allow if {
assets.allow
}
-policy_errors["assets"] := error if {
+policy_errors.assets := error if {
some error in assets.errors
}
@@ -41,7 +41,7 @@ allow if {
auth.allow
}
-policy_errors["auth"] := error if {
+policy_errors.auth := error if {
some error in auth.errors
}
@@ -56,7 +56,7 @@ allow if {
cable.allow
}
-policy_errors["cable"] := error if {
+policy_errors.cable := error if {
some error in cable.errors
}
@@ -71,7 +71,7 @@ allow if {
home.allow
}
-policy_errors["home"] := error if {
+policy_errors.home := error if {
some error in home.errors
}
@@ -86,7 +86,7 @@ allow if {
instruments.allow
}
-policy_errors["instruments"] := error if {
+policy_errors.instruments := error if {
some error in instruments.errors
}
@@ -101,7 +101,7 @@ allow if {
privatechat.allow
}
-policy_errors["privatechat"] := error if {
+policy_errors.privatechat := error if {
some error in privatechat.errors
}
@@ -116,7 +116,7 @@ allow if {
users.allow
}
-policy_errors["users"] := error if {
+policy_errors.users := error if {
some error in users.errors
}
@@ -131,7 +131,7 @@ allow if {
videostreams.allow
}
-policy_errors["videostreams"] := error if {
+policy_errors.videostreams := error if {
some error in videostreams.errors
}
diff --git a/web/policies/shared/policy.partial.tmpl b/web/policies/shared/policy.partial.tmpl
index da266e5..81b0fb5 100644
--- a/web/policies/shared/policy.partial.tmpl
+++ b/web/policies/shared/policy.partial.tmpl
@@ -11,7 +11,7 @@ allow if {
{{$policy}}.allow
}
-policy_errors["{{$policy}}"] := error if {
+policy_errors.{{$policy}} := error if {
some error in {{$policy}}.errors
}
{{- /* This comment is just here to delete whitespace */ -}}
diff --git a/web/templates/instruments/instrument-live.partial.tmpl b/web/templates/instruments/instrument-live.partial.tmpl
index 10a3310..8662536 100644
--- a/web/templates/instruments/instrument-live.partial.tmpl
+++ b/web/templates/instruments/instrument-live.partial.tmpl
@@ -11,11 +11,10 @@
{{range $camera := $instrument.Cameras}}
{{if eq $camera.Protocol "mjpeg"}}
-
+ {{
+ template "shared/videostreams/video-cable-player.partial.tmpl"
+ (print "/instruments/" $instrument.ID "/cameras/" $camera.ID "/stream")
+ }}
{{else}}