blob: 3f590e351db9bf0d30d78b6044709c716dfa5733 [file] [log] [blame] [edit]
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package apid
import (
"errors"
"os"
"time"
)
const (
SystemEventsSelector EventSelector = "system event"
ShutdownEventSelector EventSelector = "shutdown event"
ShutdownTimeout time.Duration = 10 * time.Second
)
var (
APIDInitializedEvent = systemEvent{"apid initialized"}
APIListeningEvent = systemEvent{"api listening"}
pluginInitFuncs []PluginInitFunc
services Services
)
type Services interface {
API() APIService
Config() ConfigService
Data() DataService
Events() EventsService
Log() LogService
}
type PluginInitFunc func(Services) (PluginData, error)
// passed Services can be a factory - makes copies and maintains returned references
// eg. apid.Initialize(factory.DefaultServicesFactory())
func Initialize(s Services) {
ss := &servicesSet{}
services = ss
// order is important
ss.config = s.Config()
ss.log = s.Log()
// ensure storage path exists
lsp := ss.config.GetString("local_storage_path")
if err := os.MkdirAll(lsp, 0700); err != nil {
ss.log.Panicf("can't create local storage path %s: %v", lsp, err)
}
ss.events = s.Events()
ss.api = s.API()
ss.data = s.Data()
ss.events.Emit(SystemEventsSelector, APIDInitializedEvent)
}
func RegisterPlugin(plugin PluginInitFunc) {
pluginInitFuncs = append(pluginInitFuncs, plugin)
}
func InitializePlugins(versionNumber string) {
log := Log()
log.Debugf("Initializing %d plugins...", len(pluginInitFuncs))
pie := PluginsInitializedEvent{
Description: "plugins initialized",
ApidVersion: versionNumber,
}
for _, pif := range pluginInitFuncs {
pluginData, err := pif(services)
if err != nil {
log.Panicf("Error initializing plugin: %s", err)
}
pie.Plugins = append(pie.Plugins, pluginData)
}
pluginInitFuncs = nil
Events().Emit(SystemEventsSelector, pie)
log.Debugf("done initializing plugins")
}
// Shutdown all the plugins that have registered for ShutdownEventSelector.
// This call will block until either all required plugins shutdown, or a timeout occurred.
func ShutdownPluginsAndWait() error {
shutdownEvent := ShutdownEvent{"apid is going to shutdown"}
eventChan := Events().Emit(ShutdownEventSelector, shutdownEvent)
select {
case event := <-eventChan:
if e, ok := event.(ShutdownEvent); ok {
if e == shutdownEvent {
return nil
}
}
return errors.New("Emit() problem: wrong event delivered")
case <-time.After(ShutdownTimeout):
return errors.New("Shutdown timeout")
}
}
func AllServices() Services {
return services
}
func Log() LogService {
return services.Log()
}
func API() APIService {
return services.API()
}
func Config() ConfigService {
return services.Config()
}
func Data() DataService {
return services.Data()
}
func Events() EventsService {
return services.Events()
}
type servicesSet struct {
config ConfigService
log LogService
api APIService
data DataService
events EventsService
}
func (s *servicesSet) API() APIService {
return s.api
}
func (s *servicesSet) Config() ConfigService {
return s.config
}
func (s *servicesSet) Data() DataService {
return s.data
}
func (s *servicesSet) Events() EventsService {
return s.events
}
func (s *servicesSet) Log() LogService {
return s.log
}
type systemEvent struct {
description string
}
type ShutdownEvent struct {
Description string
}