Skip to content

Commit

Permalink
replace with optional function pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
koron committed Oct 21, 2023
1 parent 5f9e3fb commit 4a8d388
Show file tree
Hide file tree
Showing 13 changed files with 141 additions and 84 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
*.exe
*~
default.pgo
tags
tmp/
32 changes: 7 additions & 25 deletions advertise.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,16 @@ type Advertiser struct {

// Advertise starts advertisement of service.
// location should be a string or a ssdp.LocationProvider.
func Advertise(st, usn string, location interface{}, server string, maxAge int, opts ...AdvertiserOption) (*Advertiser, error) {
func Advertise(st, usn string, location interface{}, server string, maxAge int, opts ...Option) (*Advertiser, error) {
locProv, err := toLocationProvider(location)
if err != nil {
return nil, err
}
conn, err := multicast.Listen(multicast.RecvAddrResolver, defaultConnOpts()...)
cfg, err := opts2config(opts)
if err != nil {
return nil, err
}
conn, err := multicast.Listen(multicast.RecvAddrResolver, cfg.multicastConfig.options()...)
if err != nil {
return nil, err
}
Expand All @@ -57,9 +61,7 @@ func Advertise(st, usn string, location interface{}, server string, maxAge int,
maxAge: maxAge,
conn: conn,
ch: make(chan *message),
}
for _, o := range opts {
o.apply(a)
addHost: cfg.advertiseConfig.addHost,
}
a.wg.Add(2)
a.wgS.Add(1)
Expand Down Expand Up @@ -202,23 +204,3 @@ func (a *Advertiser) Bye() error {
ssdplog.Printf("sent bye")
return nil
}

// AdvertiserOption configures for specific behavior of Advertiser.
type AdvertiserOption interface {
apply(*Advertiser)
}

type advertiserOptionFunc func(*Advertiser)

func (af advertiserOptionFunc) apply(a *Advertiser) {
af(a)
}

// AdvertiserOptionAddHost returns as AdvertiserOption that add HOST header
// response for M-SEARCH request. This is added to support SmartThings.
// See https://github.com/koron/go-ssdp/issues/30 for details.
func AdvertiserOptionAddHost() AdvertiserOption {
return advertiserOptionFunc(func(a *Advertiser) {
a.addHost = true
})
}
16 changes: 12 additions & 4 deletions announce.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ import (

// AnnounceAlive sends ssdp:alive message.
// location should be a string or a ssdp.LocationProvider.
func AnnounceAlive(nt, usn string, location interface{}, server string, maxAge int, localAddr string) error {
func AnnounceAlive(nt, usn string, location interface{}, server string, maxAge int, localAddr string, opts ...Option) error {
locProv, err := toLocationProvider(location)
if err != nil {
return err
}
cfg, err := opts2config(opts)
if err != nil {
return err
}
// dial multicast UDP packet.
conn, err := multicast.Listen(&multicast.AddrResolver{Addr: localAddr}, defaultConnOpts()...)
conn, err := multicast.Listen(&multicast.AddrResolver{Addr: localAddr}, cfg.multicastConfig.options()...)
if err != nil {
return err
}
Expand Down Expand Up @@ -75,9 +79,13 @@ func buildAlive(raddr net.Addr, nt, usn, location, server string, maxAge int) []
}

// AnnounceBye sends ssdp:byebye message.
func AnnounceBye(nt, usn, localAddr string) error {
func AnnounceBye(nt, usn, localAddr string, opts...Option) error {
cfg, err := opts2config(opts)
if err != nil {
return err
}
// dial multicast UDP packet.
conn, err := multicast.Listen(&multicast.AddrResolver{Addr: localAddr}, defaultConnOpts()...)
conn, err := multicast.Listen(&multicast.AddrResolver{Addr: localAddr}, cfg.multicastConfig.options()...)
if err != nil {
return err
}
Expand Down
8 changes: 5 additions & 3 deletions examples/advertise/advertise.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@ func main() {
if *v {
ssdp.Logger = log.New(os.Stderr, "[SSDP] ", log.LstdFlags)
}

var opts []ssdp.Option
if *ttl > 0 {
ssdp.SetMulticastTTL(*ttl)
opts = append(opts, ssdp.TTL(*ttl))
}
if *sysIf {
ssdp.SetMulticastSystemAssignedInterface(true)
opts = append(opts, ssdp.OnlySystemInterface())
}

ad, err := ssdp.Advertise(*st, *usn, *loc, *srv, *maxAge)
ad, err := ssdp.Advertise(*st, *usn, *loc, *srv, *maxAge, opts...)
if err != nil {
log.Fatal(err)
}
Expand Down
8 changes: 5 additions & 3 deletions examples/alive/alive.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ func main() {
if *v {
ssdp.Logger = log.New(os.Stderr, "[SSDP] ", log.LstdFlags)
}

var opts []ssdp.Option
if *ttl > 0 {
ssdp.SetMulticastTTL(*ttl)
opts = append(opts, ssdp.TTL(*ttl))
}
if *sysIf {
ssdp.SetMulticastSystemAssignedInterface(true)
opts = append(opts, ssdp.OnlySystemInterface())
}

err := ssdp.AnnounceAlive(*nt, *usn, *loc, *srv, *maxAge, *laddr)
err := ssdp.AnnounceAlive(*nt, *usn, *loc, *srv, *maxAge, *laddr, opts...)
if err != nil {
log.Fatal(err)
}
Expand Down
8 changes: 5 additions & 3 deletions examples/bye/bye.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,16 @@ func main() {
if *v {
ssdp.Logger = log.New(os.Stderr, "[SSDP] ", log.LstdFlags)
}

var opts []ssdp.Option
if *ttl > 0 {
ssdp.SetMulticastTTL(*ttl)
opts = append(opts, ssdp.TTL(*ttl))
}
if *sysIf {
ssdp.SetMulticastSystemAssignedInterface(true)
opts = append(opts, ssdp.OnlySystemInterface())
}

err := ssdp.AnnounceBye(*nt, *usn, *laddr)
err := ssdp.AnnounceBye(*nt, *usn, *laddr, opts...)
if err != nil {
log.Fatal(err)
}
Expand Down
13 changes: 8 additions & 5 deletions examples/monitor/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,20 @@ func main() {
if *v {
ssdp.Logger = log.New(os.Stderr, "[SSDP] ", log.LstdFlags)
}

var opts []ssdp.Option
if *ttl > 0 {
ssdp.SetMulticastTTL(*ttl)
opts = append(opts, ssdp.TTL(*ttl))
}
if *sysIf {
ssdp.SetMulticastSystemAssignedInterface(true)
opts = append(opts, ssdp.OnlySystemInterface())
}

m := &ssdp.Monitor{
Alive: onAlive,
Bye: onBye,
Search: onSearch,
Alive: onAlive,
Bye: onBye,
Search: onSearch,
Options: opts,
}
if err := m.Start(); err != nil {
log.Fatal(err)
Expand Down
9 changes: 6 additions & 3 deletions examples/search/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,16 @@ func main() {
if *v {
ssdp.Logger = log.New(os.Stderr, "[SSDP] ", log.LstdFlags)
}

var opts []ssdp.Option
if *ttl > 0 {
ssdp.SetMulticastTTL(*ttl)
opts = append(opts, ssdp.TTL(*ttl))
}
if *sysIf {
ssdp.SetMulticastSystemAssignedInterface(true)
opts = append(opts, ssdp.OnlySystemInterface())
}
list, err := ssdp.Search(*t, *w, *l)

list, err := ssdp.Search(*t, *w, *l, opts...)
if err != nil {
log.Fatal(err)
}
Expand Down
8 changes: 7 additions & 1 deletion monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,19 @@ type Monitor struct {
Bye ByeHandler
Search SearchHandler

Options []Option

conn *multicast.Conn
wg sync.WaitGroup
}

// Start starts to monitor SSDP messages.
func (m *Monitor) Start() error {
conn, err := multicast.Listen(multicast.RecvAddrResolver, defaultConnOpts()...)
cfg, err := opts2config(m.Options)
if err != nil {
return err
}
conn, err := multicast.Listen(multicast.RecvAddrResolver, cfg.multicastConfig.options()...)
if err != nil {
return err
}
Expand Down
77 changes: 77 additions & 0 deletions option.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package ssdp

import "github.com/koron/go-ssdp/internal/multicast"

type config struct {
multicastConfig
advertiseConfig
}

func opts2config(opts []Option) (cfg config, err error) {
for _, o := range opts {
err := o.apply(&cfg)
if err != nil {
return config{}, err
}
}
return cfg, nil
}

type multicastConfig struct {
ttl int
sysIf bool
}

func (mc multicastConfig) options() (opts []multicast.ConnOption) {
if mc.ttl > 0 {
opts = append(opts, multicast.ConnTTL(mc.ttl))
}
if mc.sysIf {
opts = append(opts, multicast.ConnSystemAssginedInterface())
}
return opts
}

type advertiseConfig struct {
addHost bool
}

// Option is option set for SSDP API.
type Option interface {
apply(c *config) error
}

type optionFunc func(*config) error

func (of optionFunc) apply(c *config) error {
return of(c)
}

// TTL returns as Option that set TTL for multicast packets.
func TTL(ttl int) Option {
return optionFunc(func(c *config) error {
c.ttl = ttl
return nil
})
}

// OnlySystemInterface returns as Option that using only a system assigned
// multicast interface.
func OnlySystemInterface() Option {
return optionFunc(func(c *config) error {
c.sysIf = true
return nil
})
}

// AdvertiseHost returns as Option that add HOST header to response for
// M-SEARCH requests.
// This option works with Advertise() function only.
// This is added to support SmartThings.
// See https://github.com/koron/go-ssdp/issues/30 for details.
func AdvertiseHost() Option {
return optionFunc(func(c *config) error {
c.addHost = true
return nil
})
}
8 changes: 6 additions & 2 deletions search.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,13 @@ const (
)

// Search searches services by SSDP.
func Search(searchType string, waitSec int, localAddr string) ([]Service, error) {
func Search(searchType string, waitSec int, localAddr string, opts ...Option) ([]Service, error) {
cfg, err := opts2config(opts)
if err != nil {
return nil, err
}
// dial multicast UDP packet.
conn, err := multicast.Listen(&multicast.AddrResolver{Addr: localAddr}, defaultConnOpts()...)
conn, err := multicast.Listen(&multicast.AddrResolver{Addr: localAddr}, cfg.multicastConfig.options()...)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion search_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ func TestSearch_ServiceRawHeader(t *testing.T) {
}

func TestSearch_AdvetiserWithHost(t *testing.T) {
a, err := Advertise("test:search+advertiserwithhost", "usn:search+advertiserwithhost", "location:search+advertiserwithhost", "server:search+advertiserwithhost", 600, AdvertiserOptionAddHost())
a, err := Advertise("test:search+advertiserwithhost", "usn:search+advertiserwithhost", "location:search+advertiserwithhost", "server:search+advertiserwithhost", 600, AdvertiseHost())
if err != nil {
t.Fatalf("failed to Advertise: %s", err)
}
Expand Down
34 changes: 0 additions & 34 deletions ssdp.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,37 +35,3 @@ func SetMulticastRecvAddrIPv4(addr string) error {
func SetMulticastSendAddrIPv4(addr string) error {
return multicast.SetSendAddrIPv4(addr)
}

func defaultConnOpts() []multicast.ConnOption {
var opts []multicast.ConnOption
if multicastTTL > 0 {
opts = append(opts, multicast.ConnTTL(multicastTTL))
}
if multicastSystemAssignedInterface {
opts = append(opts, multicast.ConnSystemAssginedInterface())
}
return opts
}

var multicastTTL int

// SetMulticastTTL sets default TTL of SSDP's UDP packets.
// 0 default, 1 or greater set TTL.
func SetMulticastTTL(ttl int) {
multicastTTL = ttl
}

var multicastSystemAssignedInterface bool

// SetMulticastSystemAssignedInterface updates state whether using the system
// assigned multicast interface or provided interfaces.
// Default is "false", it uses provided interface (see Interfaces also).
func SetMulticastSystemAssignedInterface(enable bool) {
multicastSystemAssignedInterface = enable
}

// GetMulticastSystemAssignedInterface returns state using the system assigned
// multicast interface or provided interfaces.
func GetMulticastSystemAssignedInterface() bool {
return multicastSystemAssignedInterface
}

0 comments on commit 4a8d388

Please sign in to comment.