mirror of
https://github.com/openlibrecommunity/olcrtc.git
synced 2026-05-26 07:08:11 +00:00
- Switched getToken endpoint to /api-room-manager/v2/room/%s/connection-details - Updated WebSocket URL to wss://rtc-el-01.wb.ru - Updated Python PoC scripts to match new endpoints
200 lines
5.6 KiB
Go
200 lines
5.6 KiB
Go
package wbstream
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
|
|
"github.com/openlibrecommunity/olcrtc/internal/protect"
|
|
)
|
|
|
|
var apiBase = "https://stream.wb.ru" //nolint:gochecknoglobals // package-level state intentional
|
|
|
|
var (
|
|
errGuestRegister = errors.New("guest register failed")
|
|
errCreateRoom = errors.New("create room failed")
|
|
errJoinRoom = errors.New("join room failed")
|
|
errGetToken = errors.New("get token failed")
|
|
)
|
|
|
|
type guestRegisterRequest struct {
|
|
DisplayName string `json:"displayName"`
|
|
Device device `json:"device"`
|
|
}
|
|
|
|
type device struct {
|
|
DeviceName string `json:"deviceName"`
|
|
DeviceType string `json:"deviceType"`
|
|
}
|
|
|
|
type guestRegisterResponse struct {
|
|
AccessToken string `json:"accessToken"`
|
|
}
|
|
|
|
type createRoomRequest struct {
|
|
RoomType string `json:"roomType"`
|
|
RoomPrivacy string `json:"roomPrivacy"`
|
|
}
|
|
|
|
type createRoomResponse struct {
|
|
RoomID string `json:"roomId"`
|
|
}
|
|
|
|
type tokenResponse struct {
|
|
RoomToken string `json:"roomToken"`
|
|
ServerURL string `json:"serverUrl"`
|
|
}
|
|
|
|
func registerGuest(ctx context.Context, displayName string) (string, error) {
|
|
u := apiBase + "/auth/api/v1/auth/user/guest-register"
|
|
reqBody := guestRegisterRequest{
|
|
DisplayName: displayName,
|
|
Device: device{
|
|
DeviceName: "Linux",
|
|
DeviceType: "PARTICIPANT_DEVICE_TYPE_WEB_DESKTOP",
|
|
},
|
|
}
|
|
|
|
body, err := json.Marshal(reqBody)
|
|
if err != nil {
|
|
return "", fmt.Errorf("marshal request body: %w", err)
|
|
}
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, u, bytes.NewBuffer(body))
|
|
if err != nil {
|
|
return "", fmt.Errorf("create request: %w", err)
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("User-Agent", "Mozilla/5.0 (Linux x86_64)")
|
|
|
|
client := protect.NewHTTPClient()
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return "", fmt.Errorf("do request: %w", err)
|
|
}
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
b, _ := io.ReadAll(resp.Body)
|
|
return "", fmt.Errorf("%w: %d %s", errGuestRegister, resp.StatusCode, b)
|
|
}
|
|
|
|
var res guestRegisterResponse
|
|
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
|
|
return "", fmt.Errorf("decode response: %w", err)
|
|
}
|
|
return res.AccessToken, nil
|
|
}
|
|
|
|
func createRoom(ctx context.Context, accessToken string) (string, error) {
|
|
u := apiBase + "/api-room/api/v2/room"
|
|
reqBody := createRoomRequest{
|
|
RoomType: "ROOM_TYPE_ALL_ON_SCREEN",
|
|
RoomPrivacy: "ROOM_PRIVACY_FREE",
|
|
}
|
|
|
|
body, err := json.Marshal(reqBody)
|
|
if err != nil {
|
|
return "", fmt.Errorf("marshal request body: %w", err)
|
|
}
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, u, bytes.NewBuffer(body))
|
|
if err != nil {
|
|
return "", fmt.Errorf("create request: %w", err)
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
|
req.Header.Set("User-Agent", "Mozilla/5.0 (Linux x86_64)")
|
|
|
|
client := protect.NewHTTPClient()
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return "", fmt.Errorf("do request: %w", err)
|
|
}
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated {
|
|
b, _ := io.ReadAll(resp.Body)
|
|
return "", fmt.Errorf("%w: %d %s", errCreateRoom, resp.StatusCode, b)
|
|
}
|
|
|
|
var res createRoomResponse
|
|
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
|
|
return "", fmt.Errorf("decode response: %w", err)
|
|
}
|
|
return res.RoomID, nil
|
|
}
|
|
|
|
// CreateRoom registers a temporary guest, creates a WB Stream room, and returns its id.
|
|
func CreateRoom(ctx context.Context, displayName string) (string, error) {
|
|
accessToken, err := registerGuest(ctx, displayName)
|
|
if err != nil {
|
|
return "", fmt.Errorf("register guest: %w", err)
|
|
}
|
|
roomID, err := createRoom(ctx, accessToken)
|
|
if err != nil {
|
|
return "", fmt.Errorf("create room: %w", err)
|
|
}
|
|
return roomID, nil
|
|
}
|
|
|
|
func joinRoom(ctx context.Context, accessToken, roomID string) error {
|
|
u := fmt.Sprintf("%s/api-room/api/v1/room/%s/join", apiBase, roomID)
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, u, bytes.NewReader([]byte("{}")))
|
|
if err != nil {
|
|
return fmt.Errorf("create request: %w", err)
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
|
req.Header.Set("User-Agent", "Mozilla/5.0 (Linux x86_64)")
|
|
|
|
client := protect.NewHTTPClient()
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return fmt.Errorf("do request: %w", err)
|
|
}
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
b, _ := io.ReadAll(resp.Body)
|
|
return fmt.Errorf("%w: %d %s", errJoinRoom, resp.StatusCode, b)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func getToken(ctx context.Context, accessToken, roomID, displayName string) (string, error) {
|
|
u := fmt.Sprintf("%s/api-room-manager/v2/room/%s/connection-details", apiBase, roomID)
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
|
|
if err != nil {
|
|
return "", fmt.Errorf("create request: %w", err)
|
|
}
|
|
|
|
q := req.URL.Query()
|
|
q.Add("deviceType", "PARTICIPANT_DEVICE_TYPE_WEB_DESKTOP")
|
|
q.Add("displayName", displayName)
|
|
req.URL.RawQuery = q.Encode()
|
|
|
|
req.Header.Set("Authorization", "Bearer "+accessToken)
|
|
req.Header.Set("User-Agent", "Mozilla/5.0 (Linux x86_64)")
|
|
|
|
client := protect.NewHTTPClient()
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return "", fmt.Errorf("do request: %w", err)
|
|
}
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
b, _ := io.ReadAll(resp.Body)
|
|
return "", fmt.Errorf("%w: %d %s", errGetToken, resp.StatusCode, b)
|
|
}
|
|
|
|
var res tokenResponse
|
|
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
|
|
return "", fmt.Errorf("decode response: %w", err)
|
|
}
|
|
return res.RoomToken, nil
|
|
}
|