mirror of
https://github.com/coder/coder.git
synced 2025-07-06 15:41:45 +00:00
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
169 lines
3.2 KiB
Go
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
|
|
}
|