diff --git a/service/client.go b/service/client.go index 316364a..6adbed0 100644 --- a/service/client.go +++ b/service/client.go @@ -484,3 +484,31 @@ func (c *Client) GetSession(callID, sessionID string) (rtc.SessionConfig, int, e return cfg, resp.StatusCode, nil } + +func (c *Client) GetSessions(callID string) ([]rtc.SessionConfig, int, error) { + reqURL := fmt.Sprintf("%s/calls/%s/sessions", c.cfg.httpURL, callID) + + req, err := http.NewRequest("GET", reqURL, nil) + if err != nil { + return nil, 0, fmt.Errorf("failed to build request: %w", err) + } + req.SetBasicAuth(c.cfg.ClientID, c.cfg.AuthKey) + + resp, err := c.httpClient.Do(req) + if err != nil { + return nil, 0, fmt.Errorf("http request failed: %w", err) + } + defer resp.Body.Close() + + var cfgs []rtc.SessionConfig + + if resp.StatusCode != http.StatusOK { + return nil, resp.StatusCode, fmt.Errorf("request failed with status %s", resp.Status) + } + + if err := json.NewDecoder(resp.Body).Decode(&cfgs); err != nil { + return nil, resp.StatusCode, fmt.Errorf("decoding http response failed: %w", err) + } + + return cfgs, resp.StatusCode, nil +} diff --git a/service/client_test.go b/service/client_test.go index 0d501ed..6609b40 100644 --- a/service/client_test.go +++ b/service/client_test.go @@ -880,3 +880,85 @@ func TestClientGetSession(t *testing.T) { require.Equal(t, http.StatusOK, code) }) } + +func TestClientGetSessions(t *testing.T) { + th := SetupTestHelper(t, nil) + defer th.Teardown() + + // register client + authKey := "Nl9OZthX5cMJz5a_HmU3kQJ4pHIIlohr" + err := th.srvc.auth.Register("clientA", authKey) + require.NoError(t, err) + + t.Run("unauthorized", func(t *testing.T) { + c, err := NewClient(ClientConfig{ + URL: th.apiURL, + }) + require.NoError(t, err) + require.NotNil(t, c) + defer c.Close() + + cfgs, code, err := c.GetSessions("callID") + require.EqualError(t, err, "request failed with status 401 Unauthorized") + require.Empty(t, cfgs) + require.Equal(t, http.StatusUnauthorized, code) + }) + + t.Run("no call ongoing", func(t *testing.T) { + c, err := NewClient(ClientConfig{ + URL: th.apiURL, + ClientID: "clientA", + AuthKey: authKey, + }) + require.NoError(t, err) + require.NotNil(t, c) + defer c.Close() + + cfgs, code, err := c.GetSessions("callID") + require.EqualError(t, err, "request failed with status 404 Not Found") + require.Empty(t, cfgs) + require.Equal(t, http.StatusNotFound, code) + }) + + t.Run("call ongoing", func(t *testing.T) { + c, err := NewClient(ClientConfig{ + URL: th.apiURL, + ClientID: "clientA", + AuthKey: authKey, + }) + require.NoError(t, err) + require.NotNil(t, c) + defer c.Close() + + cfgA := rtc.SessionConfig{ + GroupID: "clientA", + CallID: "callIDA", + UserID: "userA", + SessionID: "sessionA", + } + err = th.srvc.rtcServer.InitSession(cfgA, nil) + require.NoError(t, err) + defer func() { + err := th.srvc.rtcServer.CloseSession("sessionA") + require.NoError(t, err) + }() + + cfgB := rtc.SessionConfig{ + GroupID: "clientA", + CallID: "callIDA", + UserID: "userB", + SessionID: "sessionB", + } + err = th.srvc.rtcServer.InitSession(cfgB, nil) + require.NoError(t, err) + defer func() { + err := th.srvc.rtcServer.CloseSession("sessionB") + require.NoError(t, err) + }() + + sessionCfgs, code, err := c.GetSessions("callIDA") + require.NoError(t, err) + require.ElementsMatch(t, []rtc.SessionConfig{cfgA, cfgB}, sessionCfgs) + require.Equal(t, http.StatusOK, code) + }) +} diff --git a/service/rtc/server.go b/service/rtc/server.go index ab98bd5..3aea64a 100644 --- a/service/rtc/server.go +++ b/service/rtc/server.go @@ -432,3 +432,28 @@ func (s *Server) GetSessionConfig(groupID, callID, sessionID string) (SessionCon return session.cfg, nil } + +func (s *Server) GetSessionConfigs(groupID, callID string) ([]SessionConfig, error) { + group := s.getGroup(groupID) + if group == nil { + return nil, fmt.Errorf("group not found") + } + + call := group.getCall(callID) + if call == nil { + return nil, fmt.Errorf("call not found") + } + + call.mut.RLock() + defer call.mut.RUnlock() + if len(call.sessions) == 0 { + return nil, fmt.Errorf("no sessions found") + } + + cfgs := make([]SessionConfig, 0, len(call.sessions)) + for _, session := range call.sessions { + cfgs = append(cfgs, session.cfg) + } + + return cfgs, nil +} diff --git a/service/service.go b/service/service.go index 4eb399d..232cf6d 100644 --- a/service/service.go +++ b/service/service.go @@ -118,6 +118,7 @@ func New(cfg Config) (*Service, error) { s.apiServer.RegisterHandleFunc("/login", s.loginClient) s.apiServer.RegisterHandleFunc("/register", s.registerClient) s.apiServer.RegisterHandleFunc("/unregister", s.unregisterClient) + s.apiServer.RegisterHandleFunc("/calls/{callID}/sessions", s.handleGetSessions) s.apiServer.RegisterHandleFunc("/calls/{callID}/sessions/{sessionID}", s.handleGetSession) s.apiServer.RegisterHandler("/ws", s.wsServer) diff --git a/service/session.go b/service/session.go index 99471f8..2f695dd 100644 --- a/service/session.go +++ b/service/session.go @@ -50,3 +50,37 @@ func (s *Service) handleGetSession(w http.ResponseWriter, req *http.Request) { s.log.Error("failed to encode data", mlog.Err(err)) } } + +func (s *Service) handleGetSessions(w http.ResponseWriter, req *http.Request) { + if req.Method != http.MethodGet { + http.NotFound(w, req) + return + } + + clientID, code, err := s.authHandler(w, req) + if err != nil { + s.log.Error("failed to authenticate", mlog.Err(err), mlog.Int("code", code)) + } + + if clientID == "" { + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + + callID := req.PathValue("callID") + if callID == "" { + http.Error(w, "callID is required", http.StatusBadRequest) + return + } + + cfgs, err := s.rtcServer.GetSessionConfigs(clientID, callID) + if err != nil { + http.Error(w, fmt.Sprintf("failed to get session configs: %s", err.Error()), http.StatusNotFound) + return + } + + w.Header().Add("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(cfgs); err != nil { + s.log.Error("failed to encode data", mlog.Err(err)) + } +}