<commit_before>package services

import (
	"fmt"
	"strings"
	"sync"

	"github.com/akutz/gofig"
	"github.com/akutz/goof"

	"github.com/emccode/libstorage/api/types"
)

var (
	servicesByServer    = map[string]*serviceContainer{}
	servicesByServerRWL = &sync.RWMutex{}
)

type serviceContainer struct {
	config          gofig.Config
	storageServices map[string]types.StorageService
	taskService     *globalTaskService
}

// Init initializes the types.
func Init(ctx types.Context, config gofig.Config) error {
	serverName := ctx.ServerName()
	ctx.Info("initializing server services")

	sc := &serviceContainer{
		taskService:     &globalTaskService{name: "global-task-service"},
		storageServices: map[string]types.StorageService{},
	}

	if err := sc.Init(ctx, config); err != nil {
		return err
	}

	servicesByServerRWL.Lock()
	defer servicesByServerRWL.Unlock()
	servicesByServer[serverName] = sc

	return nil
}

func (sc *serviceContainer) Init(ctx types.Context, config gofig.Config) error {
	sc.config = config

	if err := sc.taskService.Init(config); err != nil {
		return err
	}

	if err := sc.initStorageServices(ctx); err != nil {
		return err
	}

	return nil
}

func getStorageServices(
	ctx types.Context) map[string]types.StorageService {
	return servicesByServer[ctx.ServerName()].storageServices
}

// GetStorageService returns the storage service specified by the given name;
// otherwise a nil value is returned if no such service exists.
func GetStorageService(
	ctx types.Context, name string) types.StorageService {
	servicesByServerRWL.RLock()
	defer servicesByServerRWL.RUnlock()
	name = strings.ToLower(name)
	ctx.WithField("service", name).Debug("getting storage service")
	return getStorageServices(ctx)[name]
}

// StorageServices returns a channel on which all the storage services are
// received.
func StorageServices(ctx types.Context) <-chan types.StorageService {
	c := make(chan types.StorageService)
	go func() {
		for _, v := range getStorageServices(ctx) {
			c <- v
		}
		close(c)
	}()
	return c
}

func (sc *serviceContainer) initStorageServices(ctx types.Context) error {
	if ctx == nil {
		panic("ctx is nil")
	}
	if sc.config == nil {
		panic("sc.config is nil")
	}
	cfgSvcs := sc.config.Get(types.ConfigServices)
	cfgSvcsMap, ok := cfgSvcs.(map[string]interface{})
	if !ok {
		err := goof.WithFields(goof.Fields{
			"configKey": types.ConfigServices,
			"obj":       cfgSvcs,
		}, "invalid format")
		return err
	}
	ctx.WithField("count", len(cfgSvcsMap)).Debug("got services map")

	for serviceName := range cfgSvcsMap {
		serviceName = strings.ToLower(serviceName)

		svcCtx := ctx.WithContextSID(types.ContextServiceName, serviceName)
		svcCtx.Debug("processing service config")

		scope := fmt.Sprintf("libstorage.server.services.%s", serviceName)
		svcCtx.WithField("scope", scope).Debug(
			"getting scoped config for service")
		config := sc.config.Scope(scope)

		storSvc := &storageService{name: serviceName}
		if err := storSvc.Init(svcCtx, config); err != nil {
			return err<commit_msg>Auto Service<commit_after>package services

import (
	"fmt"
	"strings"
	"sync"

	"github.com/akutz/gofig"
	"github.com/akutz/goof"

	"github.com/emccode/libstorage/api/types"
)

var (
	servicesByServer    = map[string]*serviceContainer{}
	servicesByServerRWL = &sync.RWMutex{}
)

type serviceContainer struct {
	config          gofig.Config
	storageServices map[string]types.StorageService
	taskService     *globalTaskService
}

// Init initializes the types.
func Init(ctx types.Context, config gofig.Config) error {
	serverName := ctx.ServerName()
	ctx.Info("initializing server services")

	sc := &serviceContainer{
		taskService:     &globalTaskService{name: "global-task-service"},
		storageServices: map[string]types.StorageService{},
	}

	if err := sc.Init(ctx, config); err != nil {
		return err
	}

	servicesByServerRWL.Lock()
	defer servicesByServerRWL.Unlock()
	servicesByServer[serverName] = sc

	return nil
}

func (sc *serviceContainer) Init(ctx types.Context, config gofig.Config) error {
	sc.config = config

	if err := sc.taskService.Init(config); err != nil {
		return err
	}

	if err := sc.initStorageServices(ctx); err != nil {
		return err
	}

	return nil
}

func getStorageServices(
	ctx types.Context) map[string]types.StorageService {
	return servicesByServer[ctx.ServerName()].storageServices
}

// GetStorageService returns the storage service specified by the given name;
// otherwise a nil value is returned if no such service exists.
func GetStorageService(
	ctx types.Context, name string) types.StorageService {
	servicesByServerRWL.RLock()
	defer servicesByServerRWL.RUnlock()
	name = strings.ToLower(name)
	ctx.WithField("service", name).Debug("getting storage service")
	return getStorageServices(ctx)[name]
}

// StorageServices returns a channel on which all the storage services are
// received.
func StorageServices(ctx types.Context) <-chan types.StorageService {
	c := make(chan types.StorageService)
	go func() {
		for _, v := range getStorageServices(ctx) {
			c <- v
		}
		close(c)
	}()
	return c
}

func (sc *serviceContainer) initStorageServices(ctx types.Context) error {
	if ctx == nil {
		panic("ctx is nil")
	}
	if sc.config == nil {
		panic("sc.config is nil")
	}
	cfgSvcs := sc.config.Get(types.ConfigServices)
	cfgSvcsMap, ok := cfgSvcs.(map[string]interface{})
	if !ok {
		driverName := sc.config.GetString("libstorage.driver")
		if driverName == "" {
			err := goof.WithFields(goof.Fields{
				"configKey": types.ConfigServices,
				"obj":       cfgSvcs,
			}, "invalid format")
			return err
		}

		cfgSvcsMap = map[string]interface{}{
			driverName: map[string]interface{}{
				"driver": driverName,
			},
		}
	}
	ctx.WithField("count", len(cfgSvcsMap)).Debug("got services map")

	for serviceName := range cfgSvcsMap {
		serviceName = strings.ToLower(serviceName)

		svcCtx := ctx.WithContextSID(types.ContextServiceName, serviceName)
		svcCtx.Debug("processing service config")

		scope := fmt.Sprintf("libstorage.server.services.%s", serviceName)
		svcCtx.WithField("scope", scope).Debug(
			"getting scoped config for service")
		config := sc.config.Scope(scope)

		storSvc := &storageService{name: serviceName}
		if err := storSvc.Init(svcCtx, config); err != nil {
			return err
{'fraction_non_alphanumeric': 0.12396430847673677, 'fraction_numerical': 0.0, 'mean_word_length': 4.501314636283961, 'pattern_counts': {'":': 5, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7125978', 'n_tokens_mistral': 2113, 'n_tokens_neox': 2020, 'n_words': 484}