diff --git a/.gitignore b/.gitignore index d11202d..b1be543 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ config.yaml mydb.sql /gordio +/calls Session.vim diff --git a/Makefile b/Makefile index 6c9938b..a31a040 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ all: go build -o gordio ./cmd/gordio/ + go build -o calls ./cmd/calls/ generate: sqlc generate -f sql/sqlc.yaml diff --git a/cmd/calls/main.go b/cmd/calls/main.go new file mode 100644 index 0000000..a756378 --- /dev/null +++ b/cmd/calls/main.go @@ -0,0 +1,140 @@ +package main + +import ( + "encoding/json" + "flag" + "log" + "net/http" + "net/http/cookiejar" + "net/url" + "os" + "os/signal" + "strings" + "time" + + "dynatron.me/x/stillbox/pkg/pb" + + "github.com/gorilla/websocket" + "google.golang.org/protobuf/proto" +) + +var ( + addr = flag.String("addr", "localhost:8080", "http service address") + username = flag.String("user", "", "username") + password = flag.String("password", "", "password") +) + +func main() { + flag.Parse() + log.SetFlags(0) + + interrupt := make(chan os.Signal, 1) + signal.Notify(interrupt, os.Interrupt) + + loginForm := url.Values{} + loginForm.Add("username", *username) + loginForm.Add("password", *password) + + loginReq, err := http.NewRequest("POST", "http://"+*addr+"/login", strings.NewReader(loginForm.Encode())) + if err != nil { + log.Fatal(err) + } + loginReq.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + jar, err := cookiejar.New(nil) + if err != nil { + log.Fatal(err) + } + + client := &http.Client{ + Jar: jar, + } + + resp, err := client.Do(loginReq) + if err != nil { + log.Fatal(err) + } + + jwt := struct { + JWT string `json:"jwt"` + }{} + + err = json.NewDecoder(resp.Body).Decode(&jwt) + if err != nil { + log.Fatal(err) + } + + u := url.URL{Scheme: "ws", Host: *addr, Path: "/ws"} + log.Printf("connecting to %s", u.String()) + + dialer := websocket.Dialer{ + Proxy: http.ProxyFromEnvironment, + HandshakeTimeout: 45 * time.Second, + Jar: jar, + } + c, _, err := dialer.Dial(u.String(), nil) + if err != nil { + log.Fatal("dial:", err) + } + defer c.Close() + + done := make(chan struct{}) + + go func() { + defer close(done) + for { + t, message, err := c.ReadMessage() + if err != nil { + log.Println("read:", err) + return + } + + if t == websocket.BinaryMessage { + var m pb.Message + + err := proto.Unmarshal(message, &m) + if err != nil { + log.Fatal(err) + } + + switch v := m.ToClientMessage.(type) { + case *pb.Message_Call: + case *pb.Message_Notification: + log.Println(v.Notification.Msg) + } + + } + } + }() + + ticker := time.NewTicker(time.Second) + defer ticker.Stop() + + for { + select { + case <-done: + return + case t := <-ticker.C: + err := c.WriteMessage(websocket.TextMessage, []byte(t.String())) + if err != nil { + log.Println("write:", err) + return + } + case <-interrupt: + log.Println("interrupt") + + // Cleanly close the connection by sending a close message and then + // waiting (with timeout) for the server to close the connection. + err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) + if err != nil { + log.Println("write close:", err) + return + } + select { + case <-done: + case <-time.After(time.Second): + } + return + } + } +} diff --git a/go.mod b/go.mod index 8f29d20..47d9e81 100644 --- a/go.mod +++ b/go.mod @@ -10,11 +10,13 @@ require ( github.com/go-chi/render v1.0.3 github.com/golang-migrate/migrate/v4 v4.17.1 github.com/google/uuid v1.4.0 + github.com/gorilla/websocket v1.5.3 github.com/jackc/pgx/v5 v5.6.0 github.com/rs/zerolog v1.33.0 github.com/spf13/cobra v1.8.1 golang.org/x/crypto v0.21.0 golang.org/x/term v0.18.0 + google.golang.org/protobuf v1.33.0 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index ba67e75..1e3ee8b 100644 --- a/go.sum +++ b/go.sum @@ -41,8 +41,12 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMnX7wLTPnnYO4= github.com/golang-migrate/migrate/v4 v4.17.1/go.mod h1:m8hinFyWBn0SA4QKHuKh175Pm9wjmxj3S2Mia7dbXzM= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -135,6 +139,10 @@ golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/gordio/auth/jwt.go b/pkg/gordio/auth/jwt.go index 710f4fc..cd834ce 100644 --- a/pkg/gordio/auth/jwt.go +++ b/pkg/gordio/auth/jwt.go @@ -2,6 +2,7 @@ package auth import ( "context" + "fmt" "net/http" "time" @@ -90,7 +91,7 @@ func (a *authenticator) newToken(uid int32) string { } func (a *authenticator) PublicRoutes(r chi.Router) { - r.Post("/auth", a.routeAuth) + r.Post("/login", a.routeAuth) } func (a *authenticator) routeAuth(w http.ResponseWriter, r *http.Request) { @@ -101,7 +102,7 @@ func (a *authenticator) routeAuth(w http.ResponseWriter, r *http.Request) { } username, password := r.PostFormValue("username"), r.PostFormValue("password") if username == "" || password == "" { - http.Error(w, "blank credentials", http.StatusBadRequest) + http.Error(w, "blank credentials"+fmt.Sprint(r.Form), http.StatusBadRequest) return } diff --git a/pkg/gordio/nexus/client.go b/pkg/gordio/nexus/client.go new file mode 100644 index 0000000..2d899cc --- /dev/null +++ b/pkg/gordio/nexus/client.go @@ -0,0 +1,63 @@ +package nexus + +import ( + "io" + "sync" + + "dynatron.me/x/stillbox/pkg/pb" + + "github.com/rs/zerolog/log" + "google.golang.org/protobuf/proto" +) + +type Client interface { + sync.Locker + + Connection + + Conn() Connection + HandleCommand(*pb.Command) + HandleMessage([]byte) +} + +type client struct { + sync.RWMutex + + Connection + + nexus *Nexus +} + +type Connection interface { + io.Closer + + Send(*pb.Message) +} + +func (n *Nexus) NewClient(conn Connection) Client { + sess := &client{ + Connection: conn, + nexus: n, + } + + return sess +} + +func (c *client) Registry() Registry { + return c.nexus +} + +func (c *client) Conn() Connection { + return c.Connection +} + +func (c *client) HandleMessage(mesgBytes []byte) { + var msg pb.Command + err := proto.Unmarshal(mesgBytes, &msg) + if err != nil { + log.Error().Err(err).Msg("command unmarshal") + return + } + + c.HandleCommand(&msg) +} diff --git a/pkg/gordio/nexus/commands.go b/pkg/gordio/nexus/commands.go new file mode 100644 index 0000000..58f81a6 --- /dev/null +++ b/pkg/gordio/nexus/commands.go @@ -0,0 +1,25 @@ +package nexus + +import ( + "dynatron.me/x/stillbox/pkg/pb" + + "github.com/rs/zerolog/log" +) + +func (c *client) HandleCommand(cmd *pb.Command) { + switch cc := cmd.Command.(type) { + case *pb.Command_LiveCommand: + c.Live(cc.LiveCommand) + case *pb.Command_SearchCommand: + default: + log.Error().Msgf("unknown command %T", cmd) + } +} + +func (c *client) Live(cmd *pb.Live) { + switch cmd.State { + case pb.LiveState_LS_STOPPED: + case pb.LiveState_LS_LIVE: + case pb.LiveState_LS_PAUSED: + } +} diff --git a/pkg/gordio/nexus/nexus.go b/pkg/gordio/nexus/nexus.go new file mode 100644 index 0000000..03175f2 --- /dev/null +++ b/pkg/gordio/nexus/nexus.go @@ -0,0 +1,43 @@ +package nexus + +import ( + "sync" +) + +type Nexus struct { + sync.RWMutex + + clients map[*client]struct{} + + *wsManager +} + +type Registry interface { + NewClient(Connection) Client + Register(Client) + Unregister(Client) +} + +func New() *Nexus { + n := &Nexus{ + clients: make(map[*client]struct{}), + } + + n.wsManager = newWsManager(n) + + return n +} + +func (n *Nexus) Register(c Client) { + n.Lock() + defer n.Unlock() + + n.clients[c.(*client)] = struct{}{} +} + +func (n *Nexus) Unregister(c Client) { + n.Lock() + defer n.Unlock() + + delete(n.clients, c.(*client)) +} diff --git a/pkg/gordio/nexus/websocket.go b/pkg/gordio/nexus/websocket.go new file mode 100644 index 0000000..faff1b8 --- /dev/null +++ b/pkg/gordio/nexus/websocket.go @@ -0,0 +1,158 @@ +package nexus + +import ( + "io" + "net/http" + "time" + + "dynatron.me/x/stillbox/pkg/pb" + + "github.com/go-chi/chi/v5" + "github.com/gorilla/websocket" + "github.com/rs/zerolog/log" + "google.golang.org/protobuf/proto" +) + +const ( + maxMessageSize = 1024 * 1024 * 10 // 10MB + + pongWait = 60 * time.Second + pingInterval = (pongWait * 9) / 10 + writeWait = 10 * time.Second + + qSize = 256 // 256 messages +) + +type wsManager struct { + Registry +} + +func newWsManager(r Registry) *wsManager { + return &wsManager{ + Registry: r, + } +} + +type wsConn struct { + *websocket.Conn + + out chan *pb.Message +} + +func (w *wsConn) Send(msg *pb.Message) { + w.out <- msg +} + +func newWsConn(c *websocket.Conn) *wsConn { + return &wsConn{ + Conn: c, + out: make(chan *pb.Message, qSize), + } +} + +var upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, +} + +func (wm *wsManager) serveWS(w http.ResponseWriter, r *http.Request) { + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + log.Error().Err(err).Msg("upgrade failed") + http.Error(w, "upgrade failed", http.StatusInternalServerError) + return + } + + cli := wm.NewClient(newWsConn(conn)) + wm.Register(cli) + + wsc := newWsConn(conn) + go wsc.readPump(wm, cli) + go wsc.writePump() +} + +func (conn *wsConn) readPump(reg Registry, c Client) { + defer func() { + reg.Unregister(c) + conn.Close() + }() + + conn.SetReadLimit(maxMessageSize) + conn.SetReadDeadline(time.Now().Add(pongWait)) + conn.SetPongHandler(func(string) error { + conn.SetReadDeadline(time.Now().Add(pongWait)) + return nil + }) + for { + _, message, err := conn.ReadMessage() + if err != nil { + if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) { + log.Error().Err(err).Msg("read failed") + } + + break + } + + go c.HandleMessage(message) + } +} + +func (conn *wsConn) writePump() { + pingTicker := time.NewTicker(pingInterval) + defer func() { + pingTicker.Stop() + conn.Close() + }() + + for { + select { + case msg, ok := <-conn.out: + conn.SetWriteDeadline(time.Now().Add(writeWait)) + if !ok { + // nexus closed + conn.WriteMessage(websocket.CloseMessage, []byte{}) + return + } + + w, err := conn.NextWriter(websocket.BinaryMessage) + if err != nil { + return + } + + conn.writeMessage(w, msg) + + if err := w.Close(); err != nil { + return + } + case <-pingTicker.C: + conn.SetWriteDeadline(time.Now().Add(writeWait)) + if err := conn.WriteMessage(websocket.PingMessage, nil); err != nil { + return + } + } + } +} + +func (conn *wsConn) writeMessage(w io.WriteCloser, msg *pb.Message) { + packWrite := func(msg *pb.Message) { + packed, err := proto.Marshal(msg) + if err != nil { + log.Error().Err(err).Msg("pack message") + return + } + + w.Write(packed) + } + + packWrite(msg) + + // add queued messages to current payload + nQ := len(conn.out) + for i := 0; i < nQ; i++ { + packWrite(<-conn.out) + } +} + +func (n *wsManager) InstallPrivateRoutes(r chi.Router) { + r.HandleFunc("/ws", n.serveWS) +} diff --git a/pkg/gordio/server/routes.go b/pkg/gordio/server/routes.go index 40180e8..214dce7 100644 --- a/pkg/gordio/server/routes.go +++ b/pkg/gordio/server/routes.go @@ -18,6 +18,7 @@ func (s *Server) setupRoutes() { r.Group(func(r chi.Router) { // authenticated routes r.Use(s.auth.AuthMiddleware(), s.auth.VerifyMiddleware()) + s.nex.InstallPrivateRoutes(r) }) r.Group(func(r chi.Router) { diff --git a/pkg/gordio/server/server.go b/pkg/gordio/server/server.go index ae846dc..0f4a4af 100644 --- a/pkg/gordio/server/server.go +++ b/pkg/gordio/server/server.go @@ -6,6 +6,7 @@ import ( "dynatron.me/x/stillbox/pkg/gordio/auth" "dynatron.me/x/stillbox/pkg/gordio/config" "dynatron.me/x/stillbox/pkg/gordio/database" + "dynatron.me/x/stillbox/pkg/gordio/nexus" "dynatron.me/x/stillbox/pkg/gordio/sinks" "dynatron.me/x/stillbox/pkg/gordio/sources" "github.com/go-chi/chi/middleware" @@ -19,6 +20,7 @@ type Server struct { r *chi.Mux sources sources.Sources sinks sinks.Sinks + nex *nexus.Nexus } func New(cfg *config.Config) (*Server, error) { @@ -34,6 +36,7 @@ func New(cfg *config.Config) (*Server, error) { conf: cfg, db: db, r: r, + nex: nexus.New(), } srv.sinks.Register("database", sinks.NewDatabaseSink(db)) diff --git a/pkg/gordio/ws/session.go b/pkg/gordio/ws/session.go deleted file mode 100644 index 1750483..0000000 --- a/pkg/gordio/ws/session.go +++ /dev/null @@ -1,13 +0,0 @@ -package ws - -import ( - "github.com/go-chi/chi/v5" - // "github.com/gorilla/websocket" -) - -type SessionManager struct { -} - -func (s *SessionManager) InstallPrivateRoutes(r chi.Router) { - -} diff --git a/pkg/pb/stillbox.pb.go b/pkg/pb/stillbox.pb.go index 4b6fdb2..22a2096 100644 --- a/pkg/pb/stillbox.pb.go +++ b/pkg/pb/stillbox.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 -// protoc v5.27.2 +// protoc v5.27.1 // source: stillbox.proto package pb @@ -21,14 +21,158 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type LiveState int32 + +const ( + LiveState_LS_STOPPED LiveState = 0 + LiveState_LS_LIVE LiveState = 1 + LiveState_LS_PAUSED LiveState = 2 +) + +// Enum value maps for LiveState. +var ( + LiveState_name = map[int32]string{ + 0: "LS_STOPPED", + 1: "LS_LIVE", + 2: "LS_PAUSED", + } + LiveState_value = map[string]int32{ + "LS_STOPPED": 0, + "LS_LIVE": 1, + "LS_PAUSED": 2, + } +) + +func (x LiveState) Enum() *LiveState { + p := new(LiveState) + *p = x + return p +} + +func (x LiveState) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (LiveState) Descriptor() protoreflect.EnumDescriptor { + return file_stillbox_proto_enumTypes[0].Descriptor() +} + +func (LiveState) Type() protoreflect.EnumType { + return &file_stillbox_proto_enumTypes[0] +} + +func (x LiveState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use LiveState.Descriptor instead. +func (LiveState) EnumDescriptor() ([]byte, []int) { + return file_stillbox_proto_rawDescGZIP(), []int{0} +} + +type Message struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to ToClientMessage: + // + // *Message_Call + // *Message_Notification + // *Message_Popup + ToClientMessage isMessage_ToClientMessage `protobuf_oneof:"toClient_message"` +} + +func (x *Message) Reset() { + *x = Message{} + if protoimpl.UnsafeEnabled { + mi := &file_stillbox_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Message) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Message) ProtoMessage() {} + +func (x *Message) ProtoReflect() protoreflect.Message { + mi := &file_stillbox_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Message.ProtoReflect.Descriptor instead. +func (*Message) Descriptor() ([]byte, []int) { + return file_stillbox_proto_rawDescGZIP(), []int{0} +} + +func (m *Message) GetToClientMessage() isMessage_ToClientMessage { + if m != nil { + return m.ToClientMessage + } + return nil +} + +func (x *Message) GetCall() *Call { + if x, ok := x.GetToClientMessage().(*Message_Call); ok { + return x.Call + } + return nil +} + +func (x *Message) GetNotification() *Notification { + if x, ok := x.GetToClientMessage().(*Message_Notification); ok { + return x.Notification + } + return nil +} + +func (x *Message) GetPopup() *UserPopup { + if x, ok := x.GetToClientMessage().(*Message_Popup); ok { + return x.Popup + } + return nil +} + +type isMessage_ToClientMessage interface { + isMessage_ToClientMessage() +} + +type Message_Call struct { + Call *Call `protobuf:"bytes,1,opt,name=call,proto3,oneof"` +} + +type Message_Notification struct { + Notification *Notification `protobuf:"bytes,2,opt,name=notification,proto3,oneof"` +} + +type Message_Popup struct { + Popup *UserPopup `protobuf:"bytes,3,opt,name=popup,proto3,oneof"` +} + +func (*Message_Call) isMessage_ToClientMessage() {} + +func (*Message_Notification) isMessage_ToClientMessage() {} + +func (*Message_Popup) isMessage_ToClientMessage() {} + type Call struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - AudioName string `protobuf:"bytes,1,opt,name=audio_name,json=audioName,proto3" json:"audio_name,omitempty"` - AudioType string `protobuf:"bytes,2,opt,name=audio_type,json=audioType,proto3" json:"audio_type,omitempty"` - DateTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=date_time,json=dateTime,proto3" json:"date_time,omitempty"` + AudioName string `protobuf:"bytes,1,opt,name=audioName,proto3" json:"audioName,omitempty"` + AudioType string `protobuf:"bytes,2,opt,name=audioType,proto3" json:"audioType,omitempty"` + DateTime *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=dateTime,proto3" json:"dateTime,omitempty"` System int32 `protobuf:"varint,4,opt,name=system,proto3" json:"system,omitempty"` Talkgroup int32 `protobuf:"varint,5,opt,name=talkgroup,proto3" json:"talkgroup,omitempty"` Source int32 `protobuf:"varint,6,opt,name=source,proto3" json:"source,omitempty"` @@ -42,7 +186,7 @@ type Call struct { func (x *Call) Reset() { *x = Call{} if protoimpl.UnsafeEnabled { - mi := &file_stillbox_proto_msgTypes[0] + mi := &file_stillbox_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -55,7 +199,7 @@ func (x *Call) String() string { func (*Call) ProtoMessage() {} func (x *Call) ProtoReflect() protoreflect.Message { - mi := &file_stillbox_proto_msgTypes[0] + mi := &file_stillbox_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -68,7 +212,7 @@ func (x *Call) ProtoReflect() protoreflect.Message { // Deprecated: Use Call.ProtoReflect.Descriptor instead. func (*Call) Descriptor() ([]byte, []int) { - return file_stillbox_proto_rawDescGZIP(), []int{0} + return file_stillbox_proto_rawDescGZIP(), []int{1} } func (x *Call) GetAudioName() string { @@ -148,35 +292,347 @@ func (x *Call) GetAudio() []byte { return nil } +type UserPopup struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Msg string `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"` +} + +func (x *UserPopup) Reset() { + *x = UserPopup{} + if protoimpl.UnsafeEnabled { + mi := &file_stillbox_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserPopup) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserPopup) ProtoMessage() {} + +func (x *UserPopup) ProtoReflect() protoreflect.Message { + mi := &file_stillbox_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserPopup.ProtoReflect.Descriptor instead. +func (*UserPopup) Descriptor() ([]byte, []int) { + return file_stillbox_proto_rawDescGZIP(), []int{2} +} + +func (x *UserPopup) GetMsg() string { + if x != nil { + return x.Msg + } + return "" +} + +type Notification struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + DateTime *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=dateTime,proto3" json:"dateTime,omitempty"` + Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` + ActionUrl string `protobuf:"bytes,3,opt,name=actionUrl,proto3" json:"actionUrl,omitempty"` +} + +func (x *Notification) Reset() { + *x = Notification{} + if protoimpl.UnsafeEnabled { + mi := &file_stillbox_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Notification) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Notification) ProtoMessage() {} + +func (x *Notification) ProtoReflect() protoreflect.Message { + mi := &file_stillbox_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Notification.ProtoReflect.Descriptor instead. +func (*Notification) Descriptor() ([]byte, []int) { + return file_stillbox_proto_rawDescGZIP(), []int{3} +} + +func (x *Notification) GetDateTime() *timestamppb.Timestamp { + if x != nil { + return x.DateTime + } + return nil +} + +func (x *Notification) GetMsg() string { + if x != nil { + return x.Msg + } + return "" +} + +func (x *Notification) GetActionUrl() string { + if x != nil { + return x.ActionUrl + } + return "" +} + +type Command struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Command: + // + // *Command_LiveCommand + // *Command_SearchCommand + Command isCommand_Command `protobuf_oneof:"command"` +} + +func (x *Command) Reset() { + *x = Command{} + if protoimpl.UnsafeEnabled { + mi := &file_stillbox_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Command) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Command) ProtoMessage() {} + +func (x *Command) ProtoReflect() protoreflect.Message { + mi := &file_stillbox_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Command.ProtoReflect.Descriptor instead. +func (*Command) Descriptor() ([]byte, []int) { + return file_stillbox_proto_rawDescGZIP(), []int{4} +} + +func (m *Command) GetCommand() isCommand_Command { + if m != nil { + return m.Command + } + return nil +} + +func (x *Command) GetLiveCommand() *Live { + if x, ok := x.GetCommand().(*Command_LiveCommand); ok { + return x.LiveCommand + } + return nil +} + +func (x *Command) GetSearchCommand() *Search { + if x, ok := x.GetCommand().(*Command_SearchCommand); ok { + return x.SearchCommand + } + return nil +} + +type isCommand_Command interface { + isCommand_Command() +} + +type Command_LiveCommand struct { + LiveCommand *Live `protobuf:"bytes,1,opt,name=liveCommand,proto3,oneof"` +} + +type Command_SearchCommand struct { + SearchCommand *Search `protobuf:"bytes,2,opt,name=searchCommand,proto3,oneof"` +} + +func (*Command_LiveCommand) isCommand_Command() {} + +func (*Command_SearchCommand) isCommand_Command() {} + +type Live struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + State LiveState `protobuf:"varint,1,opt,name=state,proto3,enum=stillbox.LiveState" json:"state,omitempty"` +} + +func (x *Live) Reset() { + *x = Live{} + if protoimpl.UnsafeEnabled { + mi := &file_stillbox_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Live) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Live) ProtoMessage() {} + +func (x *Live) ProtoReflect() protoreflect.Message { + mi := &file_stillbox_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Live.ProtoReflect.Descriptor instead. +func (*Live) Descriptor() ([]byte, []int) { + return file_stillbox_proto_rawDescGZIP(), []int{5} +} + +func (x *Live) GetState() LiveState { + if x != nil { + return x.State + } + return LiveState_LS_STOPPED +} + +type Search struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *Search) Reset() { + *x = Search{} + if protoimpl.UnsafeEnabled { + mi := &file_stillbox_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Search) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Search) ProtoMessage() {} + +func (x *Search) ProtoReflect() protoreflect.Message { + mi := &file_stillbox_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Search.ProtoReflect.Descriptor instead. +func (*Search) Descriptor() ([]byte, []int) { + return file_stillbox_proto_rawDescGZIP(), []int{6} +} + var File_stillbox_proto protoreflect.FileDescriptor var file_stillbox_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd5, 0x02, 0x0a, 0x04, - 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x5f, 0x6e, 0x61, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xae, 0x01, 0x0a, 0x07, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x04, 0x63, 0x61, 0x6c, 0x6c, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x78, + 0x2e, 0x43, 0x61, 0x6c, 0x6c, 0x48, 0x00, 0x52, 0x04, 0x63, 0x61, 0x6c, 0x6c, 0x12, 0x3c, 0x0a, + 0x0c, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, 0x6e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x0a, 0x05, 0x70, + 0x6f, 0x70, 0x75, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x74, 0x69, + 0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x6f, 0x70, 0x75, 0x70, 0x48, + 0x00, 0x52, 0x05, 0x70, 0x6f, 0x70, 0x75, 0x70, 0x42, 0x12, 0x0a, 0x10, 0x74, 0x6f, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xd2, 0x02, 0x0a, + 0x04, 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x4e, - 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x5f, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x37, 0x0a, 0x09, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x52, 0x08, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, - 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x79, 0x73, - 0x74, 0x65, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x66, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x66, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x66, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0b, 0x66, 0x72, - 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, - 0x63, 0x68, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x05, 0x52, 0x07, 0x70, 0x61, 0x74, 0x63, - 0x68, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x0a, - 0x20, 0x03, 0x28, 0x05, 0x52, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x14, 0x0a, - 0x05, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x61, 0x75, - 0x64, 0x69, 0x6f, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x54, 0x79, 0x70, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x36, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x08, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x79, 0x73, 0x74, 0x65, + 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x61, 0x6c, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x66, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x66, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x69, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0b, 0x66, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x63, 0x68, + 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x05, 0x52, 0x07, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x73, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, + 0x28, 0x05, 0x52, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x61, + 0x75, 0x64, 0x69, 0x6f, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x61, 0x75, 0x64, 0x69, + 0x6f, 0x22, 0x1d, 0x0a, 0x09, 0x55, 0x73, 0x65, 0x72, 0x50, 0x6f, 0x70, 0x75, 0x70, 0x12, 0x10, + 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, + 0x22, 0x76, 0x0a, 0x0c, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x36, 0x0a, 0x08, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, + 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x22, 0x82, 0x01, 0x0a, 0x07, 0x43, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x32, 0x0a, 0x0b, 0x6c, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x73, 0x74, 0x69, 0x6c, + 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x4c, 0x69, 0x76, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x6c, 0x69, 0x76, + 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x38, 0x0a, 0x0d, 0x73, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x10, 0x2e, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x48, 0x00, 0x52, 0x0d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x43, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x42, 0x09, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x22, 0x31, 0x0a, + 0x04, 0x4c, 0x69, 0x76, 0x65, 0x12, 0x29, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x62, 0x6f, 0x78, 0x2e, + 0x4c, 0x69, 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x22, 0x08, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2a, 0x37, 0x0a, 0x09, 0x4c, 0x69, + 0x76, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x0a, 0x4c, 0x53, 0x5f, 0x53, 0x54, + 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x4c, 0x53, 0x5f, 0x4c, 0x49, + 0x56, 0x45, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x4c, 0x53, 0x5f, 0x50, 0x41, 0x55, 0x53, 0x45, + 0x44, 0x10, 0x02, 0x42, 0x06, 0x5a, 0x04, 0x2e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } @@ -192,18 +648,33 @@ func file_stillbox_proto_rawDescGZIP() []byte { return file_stillbox_proto_rawDescData } -var file_stillbox_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_stillbox_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_stillbox_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_stillbox_proto_goTypes = []any{ - (*Call)(nil), // 0: stillbox.Call - (*timestamppb.Timestamp)(nil), // 1: google.protobuf.Timestamp + (LiveState)(0), // 0: stillbox.LiveState + (*Message)(nil), // 1: stillbox.Message + (*Call)(nil), // 2: stillbox.Call + (*UserPopup)(nil), // 3: stillbox.UserPopup + (*Notification)(nil), // 4: stillbox.Notification + (*Command)(nil), // 5: stillbox.Command + (*Live)(nil), // 6: stillbox.Live + (*Search)(nil), // 7: stillbox.Search + (*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp } var file_stillbox_proto_depIdxs = []int32{ - 1, // 0: stillbox.Call.date_time:type_name -> google.protobuf.Timestamp - 1, // [1:1] is the sub-list for method output_type - 1, // [1:1] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 2, // 0: stillbox.Message.call:type_name -> stillbox.Call + 4, // 1: stillbox.Message.notification:type_name -> stillbox.Notification + 3, // 2: stillbox.Message.popup:type_name -> stillbox.UserPopup + 8, // 3: stillbox.Call.dateTime:type_name -> google.protobuf.Timestamp + 8, // 4: stillbox.Notification.dateTime:type_name -> google.protobuf.Timestamp + 6, // 5: stillbox.Command.liveCommand:type_name -> stillbox.Live + 7, // 6: stillbox.Command.searchCommand:type_name -> stillbox.Search + 0, // 7: stillbox.Live.state:type_name -> stillbox.LiveState + 8, // [8:8] is the sub-list for method output_type + 8, // [8:8] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_stillbox_proto_init() } @@ -213,6 +684,18 @@ func file_stillbox_proto_init() { } if !protoimpl.UnsafeEnabled { file_stillbox_proto_msgTypes[0].Exporter = func(v any, i int) any { + switch v := v.(*Message); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_stillbox_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*Call); i { case 0: return &v.state @@ -224,19 +707,89 @@ func file_stillbox_proto_init() { return nil } } + file_stillbox_proto_msgTypes[2].Exporter = func(v any, i int) any { + switch v := v.(*UserPopup); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_stillbox_proto_msgTypes[3].Exporter = func(v any, i int) any { + switch v := v.(*Notification); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_stillbox_proto_msgTypes[4].Exporter = func(v any, i int) any { + switch v := v.(*Command); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_stillbox_proto_msgTypes[5].Exporter = func(v any, i int) any { + switch v := v.(*Live); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_stillbox_proto_msgTypes[6].Exporter = func(v any, i int) any { + switch v := v.(*Search); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_stillbox_proto_msgTypes[0].OneofWrappers = []any{ + (*Message_Call)(nil), + (*Message_Notification)(nil), + (*Message_Popup)(nil), + } + file_stillbox_proto_msgTypes[4].OneofWrappers = []any{ + (*Command_LiveCommand)(nil), + (*Command_SearchCommand)(nil), } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_stillbox_proto_rawDesc, - NumEnums: 0, - NumMessages: 1, + NumEnums: 1, + NumMessages: 7, NumExtensions: 0, NumServices: 0, }, GoTypes: file_stillbox_proto_goTypes, DependencyIndexes: file_stillbox_proto_depIdxs, + EnumInfos: file_stillbox_proto_enumTypes, MessageInfos: file_stillbox_proto_msgTypes, }.Build() File_stillbox_proto = out.File diff --git a/pkg/pb/stillbox.proto b/pkg/pb/stillbox.proto index efe6d78..dfb325e 100644 --- a/pkg/pb/stillbox.proto +++ b/pkg/pb/stillbox.proto @@ -4,10 +4,18 @@ option go_package = "./pb"; import "google/protobuf/timestamp.proto"; +message Message { + oneof toClient_message { + Call call = 1; + Notification notification = 2; + UserPopup popup = 3; + } +} + message Call { - string audio_name = 1; - string audio_type = 2; - google.protobuf.Timestamp date_time = 3; + string audioName = 1; + string audioType = 2; + google.protobuf.Timestamp dateTime = 3; int32 system = 4; int32 talkgroup = 5; int32 source = 6; @@ -17,3 +25,33 @@ message Call { repeated int32 sources = 10; bytes audio = 11; } + +message UserPopup { + string msg = 1; +} + +message Notification { + google.protobuf.Timestamp dateTime = 1; + string msg = 2; + string actionUrl = 3; +} + +message Command { + oneof command { + Live liveCommand = 1; + Search searchCommand = 2; + } +} + +enum LiveState { + LS_STOPPED = 0; + LS_LIVE = 1; + LS_PAUSED = 2; +} + +message Live { + LiveState state = 1; +} + +message Search { +}