2020-10-02 09:55:38 +03:00
|
|
|
package yp
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2021-11-20 09:42:50 +03:00
|
|
|
"encoding/json"
|
|
|
|
"io"
|
2020-10-02 09:55:38 +03:00
|
|
|
"net/http"
|
2020-11-05 20:20:33 +03:00
|
|
|
"net/url"
|
2020-10-02 09:55:38 +03:00
|
|
|
"time"
|
|
|
|
|
2020-10-05 20:07:09 +03:00
|
|
|
"github.com/owncast/owncast/config"
|
2021-02-19 10:05:52 +03:00
|
|
|
"github.com/owncast/owncast/core/data"
|
2020-10-05 20:07:09 +03:00
|
|
|
"github.com/owncast/owncast/models"
|
2020-10-02 09:55:38 +03:00
|
|
|
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
)
|
|
|
|
|
|
|
|
const pingInterval = 4 * time.Minute
|
|
|
|
|
2023-10-09 00:22:28 +03:00
|
|
|
var (
|
|
|
|
getStatus func() models.Status
|
|
|
|
_inErrorState = false
|
|
|
|
)
|
2020-10-02 09:55:38 +03:00
|
|
|
|
2021-10-25 10:31:45 +03:00
|
|
|
// YP is a service for handling listing in the Owncast directory.
|
2020-10-02 09:55:38 +03:00
|
|
|
type YP struct {
|
|
|
|
timer *time.Ticker
|
|
|
|
}
|
|
|
|
|
|
|
|
type ypPingResponse struct {
|
|
|
|
Key string `json:"key"`
|
|
|
|
Error string `json:"error"`
|
|
|
|
ErrorCode int `json:"errorCode"`
|
2023-05-30 20:31:43 +03:00
|
|
|
Success bool `json:"success"`
|
2020-10-02 09:55:38 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type ypPingRequest struct {
|
|
|
|
Key string `json:"key"`
|
|
|
|
URL string `json:"url"`
|
|
|
|
}
|
|
|
|
|
2020-11-13 02:14:59 +03:00
|
|
|
// NewYP creates a new instance of the YP service handler.
|
2020-10-02 09:55:38 +03:00
|
|
|
func NewYP(getStatusFunc func() models.Status) *YP {
|
|
|
|
getStatus = getStatusFunc
|
|
|
|
return &YP{}
|
|
|
|
}
|
|
|
|
|
2020-11-13 02:14:59 +03:00
|
|
|
// Start is run when a live stream begins to start pinging YP.
|
2020-10-02 09:55:38 +03:00
|
|
|
func (yp *YP) Start() {
|
|
|
|
yp.timer = time.NewTicker(pingInterval)
|
2020-11-15 05:39:53 +03:00
|
|
|
for range yp.timer.C {
|
|
|
|
yp.ping()
|
|
|
|
}
|
2020-10-02 09:55:38 +03:00
|
|
|
|
|
|
|
yp.ping()
|
|
|
|
}
|
|
|
|
|
2020-11-13 02:14:59 +03:00
|
|
|
// Stop stops the pinging of YP.
|
2020-10-02 09:55:38 +03:00
|
|
|
func (yp *YP) Stop() {
|
|
|
|
yp.timer.Stop()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (yp *YP) ping() {
|
2021-03-04 12:48:10 +03:00
|
|
|
if !data.GetDirectoryEnabled() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-03-23 06:31:25 +03:00
|
|
|
// Hack: Don't allow ping'ing when offline.
|
|
|
|
// It shouldn't even be trying to, but on some instances the ping timer isn't stopping.
|
|
|
|
if !getStatus().Online {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-02-19 10:05:52 +03:00
|
|
|
myInstanceURL := data.GetServerURL()
|
|
|
|
if myInstanceURL == "" {
|
|
|
|
log.Warnln("Server URL not set in the configuration. Directory access is disabled until this is set.")
|
|
|
|
return
|
|
|
|
}
|
2021-09-12 10:18:15 +03:00
|
|
|
isValidInstanceURL := isURL(myInstanceURL)
|
2020-11-05 20:20:33 +03:00
|
|
|
if myInstanceURL == "" || !isValidInstanceURL {
|
|
|
|
if !_inErrorState {
|
|
|
|
log.Warnln("YP Error: unable to use", myInstanceURL, "as a public instance URL. Fix this value in your configuration.")
|
|
|
|
}
|
|
|
|
_inErrorState = true
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-02-19 10:05:52 +03:00
|
|
|
key := data.GetDirectoryRegistrationKey()
|
2020-10-02 09:55:38 +03:00
|
|
|
|
2021-02-19 10:05:52 +03:00
|
|
|
log.Traceln("Pinging YP as: ", data.GetServerName(), "with key", key)
|
2020-10-02 09:55:38 +03:00
|
|
|
|
|
|
|
request := ypPingRequest{
|
|
|
|
Key: key,
|
|
|
|
URL: myInstanceURL,
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := json.Marshal(request)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorln(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-03-16 23:57:28 +03:00
|
|
|
pingURL := config.GetDefaults().YPServer + "/api/ping"
|
2020-11-15 05:39:53 +03:00
|
|
|
resp, err := http.Post(pingURL, "application/json", bytes.NewBuffer(req)) //nolint
|
2020-10-02 09:55:38 +03:00
|
|
|
if err != nil {
|
|
|
|
log.Errorln(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer resp.Body.Close()
|
2021-11-20 09:42:50 +03:00
|
|
|
body, err := io.ReadAll(resp.Body)
|
2020-10-02 09:55:38 +03:00
|
|
|
if err != nil {
|
|
|
|
log.Errorln(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
pingResponse := ypPingResponse{}
|
2021-07-09 21:16:44 +03:00
|
|
|
if err := json.Unmarshal(body, &pingResponse); err != nil {
|
2020-11-15 05:39:53 +03:00
|
|
|
log.Errorln(err)
|
|
|
|
}
|
2020-10-02 09:55:38 +03:00
|
|
|
|
|
|
|
if !pingResponse.Success {
|
2020-11-05 20:14:47 +03:00
|
|
|
if !_inErrorState {
|
|
|
|
log.Warnln("YP Ping error returned from service:", pingResponse.Error)
|
|
|
|
}
|
|
|
|
_inErrorState = true
|
2020-10-02 09:55:38 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-11-05 20:14:47 +03:00
|
|
|
_inErrorState = false
|
|
|
|
|
2020-10-02 09:55:38 +03:00
|
|
|
if pingResponse.Key != key {
|
2021-07-20 09:37:06 +03:00
|
|
|
if err := data.SetDirectoryRegistrationKey(key); err != nil {
|
|
|
|
log.Errorln("unable to save directory key:", err)
|
|
|
|
}
|
2020-10-02 09:55:38 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-12 10:18:15 +03:00
|
|
|
func isURL(str string) bool {
|
2020-11-05 20:20:33 +03:00
|
|
|
u, err := url.Parse(str)
|
|
|
|
return err == nil && u.Scheme != "" && u.Host != ""
|
|
|
|
}
|