github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/model/stack/main.go (about)

     1  package stack
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  
     8  	"github.com/cozy/cozy-stack/model/cloudery"
     9  	"github.com/cozy/cozy-stack/model/instance"
    10  	"github.com/cozy/cozy-stack/model/job"
    11  	"github.com/cozy/cozy-stack/model/session"
    12  	"github.com/cozy/cozy-stack/model/settings"
    13  	"github.com/cozy/cozy-stack/model/token"
    14  	"github.com/cozy/cozy-stack/pkg/assets/dynamic"
    15  	build "github.com/cozy/cozy-stack/pkg/config"
    16  	"github.com/cozy/cozy-stack/pkg/config/config"
    17  	"github.com/cozy/cozy-stack/pkg/couchdb"
    18  	"github.com/cozy/cozy-stack/pkg/emailer"
    19  	"github.com/cozy/cozy-stack/pkg/utils"
    20  
    21  	"github.com/google/gops/agent"
    22  )
    23  
    24  // Options can be used to give options when starting the stack.
    25  type Options int
    26  
    27  const (
    28  	// NoGops option can be used to disable gops support
    29  	NoGops Options = iota + 1
    30  	// NoDynAssets option can be used to initialize the dynamic assets
    31  	NoDynAssets
    32  )
    33  
    34  func hasOptions(needle Options, haystack []Options) bool {
    35  	for _, opt := range haystack {
    36  		if opt == needle {
    37  			return true
    38  		}
    39  	}
    40  	return false
    41  }
    42  
    43  type gopAgent struct{}
    44  
    45  func (g gopAgent) Shutdown(ctx context.Context) error {
    46  	fmt.Print("  shutting down gops...")
    47  	agent.Close()
    48  	fmt.Println("ok.")
    49  	return nil
    50  }
    51  
    52  type Services struct {
    53  	Emailer  emailer.Emailer
    54  	Settings settings.Service
    55  }
    56  
    57  // Start is used to initialize all the
    58  func Start(opts ...Options) (utils.Shutdowner, *Services, error) {
    59  	if build.IsDevRelease() {
    60  		fmt.Print(`                           !! DEVELOPMENT RELEASE !!
    61  You are running a development release which may deactivate some very important
    62  security features. Please do not use this binary as your production server.
    63  
    64  `)
    65  	}
    66  
    67  	var shutdowners []utils.Shutdowner
    68  
    69  	ctx := context.Background()
    70  
    71  	if !hasOptions(NoGops, opts) {
    72  		err := agent.Listen(agent.Options{})
    73  		if err != nil {
    74  			fmt.Fprintf(os.Stderr, "Error on gops agent: %s\n", err)
    75  		}
    76  		shutdowners = append(shutdowners, gopAgent{})
    77  	}
    78  
    79  	if err := couchdb.InitGlobalDB(ctx); err != nil {
    80  		return nil, nil, fmt.Errorf("failed to init the global db: %w", err)
    81  	}
    82  
    83  	// Init the main global connection to the swift server
    84  	if err := config.InitDefaultSwiftConnection(); err != nil {
    85  		return nil, nil, fmt.Errorf("failed to init the swift connection: %w", err)
    86  	}
    87  
    88  	workersList, err := job.GetWorkersList()
    89  	if err != nil {
    90  		return nil, nil, fmt.Errorf("failed to get the workers list: %w", err)
    91  	}
    92  
    93  	var broker job.Broker
    94  	var schder job.Scheduler
    95  	jobsConfig := config.GetConfig().Jobs
    96  	if jobsConfig.Client != nil {
    97  		broker = job.NewRedisBroker(jobsConfig.Client)
    98  		schder = job.NewRedisScheduler(jobsConfig.Client)
    99  	} else {
   100  		broker = job.NewMemBroker()
   101  		schder = job.NewMemScheduler()
   102  	}
   103  
   104  	if err = job.SystemStart(broker, schder, workersList); err != nil {
   105  		return nil, nil, fmt.Errorf("failed to start the jobs: %w", err)
   106  	}
   107  	shutdowners = append(shutdowners, job.System())
   108  
   109  	tokenSvc := token.NewService(config.GetConfig().CacheStorage)
   110  	emailerSvc := emailer.Init()
   111  	instanceSvc := instance.Init()
   112  	clouderySvc := cloudery.Init(config.GetConfig().Clouderies)
   113  
   114  	services := Services{
   115  		Emailer:  emailerSvc,
   116  		Settings: settings.Init(emailerSvc, instanceSvc, tokenSvc, clouderySvc),
   117  	}
   118  
   119  	// Initialize the dynamic assets FS. Can be OsFs, MemFs or Swift
   120  	if !hasOptions(NoDynAssets, opts) {
   121  		err = dynamic.InitDynamicAssetFS(config.FsURL().String())
   122  		if err != nil {
   123  			return nil, nil, fmt.Errorf("failed to init the dynamic asset fs: %w", err)
   124  		}
   125  	}
   126  
   127  	sessionSweeper := session.SweepLoginRegistrations()
   128  	shutdowners = append(shutdowners, sessionSweeper)
   129  
   130  	// Global shutdowner that composes all the running processes of the stack
   131  	processes := utils.NewGroupShutdown(shutdowners...)
   132  
   133  	return processes, &services, nil
   134  }