Files
coder/tailnet/multiagent.go
Spike Curtis 1e8a9c09fe chore: remove legacy wsconncache (#11816)
Fixes #8218

Removes `wsconncache` and related "is legacy?" functions and API calls that were used by it.

The only leftover is that Agents still use the legacy IP, so that back level clients or workspace proxies can dial them correctly.

We should eventually remove this: #11819
2024-01-30 07:56:36 +04:00

169 lines
3.2 KiB
Go

package tailnet
import (
"context"
"sync"
"sync/atomic"
"time"
"github.com/google/uuid"
"golang.org/x/xerrors"
"github.com/coder/coder/v2/tailnet/proto"
)
type MultiAgentConn interface {
UpdateSelf(node *proto.Node) error
SubscribeAgent(agentID uuid.UUID) error
UnsubscribeAgent(agentID uuid.UUID) error
NextUpdate(ctx context.Context) (*proto.CoordinateResponse, bool)
Close() error
IsClosed() bool
}
type MultiAgent struct {
mu sync.RWMutex
ID uuid.UUID
OnSubscribe func(enq Queue, agent uuid.UUID) error
OnUnsubscribe func(enq Queue, agent uuid.UUID) error
OnNodeUpdate func(id uuid.UUID, node *proto.Node) error
OnRemove func(enq Queue)
ctx context.Context
ctxCancel func()
closed bool
updates chan *proto.CoordinateResponse
closeOnce sync.Once
start int64
lastWrite int64
// Client nodes normally generate a unique id for each connection so
// overwrites are really not an issue, but is provided for compatibility.
overwrites int64
}
func (m *MultiAgent) Init() *MultiAgent {
m.updates = make(chan *proto.CoordinateResponse, 128)
m.start = time.Now().Unix()
m.ctx, m.ctxCancel = context.WithCancel(context.Background())
return m
}
func (*MultiAgent) Kind() QueueKind {
return QueueKindClient
}
func (m *MultiAgent) UniqueID() uuid.UUID {
return m.ID
}
var ErrMultiAgentClosed = xerrors.New("multiagent is closed")
func (m *MultiAgent) UpdateSelf(node *proto.Node) error {
m.mu.RLock()
defer m.mu.RUnlock()
if m.closed {
return ErrMultiAgentClosed
}
return m.OnNodeUpdate(m.ID, node)
}
func (m *MultiAgent) SubscribeAgent(agentID uuid.UUID) error {
m.mu.RLock()
defer m.mu.RUnlock()
if m.closed {
return ErrMultiAgentClosed
}
err := m.OnSubscribe(m, agentID)
if err != nil {
return err
}
return nil
}
func (m *MultiAgent) UnsubscribeAgent(agentID uuid.UUID) error {
m.mu.RLock()
defer m.mu.RUnlock()
if m.closed {
return ErrMultiAgentClosed
}
return m.OnUnsubscribe(m, agentID)
}
func (m *MultiAgent) NextUpdate(ctx context.Context) (*proto.CoordinateResponse, bool) {
select {
case <-ctx.Done():
return nil, false
case resp, ok := <-m.updates:
return resp, ok
}
}
func (m *MultiAgent) Enqueue(resp *proto.CoordinateResponse) error {
m.mu.RLock()
defer m.mu.RUnlock()
if m.closed {
return nil
}
return m.enqueueLocked(resp)
}
func (m *MultiAgent) enqueueLocked(resp *proto.CoordinateResponse) error {
atomic.StoreInt64(&m.lastWrite, time.Now().Unix())
select {
case m.updates <- resp:
return nil
default:
return ErrWouldBlock
}
}
func (m *MultiAgent) Name() string {
return m.ID.String()
}
func (m *MultiAgent) Stats() (start int64, lastWrite int64) {
return m.start, atomic.LoadInt64(&m.lastWrite)
}
func (m *MultiAgent) Overwrites() int64 {
return m.overwrites
}
func (m *MultiAgent) IsClosed() bool {
m.mu.RLock()
defer m.mu.RUnlock()
return m.closed
}
func (m *MultiAgent) CoordinatorClose() error {
m.mu.Lock()
if !m.closed {
m.closed = true
close(m.updates)
}
m.mu.Unlock()
return nil
}
func (m *MultiAgent) Done() <-chan struct{} {
return m.ctx.Done()
}
func (m *MultiAgent) Close() error {
_ = m.CoordinatorClose()
m.ctxCancel()
m.closeOnce.Do(func() { m.OnRemove(m) })
return nil
}