From 4e5131149e9aadf5fd1d2110f88621118cd24eff Mon Sep 17 00:00:00 2001 From: Alex Ballas Date: Tue, 23 May 2023 19:44:51 +0300 Subject: [PATCH] Add context to the soapcalls API --- cmd/go2tv-lite/go2tv.go | 2 +- cmd/go2tv/go2tv.go | 2 +- devices/devices.go | 3 ++- internal/gui/main.go | 3 ++- soapcalls/friendlyname.go | 5 +++-- soapcalls/friendlyname_test.go | 3 ++- soapcalls/soapcallers.go | 30 ++++++++++++++++-------------- soapcalls/soapcalls.go | 10 ++++++++-- soapcalls/xmlparsers.go | 5 +++-- soapcalls/xmlparsers_test.go | 3 ++- 10 files changed, 40 insertions(+), 26 deletions(-) diff --git a/cmd/go2tv-lite/go2tv.go b/cmd/go2tv-lite/go2tv.go index 37a27b3..eb2ff4d 100644 --- a/cmd/go2tv-lite/go2tv.go +++ b/cmd/go2tv-lite/go2tv.go @@ -147,7 +147,7 @@ func run() error { scr := &dummyScreen{ctxCancel: cancel} - tvdata, err := soapcalls.NewTVPayload(soapcalls.Options{ + tvdata, err := soapcalls.NewTVPayload(&soapcalls.Options{ DMR: flagRes.dmrURL, Media: absMediaFile, Subs: absSubtitlesFile, diff --git a/cmd/go2tv/go2tv.go b/cmd/go2tv/go2tv.go index 5cee3a3..a79bca7 100644 --- a/cmd/go2tv/go2tv.go +++ b/cmd/go2tv/go2tv.go @@ -147,7 +147,7 @@ func run() error { return err } - tvdata, err := soapcalls.NewTVPayload(soapcalls.Options{ + tvdata, err := soapcalls.NewTVPayload(&soapcalls.Options{ DMR: flagRes.dmrURL, Media: absMediaFile, Subs: absSubtitlesFile, diff --git a/devices/devices.go b/devices/devices.go index b4d8bcf..10031a4 100644 --- a/devices/devices.go +++ b/devices/devices.go @@ -1,6 +1,7 @@ package devices import ( + "context" "fmt" "sort" @@ -30,7 +31,7 @@ func LoadSSDPservices(delay int) (map[string]string, error) { // (stop,play,pause). If we need support other functionalities // like volume control we need to use the RenderingControl service. if srv.Type == "urn:schemas-upnp-org:service:AVTransport:1" { - friendlyName, err := soapcalls.GetFriendlyName(srv.Location) + friendlyName, err := soapcalls.GetFriendlyName(context.Background(), srv.Location) if err != nil { continue } diff --git a/internal/gui/main.go b/internal/gui/main.go index a0e730b..8d3afec 100644 --- a/internal/gui/main.go +++ b/internal/gui/main.go @@ -4,6 +4,7 @@ package gui import ( + "context" "errors" "log" "math" @@ -382,7 +383,7 @@ func mainWindow(s *NewScreen) fyne.CanvasObject { // Widgets actions list.OnSelected = func(id widget.ListItemID) { playpause.Enable() - t, err := soapcalls.DMRextractor(data[id].addr) + t, err := soapcalls.DMRextractor(context.Background(), data[id].addr) check(s, err) if err == nil { s.selectedDevice = data[id] diff --git a/soapcalls/friendlyname.go b/soapcalls/friendlyname.go index 770d92f..173e801 100644 --- a/soapcalls/friendlyname.go +++ b/soapcalls/friendlyname.go @@ -1,15 +1,16 @@ package soapcalls import ( + "context" "encoding/xml" "fmt" "net/http" ) // GetFriendlyName returns the friendly name value for a the specific DMR url. -func GetFriendlyName(dmr string) (string, error) { +func GetFriendlyName(ctx context.Context, dmr string) (string, error) { client := &http.Client{} - req, err := http.NewRequest(http.MethodGet, dmr, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, dmr, nil) if err != nil { return "", fmt.Errorf("failed to create NewRequest for GetFriendlyName: %w", err) } diff --git a/soapcalls/friendlyname_test.go b/soapcalls/friendlyname_test.go index a8a8728..a2461ff 100644 --- a/soapcalls/friendlyname_test.go +++ b/soapcalls/friendlyname_test.go @@ -1,6 +1,7 @@ package soapcalls import ( + "context" "encoding/xml" "net/http" "net/http/httptest" @@ -31,7 +32,7 @@ func TestGetFriendlyName(t *testing.T) { defer testServer.Close() - friendly, err := GetFriendlyName(testServer.URL) + friendly, err := GetFriendlyName(context.Background(), testServer.URL) if err != nil { t.Fatalf("%s: Failed to call GetFriendlyName due to %s", testName, err.Error()) } diff --git a/soapcalls/soapcallers.go b/soapcalls/soapcallers.go index 1e095dc..8179e01 100644 --- a/soapcalls/soapcallers.go +++ b/soapcalls/soapcallers.go @@ -2,6 +2,7 @@ package soapcalls import ( "bytes" + "context" "encoding/json" "encoding/xml" "fmt" @@ -37,6 +38,7 @@ type TVPayload struct { initLogOnce sync.Once mu sync.RWMutex Logging io.Writer + ctx context.Context MediaRenderersStates map[string]*States CurrentTimers map[string]*time.Timer InitialMediaRenderersStates map[string]bool @@ -179,7 +181,7 @@ func (p *TVPayload) setAVTransportSoapCall() error { retryClient.Logger = nil client := retryClient.StandardClient() - req, err := http.NewRequest("POST", parsedURLtransport.String(), bytes.NewReader(xml)) + req, err := http.NewRequestWithContext(p.ctx, "POST", parsedURLtransport.String(), bytes.NewReader(xml)) if err != nil { p.Log().Error().Str("Method", "setAVTransportSoapCall").Str("Action", "Prepare POST").Err(err).Msg("") return fmt.Errorf("setAVTransportSoapCall POST error: %w", err) @@ -245,7 +247,7 @@ func (p *TVPayload) setNextAVTransportSoapCall(clear bool) error { client := &http.Client{} - req, err := http.NewRequest("POST", parsedURLtransport.String(), bytes.NewReader(xml)) + req, err := http.NewRequestWithContext(p.ctx, "POST", parsedURLtransport.String(), bytes.NewReader(xml)) if err != nil { p.Log().Error().Str("Method", "setNextAVTransportSoapCall").Str("Action", "Prepare POST").Err(err).Msg("") return fmt.Errorf("setNextAVTransportSoapCall POST error: %w", err) @@ -330,7 +332,7 @@ func (p *TVPayload) PlayPauseStopSoapCall(action string) error { client = retryClient.StandardClient() } - req, err := http.NewRequest("POST", parsedURLtransport.String(), bytes.NewReader(xml)) + req, err := http.NewRequestWithContext(p.ctx, "POST", parsedURLtransport.String(), bytes.NewReader(xml)) if err != nil { p.Log().Error().Str("Method", "AVTransportActionSoapCall").Str("Action", "Prepare POST").Err(err).Msg("") return fmt.Errorf("AVTransportActionSoapCall POST error: %w", err) @@ -407,7 +409,7 @@ func (p *TVPayload) SeekSoapCall(reltime string) error { client = retryClient.StandardClient() } - req, err := http.NewRequest("POST", parsedURLtransport.String(), bytes.NewReader(xml)) + req, err := http.NewRequestWithContext(p.ctx, "POST", parsedURLtransport.String(), bytes.NewReader(xml)) if err != nil { p.Log().Error().Str("Method", "SeekSoapCall").Str("Action", "Prepare POST").Err(err).Msg("") return fmt.Errorf("SeekSoapCall POST error: %w", err) @@ -481,7 +483,7 @@ func (p *TVPayload) SubscribeSoapCall(uuidInput string) error { client := retryClient.StandardClient() - req, err := http.NewRequest("SUBSCRIBE", parsedURLcontrol.String(), nil) + req, err := http.NewRequestWithContext(p.ctx, "SUBSCRIBE", parsedURLcontrol.String(), nil) if err != nil { p.Log().Error().Str("Method", "SubscribeSoapCall").Str("Action", "Prepare SUBSCRIBE").Err(err).Msg("") return fmt.Errorf("SubscribeSoapCall SUBSCRIBE error: %w", err) @@ -592,7 +594,7 @@ func (p *TVPayload) UnsubscribeSoapCall(uuid string) error { client := &http.Client{} - req, err := http.NewRequest("UNSUBSCRIBE", parsedURLcontrol.String(), nil) + req, err := http.NewRequestWithContext(p.ctx, "UNSUBSCRIBE", parsedURLcontrol.String(), nil) if err != nil { return fmt.Errorf("UnsubscribeSoapCall UNSUBSCRIBE error: %w", err) } @@ -654,7 +656,7 @@ func (p *TVPayload) GetMuteSoapCall() (string, error) { } client := &http.Client{} - req, err := http.NewRequest("POST", parsedRenderingControlURL.String(), bytes.NewReader(xmlbuilder)) + req, err := http.NewRequestWithContext(p.ctx, "POST", parsedRenderingControlURL.String(), bytes.NewReader(xmlbuilder)) if err != nil { p.Log().Error().Str("Method", "GetMuteSoapCall").Str("Action", "Prepare POST").Err(err).Msg("") return "", fmt.Errorf("GetMuteSoapCall POST error: %w", err) @@ -731,7 +733,7 @@ func (p *TVPayload) SetMuteSoapCall(number string) error { } client := &http.Client{} - req, err := http.NewRequest("POST", parsedRenderingControlURL.String(), bytes.NewReader(xmlbuilder)) + req, err := http.NewRequestWithContext(p.ctx, "POST", parsedRenderingControlURL.String(), bytes.NewReader(xmlbuilder)) if err != nil { p.Log().Error().Str("Method", "SetMuteSoapCall").Str("Action", "Prepare POST").Err(err).Msg("") return fmt.Errorf("SetMuteSoapCall POST error: %w", err) @@ -798,7 +800,7 @@ func (p *TVPayload) GetVolumeSoapCall() (int, error) { } client := &http.Client{} - req, err := http.NewRequest("POST", parsedRenderingControlURL.String(), bytes.NewReader(xmlbuilder)) + req, err := http.NewRequestWithContext(p.ctx, "POST", parsedRenderingControlURL.String(), bytes.NewReader(xmlbuilder)) if err != nil { p.Log().Error().Str("Method", "GetVolumeSoapCall").Str("Action", "Prepare POST").Err(err).Msg("") return 0, fmt.Errorf("GetVolumeSoapCall POST error: %w", err) @@ -886,7 +888,7 @@ func (p *TVPayload) SetVolumeSoapCall(v string) error { } client := &http.Client{} - req, err := http.NewRequest("POST", parsedRenderingControlURL.String(), bytes.NewReader(xmlbuilder)) + req, err := http.NewRequestWithContext(p.ctx, "POST", parsedRenderingControlURL.String(), bytes.NewReader(xmlbuilder)) if err != nil { p.Log().Error().Str("Method", "SetVolumeSoapCall").Str("Action", "Prepare POST").Err(err).Msg("") return fmt.Errorf("SetVolumeSoapCall POST error: %w", err) @@ -953,7 +955,7 @@ func (p *TVPayload) GetProtocolInfo() error { } client := &http.Client{} - req, err := http.NewRequest("POST", parsedConnectionManagerURL.String(), bytes.NewReader(xmlbuilder)) + req, err := http.NewRequestWithContext(p.ctx, "POST", parsedConnectionManagerURL.String(), bytes.NewReader(xmlbuilder)) if err != nil { p.Log().Error().Str("Method", "GetProtocolInfo").Str("Action", "Prepare POST").Err(err).Msg("") return fmt.Errorf("GetProtocolInfo POST error: %w", err) @@ -1027,7 +1029,7 @@ func (p *TVPayload) Gapless() (string, error) { } client := &http.Client{} - req, err := http.NewRequest("POST", parsedURLtransport.String(), bytes.NewReader(xmlbuilder)) + req, err := http.NewRequestWithContext(p.ctx, "POST", parsedURLtransport.String(), bytes.NewReader(xmlbuilder)) if err != nil { p.Log().Error().Str("Method", "Gapless").Str("Action", "Prepare POST").Err(err).Msg("") return "", fmt.Errorf("Gapless POST error: %w", err) @@ -1106,7 +1108,7 @@ func (p *TVPayload) GetTransportInfo() ([]string, error) { } client := &http.Client{} - req, err := http.NewRequest("POST", parsedURLtransport.String(), bytes.NewReader(xmlbuilder)) + req, err := http.NewRequestWithContext(p.ctx, "POST", parsedURLtransport.String(), bytes.NewReader(xmlbuilder)) if err != nil { p.Log().Error().Str("Method", "GetTransportInfo").Str("Action", "Prepare POST").Err(err).Msg("") return nil, fmt.Errorf("GetTransportInfo POST error: %w", err) @@ -1188,7 +1190,7 @@ func (p *TVPayload) GetPositionInfo() ([]string, error) { } client := &http.Client{} - req, err := http.NewRequest("POST", parsedURLtransport.String(), bytes.NewReader(xmlbuilder)) + req, err := http.NewRequestWithContext(p.ctx, "POST", parsedURLtransport.String(), bytes.NewReader(xmlbuilder)) if err != nil { p.Log().Error().Str("Method", "GetPositionInfo").Str("Action", "Prepare POST").Err(err).Msg("") return nil, fmt.Errorf("GetPositionInfo POST error: %w", err) diff --git a/soapcalls/soapcalls.go b/soapcalls/soapcalls.go index 4fc3311..12f76f4 100644 --- a/soapcalls/soapcalls.go +++ b/soapcalls/soapcalls.go @@ -1,6 +1,7 @@ package soapcalls import ( + "context" "io" "net/url" "time" @@ -10,6 +11,7 @@ import ( type Options struct { Logging io.Writer + ctx context.Context DMR string Media string Subs string @@ -19,8 +21,12 @@ type Options struct { Seek bool } -func NewTVPayload(o Options) (*TVPayload, error) { - upnpServicesURLs, err := DMRextractor(o.DMR) +func NewTVPayload(o *Options) (*TVPayload, error) { + if o.ctx == nil { + o.ctx = context.Background() + } + + upnpServicesURLs, err := DMRextractor(o.ctx, o.DMR) if err != nil { return nil, err } diff --git a/soapcalls/xmlparsers.go b/soapcalls/xmlparsers.go index 659687e..f3445f9 100644 --- a/soapcalls/xmlparsers.go +++ b/soapcalls/xmlparsers.go @@ -1,6 +1,7 @@ package soapcalls import ( + "context" "encoding/xml" "fmt" "io" @@ -55,7 +56,7 @@ type DMRextracted struct { } // DMRextractor extracts the services URLs from the main DMR xml. -func DMRextractor(dmrurl string) (*DMRextracted, error) { +func DMRextractor(ctx context.Context, dmrurl string) (*DMRextracted, error) { var root rootNode ex := &DMRextracted{} @@ -65,7 +66,7 @@ func DMRextractor(dmrurl string) (*DMRextracted, error) { } client := &http.Client{} - req, err := http.NewRequest("GET", dmrurl, nil) + req, err := http.NewRequestWithContext(ctx, "GET", dmrurl, nil) if err != nil { return nil, fmt.Errorf("DMRextractor GET error: %w", err) } diff --git a/soapcalls/xmlparsers_test.go b/soapcalls/xmlparsers_test.go index 93873e8..f9613f6 100644 --- a/soapcalls/xmlparsers_test.go +++ b/soapcalls/xmlparsers_test.go @@ -1,6 +1,7 @@ package soapcalls import ( + "context" "net/http" "net/http/httptest" "testing" @@ -42,7 +43,7 @@ func TestDMRextractor(t *testing.T) { defer testServer.Close() - _, err := DMRextractor(testServer.URL) + _, err := DMRextractor(context.Background(), testServer.URL) if err != nil { t.Fatalf("Failed to call DMRextractor due to %s", err.Error()) }