// SPDX-FileCopyrightText: 2022 Free Mobile // SPDX-License-Identifier: AGPL-3.0-only // Package core plumbs all the other components together. package core import ( "time" "gopkg.in/tomb.v2" "akvorado/common/daemon" "akvorado/common/helpers/cache" "akvorado/common/httpserver" "akvorado/common/reporter" "akvorado/common/schema" "akvorado/outlet/clickhouse" "akvorado/outlet/flow" "akvorado/outlet/kafka" "akvorado/outlet/metadata" "akvorado/outlet/routing" ) // Component represents the HTTP compomenent. type Component struct { r *reporter.Reporter d *Dependencies t tomb.Tomb config Configuration metrics metrics httpFlowClients uint32 // for dumping flows httpFlowChannel chan []byte httpFlowFlushDelay time.Duration classifierExporterCache *cache.Cache[exporterInfo, exporterClassification] classifierInterfaceCache *cache.Cache[exporterAndInterfaceInfo, interfaceClassification] classifierErrLogger reporter.Logger } // Dependencies define the dependencies of the HTTP component. type Dependencies struct { Daemon daemon.Component Flow *flow.Component Metadata *metadata.Component Routing *routing.Component Kafka kafka.Component ClickHouse clickhouse.Component HTTP *httpserver.Component Schema *schema.Component } // New creates a new core component. func New(r *reporter.Reporter, configuration Configuration, dependencies Dependencies) (*Component, error) { c := Component{ r: r, d: &dependencies, config: configuration, httpFlowClients: 0, httpFlowChannel: make(chan []byte, 10), httpFlowFlushDelay: time.Second, classifierExporterCache: cache.New[exporterInfo, exporterClassification](), classifierInterfaceCache: cache.New[exporterAndInterfaceInfo, interfaceClassification](), classifierErrLogger: r.Sample(reporter.BurstSampler(10*time.Second, 3)), } c.d.Daemon.Track(&c.t, "outlet/core") c.initMetrics() return &c, nil } // Start starts the core component. func (c *Component) Start() error { c.r.Info().Msg("starting core component") c.d.Kafka.StartWorkers(c.newWorker) // Classifier cache expiration c.t.Go(func() error { for { select { case <-c.t.Dying(): return nil case <-time.After(c.config.ClassifierCacheDuration): before := time.Now().Add(-c.config.ClassifierCacheDuration) c.classifierExporterCache.DeleteLastAccessedBefore(before) c.classifierInterfaceCache.DeleteLastAccessedBefore(before) } } }) c.d.HTTP.GinRouter.GET("/api/v0/outlet/flows", c.FlowsHTTPHandler) return nil } // Stop stops the core component. func (c *Component) Stop() error { defer func() { close(c.httpFlowChannel) c.r.Info().Msg("core component stopped") }() c.r.Info().Msg("stopping core component") c.t.Kill(nil) return c.t.Wait() }