123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- package yp
- import (
- "bytes"
- "encoding/json"
- "io"
- "net/http"
- "net/url"
- "time"
- "github.com/owncast/owncast/config"
- "github.com/owncast/owncast/core/data"
- "github.com/owncast/owncast/models"
- log "github.com/sirupsen/logrus"
- )
- const pingInterval = 4 * time.Minute
- var (
- getStatus func() models.Status
- _inErrorState = false
- )
- // YP is a service for handling listing in the Owncast directory.
- type YP struct {
- timer *time.Ticker
- }
- type ypPingResponse struct {
- Key string `json:"key"`
- Error string `json:"error"`
- ErrorCode int `json:"errorCode"`
- Success bool `json:"success"`
- }
- type ypPingRequest struct {
- Key string `json:"key"`
- URL string `json:"url"`
- }
- // NewYP creates a new instance of the YP service handler.
- func NewYP(getStatusFunc func() models.Status) *YP {
- getStatus = getStatusFunc
- return &YP{}
- }
- // Start is run when a live stream begins to start pinging YP.
- func (yp *YP) Start() {
- yp.timer = time.NewTicker(pingInterval)
- for range yp.timer.C {
- yp.ping()
- }
- yp.ping()
- }
- // Stop stops the pinging of YP.
- func (yp *YP) Stop() {
- yp.timer.Stop()
- }
- func (yp *YP) ping() {
- if !data.GetDirectoryEnabled() {
- return
- }
- // 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
- }
- myInstanceURL := data.GetServerURL()
- if myInstanceURL == "" {
- log.Warnln("Server URL not set in the configuration. Directory access is disabled until this is set.")
- return
- }
- isValidInstanceURL := isURL(myInstanceURL)
- 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
- }
- key := data.GetDirectoryRegistrationKey()
- log.Traceln("Pinging YP as: ", data.GetServerName(), "with key", key)
- request := ypPingRequest{
- Key: key,
- URL: myInstanceURL,
- }
- req, err := json.Marshal(request)
- if err != nil {
- log.Errorln(err)
- return
- }
- pingURL := config.GetDefaults().YPServer + "/api/ping"
- resp, err := http.Post(pingURL, "application/json", bytes.NewBuffer(req)) //nolint
- if err != nil {
- log.Errorln(err)
- return
- }
- defer resp.Body.Close()
- body, err := io.ReadAll(resp.Body)
- if err != nil {
- log.Errorln(err)
- }
- pingResponse := ypPingResponse{}
- if err := json.Unmarshal(body, &pingResponse); err != nil {
- log.Errorln(err)
- }
- if !pingResponse.Success {
- if !_inErrorState {
- log.Warnln("YP Ping error returned from service:", pingResponse.Error)
- }
- _inErrorState = true
- return
- }
- _inErrorState = false
- if pingResponse.Key != key {
- if err := data.SetDirectoryRegistrationKey(key); err != nil {
- log.Errorln("unable to save directory key:", err)
- }
- }
- }
- func isURL(str string) bool {
- u, err := url.Parse(str)
- return err == nil && u.Scheme != "" && u.Host != ""
- }
|