2b7682cdb3
- replace traditional for loop with range-based for loop for clarity
refactor(ffmpeg): simplify cut function loop
- utilize range-based for loop instead of traditional for loop
refactor(ring): update API response mapping type
- change map type from `interface{}` to `any` for better type safety
refactor(stream): handle nil source in NewStream
- add nil check for source elements before processing
refactor(webrtc): unify payload handling in GetToken
- change map type from `interface{}` to `any` for consistency
refactor(ascii): optimize nested loops in Write function
- replace traditional for loops with range-based for loops for readability
refactor(bits): enhance readability in Reader methods
- replace traditional for loops with range-based for loops in Read functions
refactor(h264): modernize loop structures in DecodeConfig
- switch to range-based for loops for cleaner code
refactor(h265): streamline profile_tier_level loops
- utilize range-based for loops instead of traditional for loops
chore(core): remove commented-out test function for clarity
refactor(core): simplify RandString function loop
- change traditional for loop to range-based for loop
refactor(flvt): optimize timestamp handling in TestTimeToRTP
- switch to range-based for loop for iterating frames
refactor(nest): improve error handling in ExchangeSDP
- format error message with printf-style formatting for clarity
refactor(tapo): enhance securityEncode function
- change traditional for loop to range-based for loop for readability
fix(tcp): correct masking in websocket Write method
- replace traditional for loop with range-based for loop
refactor(tutk): modernize encoding loops in crypto functions
- utilize range-based for loops for better readability
refactor(tuya): unify data types in MQTT message struct
- change map type from `interface{}` to `any` for consistency
refactor(webrtc): standardize codec registration
- change map type from `interface{}` to `any` for type safety
refactor(yaml): simplify Unmarshal function signature
- update parameter type from `interface{}` to `any` for better clarity
107 lines
2.4 KiB
Go
107 lines
2.4 KiB
Go
package ring
|
|
|
|
import (
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"fmt"
|
|
|
|
"github.com/AlexxIT/go2rtc/internal/api"
|
|
"github.com/AlexxIT/go2rtc/internal/streams"
|
|
"github.com/AlexxIT/go2rtc/pkg/core"
|
|
"github.com/AlexxIT/go2rtc/pkg/ring"
|
|
)
|
|
|
|
func Init() {
|
|
streams.HandleFunc("ring", func(source string) (core.Producer, error) {
|
|
return ring.Dial(source)
|
|
})
|
|
|
|
api.HandleFunc("api/ring", apiRing)
|
|
}
|
|
|
|
func apiRing(w http.ResponseWriter, r *http.Request) {
|
|
query := r.URL.Query()
|
|
var ringAPI *ring.RingApi
|
|
|
|
// Check auth method
|
|
if email := query.Get("email"); email != "" {
|
|
// Email/Password Flow
|
|
password := query.Get("password")
|
|
code := query.Get("code")
|
|
|
|
var err error
|
|
ringAPI, err = ring.NewRestClient(ring.EmailAuth{
|
|
Email: email,
|
|
Password: password,
|
|
}, nil)
|
|
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Try authentication (this will trigger 2FA if needed)
|
|
if _, err = ringAPI.GetAuth(code); err != nil {
|
|
if ringAPI.Using2FA {
|
|
// Return 2FA prompt
|
|
api.ResponseJSON(w, map[string]any{
|
|
"needs_2fa": true,
|
|
"prompt": ringAPI.PromptFor2FA,
|
|
})
|
|
return
|
|
}
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
} else if refreshToken := query.Get("refresh_token"); refreshToken != "" {
|
|
// Refresh Token Flow
|
|
if refreshToken == "" {
|
|
http.Error(w, "either email/password or refresh_token is required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var err error
|
|
ringAPI, err = ring.NewRestClient(ring.RefreshTokenAuth{
|
|
RefreshToken: refreshToken,
|
|
}, nil)
|
|
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
} else {
|
|
http.Error(w, "either email/password or refresh token is required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
devices, err := ringAPI.FetchRingDevices()
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
cleanQuery := url.Values{}
|
|
cleanQuery.Set("refresh_token", ringAPI.RefreshToken)
|
|
|
|
var items []*api.Source
|
|
for _, camera := range devices.AllCameras {
|
|
cleanQuery.Set("camera_id", fmt.Sprint(camera.ID))
|
|
cleanQuery.Set("device_id", camera.DeviceID)
|
|
|
|
// Stream source
|
|
items = append(items, &api.Source{
|
|
Name: camera.Description,
|
|
URL: "ring:?" + cleanQuery.Encode(),
|
|
})
|
|
|
|
// Snapshot source
|
|
items = append(items, &api.Source{
|
|
Name: camera.Description + " Snapshot",
|
|
URL: "ring:?" + cleanQuery.Encode() + "&snapshot",
|
|
})
|
|
}
|
|
|
|
api.ResponseSources(w, items)
|
|
}
|