fetch_ml/internal/network/ssh_pool.go
Jeremie Fraeys ea15af1833 Fix multi-user authentication and clean up debug code
- Fix YAML tags in auth config struct (json -> yaml)
- Update CLI configs to use pre-hashed API keys
- Remove double hashing in WebSocket client
- Fix port mapping (9102 -> 9103) in CLI commands
- Update permission keys to use jobs:read, jobs:create, etc.
- Clean up all debug logging from CLI and server
- All user roles now authenticate correctly:
  * Admin: Can queue jobs and see all jobs
  * Researcher: Can queue jobs and see own jobs
  * Analyst: Can see status (read-only access)

Multi-user authentication is now fully functional.
2025-12-06 12:35:32 -05:00

89 lines
1.8 KiB
Go
Executable file

// Package network provides SSH client and retry utilities.
package network
import (
"context"
"sync"
"github.com/jfraeys/fetch_ml/internal/logging"
)
// SSHPool manages a pool of SSH client connections.
type SSHPool struct {
factory func() (*SSHClient, error)
pool chan *SSHClient
active int
maxConns int
mu sync.Mutex
logger *logging.Logger
}
// NewSSHPool creates a new SSH connection pool.
func NewSSHPool(maxConns int, factory func() (*SSHClient, error), logger *logging.Logger) *SSHPool {
return &SSHPool{
factory: factory,
pool: make(chan *SSHClient, maxConns),
maxConns: maxConns,
logger: logger,
}
}
// Get retrieves an SSH client from the pool or creates a new one.
func (p *SSHPool) Get(ctx context.Context) (*SSHClient, error) {
select {
case conn := <-p.pool:
return conn, nil
case <-ctx.Done():
return nil, ctx.Err()
default:
p.mu.Lock()
if p.active < p.maxConns {
p.active++
p.mu.Unlock()
return p.factory()
}
p.mu.Unlock()
// Wait for available connection
select {
case conn := <-p.pool:
return conn, nil
case <-ctx.Done():
return nil, ctx.Err()
}
}
}
// Put returns an SSH client to the pool.
func (p *SSHPool) Put(conn *SSHClient) {
select {
case p.pool <- conn:
default:
// Pool is full, close connection
err := conn.Close()
if err != nil {
p.logger.Warn("failed to close SSH connection", "error", err)
}
p.mu.Lock()
p.active--
p.mu.Unlock()
}
}
// Close closes all connections in the pool.
func (p *SSHPool) Close() {
p.mu.Lock()
defer p.mu.Unlock()
// Close all connections in the pool
close(p.pool)
for conn := range p.pool {
err := conn.Close()
if err != nil {
p.logger.Warn("failed to close SSH connection", "error", err)
}
}
// Reset active count
p.active = 0
}