2022-10-12 10:00:14 +00:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"sync"
|
2022-10-19 10:01:04 +00:00
|
|
|
|
|
|
|
"go.uber.org/zap"
|
2022-10-12 10:00:14 +00:00
|
|
|
)
|
|
|
|
|
2022-10-12 14:41:19 +00:00
|
|
|
// portManager is responsible for maintaining segregated access to the port field
|
|
|
|
// via the use of rwLock sync.RWMutex and mustRead sync.Mutex
|
|
|
|
// rwLock establishes a standard read write mutex that allows consecutive reads and exclusive writes
|
|
|
|
// mustRead forces MustGetPort to wait until port has a none 0 value
|
2022-10-12 10:00:14 +00:00
|
|
|
type portManger struct {
|
2022-10-19 10:01:04 +00:00
|
|
|
logger *zap.Logger
|
2022-10-12 10:00:14 +00:00
|
|
|
port int
|
|
|
|
afterPortChanged func(port int)
|
2022-10-12 14:41:19 +00:00
|
|
|
rwLock *sync.RWMutex
|
|
|
|
mustRead *sync.Mutex
|
2022-10-12 10:00:14 +00:00
|
|
|
}
|
|
|
|
|
2022-10-12 14:41:19 +00:00
|
|
|
// newPortManager returns a newly initialised portManager with a pre-Locked portManger.mustRead sync.Mutex
|
2022-10-19 10:01:04 +00:00
|
|
|
func newPortManager(logger *zap.Logger, afterPortChanged func(int)) portManger {
|
2022-10-12 10:00:14 +00:00
|
|
|
pm := portManger{
|
2022-10-19 10:01:04 +00:00
|
|
|
logger: logger.Named("portManger"),
|
2022-10-12 10:00:14 +00:00
|
|
|
afterPortChanged: afterPortChanged,
|
2022-10-12 14:41:19 +00:00
|
|
|
rwLock: new(sync.RWMutex),
|
|
|
|
mustRead: new(sync.Mutex),
|
2022-10-12 10:00:14 +00:00
|
|
|
}
|
2022-10-12 14:41:19 +00:00
|
|
|
pm.mustRead.Lock()
|
2022-10-12 10:00:14 +00:00
|
|
|
return pm
|
|
|
|
}
|
|
|
|
|
2022-10-12 14:41:19 +00:00
|
|
|
// SetPort sets portManger.port field to the given port value
|
2022-10-12 14:09:28 +00:00
|
|
|
// next triggers any given portManger.afterPortChanged function
|
2022-10-12 14:41:19 +00:00
|
|
|
// additionally portManger.mustRead.Unlock() is called, releasing any calls to MustGetPort
|
2022-10-12 10:00:14 +00:00
|
|
|
func (p *portManger) SetPort(port int) error {
|
2022-10-19 10:01:04 +00:00
|
|
|
l := p.logger.Named("SetPort")
|
|
|
|
l.Debug("fired", zap.Int("port", port))
|
|
|
|
|
2022-10-12 14:41:19 +00:00
|
|
|
p.rwLock.Lock()
|
|
|
|
defer p.rwLock.Unlock()
|
2022-10-19 10:01:04 +00:00
|
|
|
l.Debug("acquired rwLock.Lock")
|
2022-10-12 14:09:28 +00:00
|
|
|
|
2022-10-12 10:00:14 +00:00
|
|
|
if port == 0 {
|
2022-10-19 10:01:04 +00:00
|
|
|
errMsg := "port can not be `0`, use ResetPort() instead"
|
|
|
|
l.Error(errMsg)
|
|
|
|
return fmt.Errorf(errMsg)
|
2022-10-12 10:00:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
p.port = port
|
2022-10-12 14:09:28 +00:00
|
|
|
if p.afterPortChanged != nil {
|
2022-10-19 10:01:04 +00:00
|
|
|
l.Debug("p.afterPortChanged != nil")
|
2022-10-12 14:09:28 +00:00
|
|
|
p.afterPortChanged(port)
|
|
|
|
}
|
2022-10-12 14:41:19 +00:00
|
|
|
p.mustRead.Unlock()
|
2022-10-19 10:01:04 +00:00
|
|
|
l.Debug("p.mustRead.Unlock()")
|
2022-10-12 10:00:14 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-10-12 14:09:28 +00:00
|
|
|
// ResetPort attempts to reset portManger.port to 0
|
2022-10-12 14:41:19 +00:00
|
|
|
// if portManger.mustRead is already locked the function returns after doing nothing
|
|
|
|
// portManger.mustRead.TryLock() is called because ResetPort may be called multiple times in a row
|
|
|
|
// and calling multiple times must not cause a deadlock or an infinite hang, but the lock needs to be
|
|
|
|
// reapplied if it is not present.
|
2022-10-12 10:00:14 +00:00
|
|
|
func (p *portManger) ResetPort() {
|
2022-10-19 10:01:04 +00:00
|
|
|
l := p.logger.Named("ResetPort")
|
|
|
|
l.Debug("fired")
|
|
|
|
|
2022-10-12 14:41:19 +00:00
|
|
|
p.rwLock.Lock()
|
|
|
|
defer p.rwLock.Unlock()
|
2022-10-19 10:01:04 +00:00
|
|
|
l.Debug("acquired rwLock.Lock")
|
2022-10-12 14:41:19 +00:00
|
|
|
|
|
|
|
if p.mustRead.TryLock() {
|
2022-10-19 10:01:04 +00:00
|
|
|
l.Debug("able to lock mustRead")
|
2022-10-12 10:00:14 +00:00
|
|
|
p.port = 0
|
2022-10-19 10:01:04 +00:00
|
|
|
return
|
2022-10-12 10:00:14 +00:00
|
|
|
}
|
2022-10-19 10:01:04 +00:00
|
|
|
l.Debug("unable to lock mustRead")
|
2022-10-12 10:00:14 +00:00
|
|
|
}
|
|
|
|
|
2022-10-12 14:09:28 +00:00
|
|
|
// GetPort gets the current value of portManager.port without any concern for the state of its value
|
2022-10-12 14:41:19 +00:00
|
|
|
// and therefore does not block until portManager.mustRead.Unlock() is called
|
2022-10-12 12:51:13 +00:00
|
|
|
func (p *portManger) GetPort() int {
|
2022-10-19 10:01:04 +00:00
|
|
|
l := p.logger.Named("GetPort")
|
|
|
|
l.Debug("fired")
|
|
|
|
|
2022-10-12 14:41:19 +00:00
|
|
|
p.rwLock.RLock()
|
|
|
|
defer p.rwLock.RUnlock()
|
2022-10-19 10:01:04 +00:00
|
|
|
l.Debug("acquired rwLock.RLock")
|
|
|
|
|
2022-10-12 12:51:13 +00:00
|
|
|
return p.port
|
|
|
|
}
|
|
|
|
|
2022-10-12 14:41:19 +00:00
|
|
|
// MustGetPort only returns portManager.port if portManager.mustRead is unlocked.
|
|
|
|
// This presupposes that portManger.mustRead has a default state of locked and SetPort unlock portManager.mustRead
|
2022-10-12 10:00:14 +00:00
|
|
|
func (p *portManger) MustGetPort() int {
|
2022-10-19 10:01:04 +00:00
|
|
|
l := p.logger.Named("MustGetPort")
|
|
|
|
l.Debug("fired")
|
|
|
|
|
2022-10-12 14:41:19 +00:00
|
|
|
p.mustRead.Lock()
|
|
|
|
defer p.mustRead.Unlock()
|
2022-10-19 10:01:04 +00:00
|
|
|
l.Debug("acquired mustRead.Lock")
|
2022-10-12 14:41:19 +00:00
|
|
|
|
|
|
|
p.rwLock.RLock()
|
|
|
|
defer p.rwLock.RUnlock()
|
2022-10-19 10:01:04 +00:00
|
|
|
l.Debug("acquired rwLock.RLock")
|
2022-10-12 10:00:14 +00:00
|
|
|
|
|
|
|
return p.port
|
|
|
|
}
|