mirror of
https://github.com/netbirdio/netbird.git
synced 2026-03-31 06:24:18 -04:00
* [client] Add Expose support to embed library Add ability to expose local services via the NetBird reverse proxy from embedded client code. Introduce ExposeSession with a blocking Wait method that keeps the session alive until the context is cancelled. Extract ProtocolType with ParseProtocolType into the expose package and use it across CLI and embed layers. * Fix TestNewRequest assertion to use ProtocolType instead of int * Add documentation for Request and KeepAlive in expose manager * Refactor ExposeSession to pass context explicitly in Wait method * Refactor ExposeSession Wait method to explicitly pass context * Update client/embed/expose.go Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Fix build * Update client/embed/expose.go Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Viktor Liu <viktor@netbird.io> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Viktor Liu <17948409+lixmal@users.noreply.github.com>
105 lines
2.8 KiB
Go
105 lines
2.8 KiB
Go
package expose
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
mgm "github.com/netbirdio/netbird/shared/management/client"
|
|
)
|
|
|
|
const (
|
|
renewTimeout = 10 * time.Second
|
|
)
|
|
|
|
// Response holds the response from exposing a service.
|
|
type Response struct {
|
|
ServiceName string
|
|
ServiceURL string
|
|
Domain string
|
|
PortAutoAssigned bool
|
|
}
|
|
|
|
// Request holds the parameters for exposing a local service via the management server.
|
|
// It is part of the embed API surface and exposed via a type alias.
|
|
type Request struct {
|
|
NamePrefix string
|
|
Domain string
|
|
Port uint16
|
|
Protocol ProtocolType
|
|
Pin string
|
|
Password string
|
|
UserGroups []string
|
|
ListenPort uint16
|
|
}
|
|
|
|
type ManagementClient interface {
|
|
CreateExpose(ctx context.Context, req mgm.ExposeRequest) (*mgm.ExposeResponse, error)
|
|
RenewExpose(ctx context.Context, domain string) error
|
|
StopExpose(ctx context.Context, domain string) error
|
|
}
|
|
|
|
// Manager handles expose session lifecycle via the management client.
|
|
type Manager struct {
|
|
mgmClient ManagementClient
|
|
ctx context.Context
|
|
}
|
|
|
|
// NewManager creates a new expose Manager using the given management client.
|
|
func NewManager(ctx context.Context, mgmClient ManagementClient) *Manager {
|
|
return &Manager{mgmClient: mgmClient, ctx: ctx}
|
|
}
|
|
|
|
// Expose creates a new expose session via the management server.
|
|
func (m *Manager) Expose(ctx context.Context, req Request) (*Response, error) {
|
|
log.Infof("exposing service on port %d", req.Port)
|
|
resp, err := m.mgmClient.CreateExpose(ctx, toClientExposeRequest(req))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
log.Infof("expose session created for %s", resp.Domain)
|
|
|
|
return fromClientExposeResponse(resp), nil
|
|
}
|
|
|
|
// KeepAlive periodically renews the expose session for the given domain until the context is canceled or an error occurs.
|
|
// It is part of the embed API surface and exposed via a type alias.
|
|
func (m *Manager) KeepAlive(ctx context.Context, domain string) error {
|
|
ticker := time.NewTicker(30 * time.Second)
|
|
defer ticker.Stop()
|
|
defer m.stop(domain)
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
log.Infof("context canceled, stopping keep alive for %s", domain)
|
|
|
|
return nil
|
|
case <-ticker.C:
|
|
if err := m.renew(ctx, domain); err != nil {
|
|
log.Errorf("renewing expose session for %s: %v", domain, err)
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// renew extends the TTL of an active expose session.
|
|
func (m *Manager) renew(ctx context.Context, domain string) error {
|
|
renewCtx, cancel := context.WithTimeout(ctx, renewTimeout)
|
|
defer cancel()
|
|
return m.mgmClient.RenewExpose(renewCtx, domain)
|
|
}
|
|
|
|
// stop terminates an active expose session.
|
|
func (m *Manager) stop(domain string) {
|
|
stopCtx, cancel := context.WithTimeout(m.ctx, renewTimeout)
|
|
defer cancel()
|
|
err := m.mgmClient.StopExpose(stopCtx, domain)
|
|
if err != nil {
|
|
log.Warnf("Failed stopping expose session for %s: %v", domain, err)
|
|
}
|
|
}
|