2020-11-29 03:22:39 +05:00
|
|
|
package application
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"log"
|
2020-11-29 05:44:21 +05:00
|
|
|
"net/http"
|
|
|
|
"sync"
|
2020-11-29 03:22:39 +05:00
|
|
|
|
2020-11-29 06:09:35 +05:00
|
|
|
"go.dev.pztrn.name/metricator/internal/common"
|
2020-11-29 03:22:39 +05:00
|
|
|
"go.dev.pztrn.name/metricator/internal/storage"
|
|
|
|
"go.dev.pztrn.name/metricator/internal/storage/memory"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Application is a thing that responsible for all application-related
|
|
|
|
// actions like data fetching, storing, etc. on higher level.
|
|
|
|
type Application struct {
|
|
|
|
config *Config
|
|
|
|
ctx context.Context
|
|
|
|
doneChan chan struct{}
|
|
|
|
name string
|
|
|
|
|
|
|
|
storage storage.Metrics
|
|
|
|
storageDone chan struct{}
|
2020-11-29 05:44:21 +05:00
|
|
|
|
|
|
|
fetchIsRunning bool
|
|
|
|
fetchIsRunningMutex sync.RWMutex
|
|
|
|
|
|
|
|
httpClient *http.Client
|
2020-11-29 03:22:39 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewApplication creates new application.
|
|
|
|
func NewApplication(ctx context.Context, name string, config *Config) *Application {
|
|
|
|
a := &Application{
|
|
|
|
config: config,
|
|
|
|
ctx: ctx,
|
|
|
|
doneChan: make(chan struct{}),
|
|
|
|
name: name,
|
|
|
|
}
|
|
|
|
a.initialize()
|
|
|
|
|
|
|
|
return a
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetDoneChan returns a channel which should be used to block execution until
|
|
|
|
// application's routines are completed.
|
|
|
|
func (a *Application) GetDoneChan() chan struct{} {
|
|
|
|
return a.doneChan
|
|
|
|
}
|
|
|
|
|
2020-11-29 06:09:35 +05:00
|
|
|
// GetHandler returns HTTP requests handling function.
|
|
|
|
func (a *Application) GetHandler() common.HTTPHandlerFunc {
|
|
|
|
return a.respond
|
|
|
|
}
|
|
|
|
|
2020-11-29 03:22:39 +05:00
|
|
|
// Initializes internal things like storage, HTTP client, etc.
|
|
|
|
func (a *Application) initialize() {
|
|
|
|
a.storage, a.storageDone = memory.NewStorage(a.ctx, a.name+" storage")
|
|
|
|
|
|
|
|
log.Printf("Application '%s' initialized with configuration: %+v\n", a.name, a.config)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start starts asynchronous things like data fetching, storage cleanup, etc.
|
|
|
|
func (a *Application) Start() {
|
|
|
|
a.storage.Start()
|
|
|
|
|
2020-11-29 05:44:21 +05:00
|
|
|
go a.startFetcher()
|
|
|
|
|
2020-11-29 03:22:39 +05:00
|
|
|
// The Context Listening Goroutine.
|
|
|
|
go func() {
|
|
|
|
<-a.ctx.Done()
|
|
|
|
// We should wait until storage routines are also stopped.
|
|
|
|
<-a.storage.GetDoneChan()
|
|
|
|
|
|
|
|
log.Println("Application", a.name, "stopped")
|
|
|
|
|
|
|
|
a.doneChan <- struct{}{}
|
|
|
|
}()
|
|
|
|
}
|