diff --git a/acn.go b/acn.go index 3da4f52..af5f497 100644 --- a/acn.go +++ b/acn.go @@ -58,5 +58,7 @@ type ACN interface { // GetVersion returns a string of what the ACN returns when asked for a version GetVersion() string + Callback() func(int, string) + Close() } diff --git a/error_acn.go b/error_acn.go new file mode 100644 index 0000000..425356c --- /dev/null +++ b/error_acn.go @@ -0,0 +1,49 @@ +package connectivity + +import ( + "fmt" + "net" +) + +// ErrorACN - a status-callback safe errored ACN. Use this when ACN construction goes wrong +// and you need a safe substitute that can later be replaced with a working ACN without impacting calling clients. +type ErrorACN struct { + statusCallbackCache func(int, string) +} + +func (e ErrorACN) Callback() func(int, string) { + return e.statusCallbackCache +} + +func (e ErrorACN) GetBootstrapStatus() (int, string) { + return -1, "error initializing tor" +} + +func (e ErrorACN) WaitTillBootstrapped() { +} + +func (e *ErrorACN) SetStatusCallback(callback func(int, string)) { + e.statusCallbackCache = callback +} + +func (e ErrorACN) Restart() { +} + +func (e ErrorACN) Open(hostname string) (net.Conn, string, error) { + return nil, "", fmt.Errorf("error initializing tor") +} + +func (e ErrorACN) Listen(identity PrivateKey, port int) (ListenService, error) { + return nil, fmt.Errorf("error initializing tor") +} + +func (e ErrorACN) GetPID() (int, error) { + return -1, fmt.Errorf("error initializing tor") +} + +func (e ErrorACN) GetVersion() string { + return "Error Initializing Tor" +} + +func (e ErrorACN) Close() { +} diff --git a/localProvider.go b/localProvider.go index 5a08baa..6c66499 100644 --- a/localProvider.go +++ b/localProvider.go @@ -18,6 +18,10 @@ func NewLocalACN() ACN { return &localProvider{} } +func (lp *localProvider) Callback() func(int, string) { + return func(int, string) {} +} + func (ls *localListenService) AddressFull() string { return ls.l.Addr().String() } diff --git a/proxy_acn.go b/proxy_acn.go new file mode 100644 index 0000000..0a3958a --- /dev/null +++ b/proxy_acn.go @@ -0,0 +1,67 @@ +package connectivity + +import ( + "net" +) + +// ProxyACN because there is rarely a problem that can't be solved by another layer of indirection. +// ACN is a core resource that many parts of a system may need access too e.g. all clients and servers need an instance +// and a UI may also need status information and a configuration interface. +// We want to allow configuration and replacement of an ACN without impacting the API of all downstream systems - introducing +// ProxyACN - a wrapper around an ACN that allows safe replacement of a running ACN that is transparent to callers. +type ProxyACN struct { + acn ACN +} + +func NewProxyACN(acn ACN) ProxyACN { + return ProxyACN{ + acn: acn, + } +} + +// ReplaceACN closes down the current ACN and replaces it with a new ACN. +func (p *ProxyACN) ReplaceACN(acn ACN) { + p.acn.Close() + acn.SetStatusCallback(p.acn.Callback()) + p.acn = acn +} + +func (p *ProxyACN) GetBootstrapStatus() (int, string) { + return p.acn.GetBootstrapStatus() +} + +func (p *ProxyACN) WaitTillBootstrapped() { + p.acn.WaitTillBootstrapped() +} + +func (p *ProxyACN) SetStatusCallback(callback func(int, string)) { + p.acn.SetStatusCallback(callback) +} + +func (p *ProxyACN) Restart() { + p.acn.Restart() +} + +func (p *ProxyACN) Open(hostname string) (net.Conn, string, error) { + return p.acn.Open(hostname) +} + +func (p *ProxyACN) Listen(identity PrivateKey, port int) (ListenService, error) { + return p.acn.Listen(identity, port) +} + +func (p *ProxyACN) GetPID() (int, error) { + return p.acn.GetPID() +} + +func (p *ProxyACN) GetVersion() string { + return p.acn.GetVersion() +} + +func (p *ProxyACN) Close() { + p.acn.Close() +} + +func (p *ProxyACN) Callback() func(int, string) { + return p.acn.Callback() +} diff --git a/tor/torProvider.go b/tor/torProvider.go index 8d4b954..2a3e182 100644 --- a/tor/torProvider.go +++ b/tor/torProvider.go @@ -303,6 +303,12 @@ func (tp *torProvider) SetStatusCallback(callback func(int, string)) { tp.statusCallback = callback } +func (tp *torProvider) Callback() func(int, string) { + tp.lock.Lock() + defer tp.lock.Unlock() + return tp.statusCallback +} + func (tp *torProvider) callStatusCallback(prog int, status string) { tp.lock.Lock() if tp.statusCallback != nil {