service: update example to use correct import path.

This commit is contained in:
Daniel Theophanes
2015-01-21 14:30:16 -08:00
parent 1e8453e357
commit dfca0ec817
2 changed files with 426 additions and 426 deletions
+105 -105
View File
@@ -1,105 +1,105 @@
// Copyright 2015 Daniel Theophanes. // Copyright 2015 Daniel Theophanes.
// Use of this source code is governed by a zlib-style // Use of this source code is governed by a zlib-style
// license that can be found in the LICENSE file.package service // license that can be found in the LICENSE file.package service
// Simple service that only works by printing a log message every few seconds. // Simple service that only works by printing a log message every few seconds.
package main package main
import ( import (
"flag" "flag"
"log" "log"
"time" "time"
"bitbucket.org/kardianos/service2beta" "github.com/kardianos/service"
) )
var logger service.Logger var logger service.Logger
// Program structures. // Program structures.
// Define Start and Stop methods. // Define Start and Stop methods.
type program struct { type program struct {
exit chan struct{} exit chan struct{}
} }
func (p *program) Start(s service.Service) error { func (p *program) Start(s service.Service) error {
if service.Interactive() { if service.Interactive() {
logger.Info("Running in terminal.") logger.Info("Running in terminal.")
} else { } else {
logger.Info("Running under service manager.") logger.Info("Running under service manager.")
} }
p.exit = make(chan struct{}) p.exit = make(chan struct{})
// Start should not block. Do the actual work async. // Start should not block. Do the actual work async.
go p.run() go p.run()
return nil return nil
} }
func (p *program) run() error { func (p *program) run() error {
logger.Infof("I'm running %v.", service.Platform()) logger.Infof("I'm running %v.", service.Platform())
ticker := time.NewTicker(2 * time.Second) ticker := time.NewTicker(2 * time.Second)
for { for {
select { select {
case tm := <-ticker.C: case tm := <-ticker.C:
logger.Infof("Still running at %v...", tm) logger.Infof("Still running at %v...", tm)
case <-p.exit: case <-p.exit:
ticker.Stop() ticker.Stop()
return nil return nil
} }
} }
return nil return nil
} }
func (p *program) Stop(s service.Service) error { func (p *program) Stop(s service.Service) error {
// Any work in Stop should be quick, usually a few seconds at most. // Any work in Stop should be quick, usually a few seconds at most.
logger.Info("I'm Stopping!") logger.Info("I'm Stopping!")
close(p.exit) close(p.exit)
return nil return nil
} }
// Service setup. // Service setup.
// Define service config. // Define service config.
// Create the service. // Create the service.
// Setup the logger. // Setup the logger.
// Handle service controls (optional). // Handle service controls (optional).
// Run the service. // Run the service.
func main() { func main() {
svcFlag := flag.String("service", "", "Control the system service.") svcFlag := flag.String("service", "", "Control the system service.")
flag.Parse() flag.Parse()
svcConfig := &service.Config{ svcConfig := &service.Config{
Name: "GoServiceTest", Name: "GoServiceTest",
DisplayName: "Go Service Test", DisplayName: "Go Service Test",
Description: "This is a test Go service.", Description: "This is a test Go service.",
} }
prg := &program{} prg := &program{}
s, err := service.New(prg, svcConfig) s, err := service.New(prg, svcConfig)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
errs := make(chan error, 5) errs := make(chan error, 5)
logger, err = s.Logger(errs) logger, err = s.Logger(errs)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
go func() { go func() {
for { for {
err := <-errs err := <-errs
if err != nil { if err != nil {
log.Print(err) log.Print(err)
} }
} }
}() }()
if len(*svcFlag) != 0 { if len(*svcFlag) != 0 {
err := service.Control(s, *svcFlag) err := service.Control(s, *svcFlag)
if err != nil { if err != nil {
log.Printf("Valid actions: %q\n", service.ControlAction) log.Printf("Valid actions: %q\n", service.ControlAction)
log.Fatal(err) log.Fatal(err)
} }
return return
} }
err = s.Run() err = s.Run()
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
} }
} }
+321 -321
View File
@@ -1,321 +1,321 @@
// Copyright 2015 Daniel Theophanes. // Copyright 2015 Daniel Theophanes.
// Use of this source code is governed by a zlib-style // Use of this source code is governed by a zlib-style
// license that can be found in the LICENSE file.package service // license that can be found in the LICENSE file.package service
// Package service provides a simple way to create a system service. // Package service provides a simple way to create a system service.
// Currently supports Windows, Linux/(systemd | Upstart | SysV), and OSX/Launchd. // Currently supports Windows, Linux/(systemd | Upstart | SysV), and OSX/Launchd.
// //
// Windows controls services by setting up callbacks that is non-trivial. This // Windows controls services by setting up callbacks that is non-trivial. This
// is very different then other systems. This package provides the same API // is very different then other systems. This package provides the same API
// despite the substantial differences. // despite the substantial differences.
// It also can be used to detect how a program is called, from an interactive // It also can be used to detect how a program is called, from an interactive
// terminal or from a service manager. // terminal or from a service manager.
/* /*
// Simple service that only works by printing a log message every few seconds. // Simple service that only works by printing a log message every few seconds.
package main package main
import ( import (
"flag" "flag"
"log" "log"
"time" "time"
"bitbucket.org/kardianos/service2beta" "github.com/kardianos/service"
) )
var logger service.Logger var logger service.Logger
// Program structures. // Program structures.
// Define Start and Stop methods. // Define Start and Stop methods.
type program struct { type program struct {
exit chan struct{} exit chan struct{}
} }
func (p *program) Start(s service.Service) error { func (p *program) Start(s service.Service) error {
if service.Interactive() { if service.Interactive() {
logger.Info("Running in terminal.") logger.Info("Running in terminal.")
} else { } else {
logger.Info("Running under service manager.") logger.Info("Running under service manager.")
} }
p.exit = make(chan struct{}) p.exit = make(chan struct{})
// Start should not block. Do the actual work async. // Start should not block. Do the actual work async.
go p.run() go p.run()
return nil return nil
} }
func (p *program) run() error { func (p *program) run() error {
logger.Infof("I'm running %v.", service.Platform()) logger.Infof("I'm running %v.", service.Platform())
ticker := time.NewTicker(2 * time.Second) ticker := time.NewTicker(2 * time.Second)
for { for {
select { select {
case tm := <-ticker.C: case tm := <-ticker.C:
logger.Infof("Still running at %v...", tm) logger.Infof("Still running at %v...", tm)
case <-p.exit: case <-p.exit:
ticker.Stop() ticker.Stop()
return nil return nil
} }
} }
return nil return nil
} }
func (p *program) Stop(s service.Service) error { func (p *program) Stop(s service.Service) error {
// Any work in Stop should be quick, usually a few seconds at most. // Any work in Stop should be quick, usually a few seconds at most.
logger.Info("I'm Stopping!") logger.Info("I'm Stopping!")
close(p.exit) close(p.exit)
return nil return nil
} }
// Service setup. // Service setup.
// Define service config. // Define service config.
// Create the service. // Create the service.
// Setup the logger. // Setup the logger.
// Handle service controls (optional). // Handle service controls (optional).
// Run the service. // Run the service.
func main() { func main() {
svcFlag := flag.String("service", "", "Control the system service.") svcFlag := flag.String("service", "", "Control the system service.")
flag.Parse() flag.Parse()
svcConfig := &service.Config{ svcConfig := &service.Config{
Name: "GoServiceTest", Name: "GoServiceTest",
DisplayName: "Go Service Test", DisplayName: "Go Service Test",
Description: "This is a test Go service.", Description: "This is a test Go service.",
} }
prg := &program{} prg := &program{}
s, err := service.New(prg, svcConfig) s, err := service.New(prg, svcConfig)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
errs := make(chan error, 5) errs := make(chan error, 5)
logger, err = s.Logger(errs) logger, err = s.Logger(errs)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
go func() { go func() {
for { for {
err := <-errs err := <-errs
if err != nil { if err != nil {
log.Print(err) log.Print(err)
} }
} }
}() }()
if len(*svcFlag) != 0 { if len(*svcFlag) != 0 {
err := service.Control(s, *svcFlag) err := service.Control(s, *svcFlag)
if err != nil { if err != nil {
log.Printf("Valid actions: %q\n", service.ControlAction) log.Printf("Valid actions: %q\n", service.ControlAction)
log.Fatal(err) log.Fatal(err)
} }
return return
} }
err = s.Run() err = s.Run()
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
} }
} }
*/ */
package service // import "github.com/kardianos/service" package service // import "github.com/kardianos/service"
import ( import (
"errors" "errors"
"fmt" "fmt"
) )
// Config provides the setup for a Service. The Name field is required. // Config provides the setup for a Service. The Name field is required.
type Config struct { type Config struct {
Name string // Required name of the service. No spaces suggested. Name string // Required name of the service. No spaces suggested.
DisplayName string // Display name, spaces allowed. DisplayName string // Display name, spaces allowed.
Description string // Long description of service. Description string // Long description of service.
UserName string // Run as username. UserName string // Run as username.
Arguments []string // Run with arguments. Arguments []string // Run with arguments.
WorkingDirectory string // Service working directory. WorkingDirectory string // Service working directory.
ChRoot string ChRoot string
UserService bool // Install as a current user service. UserService bool // Install as a current user service.
// System specific options. // System specific options.
Option KeyValue Option KeyValue
} }
var errNameFieldRequired = errors.New("Config.Name field is required.") var errNameFieldRequired = errors.New("Config.Name field is required.")
// New creates a new service based on a service interface and configuration. // New creates a new service based on a service interface and configuration.
func New(i Interface, c *Config) (Service, error) { func New(i Interface, c *Config) (Service, error) {
if len(c.Name) == 0 { if len(c.Name) == 0 {
return nil, errNameFieldRequired return nil, errNameFieldRequired
} }
return newService(i, c) return newService(i, c)
} }
// KeyValue provides a list of platform specific options. See platform docs for // KeyValue provides a list of platform specific options. See platform docs for
// more details. // more details.
type KeyValue map[string]interface{} type KeyValue map[string]interface{}
// Bool returns the value of the given name, assuming the value is a boolean. // Bool returns the value of the given name, assuming the value is a boolean.
// If the value isn't found or is not of the type, the defaultValue is returned. // If the value isn't found or is not of the type, the defaultValue is returned.
func (kv KeyValue) bool(name string, defaultValue bool) bool { func (kv KeyValue) bool(name string, defaultValue bool) bool {
if v, found := kv[name]; found { if v, found := kv[name]; found {
if castValue, is := v.(bool); is { if castValue, is := v.(bool); is {
return castValue return castValue
} }
} }
return defaultValue return defaultValue
} }
// Int returns the value of the given name, assuming the value is an int. // Int returns the value of the given name, assuming the value is an int.
// If the value isn't found or is not of the type, the defaultValue is returned. // If the value isn't found or is not of the type, the defaultValue is returned.
func (kv KeyValue) int(name string, defaultValue int) int { func (kv KeyValue) int(name string, defaultValue int) int {
if v, found := kv[name]; found { if v, found := kv[name]; found {
if castValue, is := v.(int); is { if castValue, is := v.(int); is {
return castValue return castValue
} }
} }
return defaultValue return defaultValue
} }
// Int returns the value of the given name, assuming the value is a string. // Int returns the value of the given name, assuming the value is a string.
// If the value isn't found or is not of the type, the defaultValue is returned. // If the value isn't found or is not of the type, the defaultValue is returned.
func (kv KeyValue) string(name string, defaultValue string) string { func (kv KeyValue) string(name string, defaultValue string) string {
if v, found := kv[name]; found { if v, found := kv[name]; found {
if castValue, is := v.(string); is { if castValue, is := v.(string); is {
return castValue return castValue
} }
} }
return defaultValue return defaultValue
} }
// Int returns the value of the given name, assuming the value is a float64. // Int returns the value of the given name, assuming the value is a float64.
// If the value isn't found or is not of the type, the defaultValue is returned. // If the value isn't found or is not of the type, the defaultValue is returned.
func (kv KeyValue) float64(name string, defaultValue float64) float64 { func (kv KeyValue) float64(name string, defaultValue float64) float64 {
if v, found := kv[name]; found { if v, found := kv[name]; found {
if castValue, is := v.(float64); is { if castValue, is := v.(float64); is {
return castValue return castValue
} }
} }
return defaultValue return defaultValue
} }
// Platform returns a description of the OS and service platform. // Platform returns a description of the OS and service platform.
func Platform() string { func Platform() string {
return system.String() return system.String()
} }
// Interactive returns false if running under the OS service manager // Interactive returns false if running under the OS service manager
// and true otherwise. // and true otherwise.
func Interactive() bool { func Interactive() bool {
return system.Interactive() return system.Interactive()
} }
// runningSystem represents the system and system's service being used. // runningSystem represents the system and system's service being used.
type runningSystem interface { type runningSystem interface {
// String returns a description of the OS and service platform. // String returns a description of the OS and service platform.
String() string String() string
// Interactive returns false if running under the OS service manager // Interactive returns false if running under the OS service manager
// and true otherwise. // and true otherwise.
Interactive() bool Interactive() bool
} }
// Be sure to implement each platform. // Be sure to implement each platform.
var _ runningSystem = system var _ runningSystem = system
// Interface represents the service interface for a program. Start runs before // Interface represents the service interface for a program. Start runs before
// the hosting process is granted control and Stop runs when control is returned. // the hosting process is granted control and Stop runs when control is returned.
// //
// 1. OS service manager executes user program. // 1. OS service manager executes user program.
// 2. User program sees it is executed from a service manager (IsInteractive is false). // 2. User program sees it is executed from a service manager (IsInteractive is false).
// 3. User program calls Service.Run() which blocks. // 3. User program calls Service.Run() which blocks.
// 4. Interface.Start() is called and quickly returns. // 4. Interface.Start() is called and quickly returns.
// 5. User program runs. // 5. User program runs.
// 6. OS service manager signals the user program to stop. // 6. OS service manager signals the user program to stop.
// 7. Interface.Stop() is called and quickly returns. // 7. Interface.Stop() is called and quickly returns.
// - For a successful exit, os.Exit should not be called in Interface.Stop(). // - For a successful exit, os.Exit should not be called in Interface.Stop().
// 8. Service.Run returns. // 8. Service.Run returns.
// 9. User program should quickly exit. // 9. User program should quickly exit.
type Interface interface { type Interface interface {
// Start provides a place to initiate the service. The service doesn't not // Start provides a place to initiate the service. The service doesn't not
// signal a completed start until after this function returns, so the // signal a completed start until after this function returns, so the
// Start function must not take more then a few seconds at most. // Start function must not take more then a few seconds at most.
Start(s Service) error Start(s Service) error
// Stop provides a place to clean up program execution before it is terminated. // Stop provides a place to clean up program execution before it is terminated.
// It should not take more then a few seconds to execute. // It should not take more then a few seconds to execute.
// Stop should not call os.Exit directly in the function. // Stop should not call os.Exit directly in the function.
Stop(s Service) error Stop(s Service) error
} }
// Service represents a service that can be run or controlled. // Service represents a service that can be run or controlled.
type Service interface { type Service interface {
// Run should be called shortly after the program entry point. // Run should be called shortly after the program entry point.
// After Interface.Stop has finished running, Run will stop blocking. // After Interface.Stop has finished running, Run will stop blocking.
// After Run stops blocking, the program must exit shortly after. // After Run stops blocking, the program must exit shortly after.
Run() error Run() error
// Start signals to the OS service manager the given service should start. // Start signals to the OS service manager the given service should start.
Start() error Start() error
// Stop signals to the OS service manager the given service should stop. // Stop signals to the OS service manager the given service should stop.
Stop() error Stop() error
// Restart signals to the OS service manager the given service should stop then start. // Restart signals to the OS service manager the given service should stop then start.
Restart() error Restart() error
// Install setups up the given service in the OS service manager. This may require // Install setups up the given service in the OS service manager. This may require
// greater rights. Will return an error if it is already installed. // greater rights. Will return an error if it is already installed.
Install() error Install() error
// Uninstall removes the given service from the OS service manager. This may require // Uninstall removes the given service from the OS service manager. This may require
// greater rights. Will return an error if the service is not present. // greater rights. Will return an error if the service is not present.
Uninstall() error Uninstall() error
// Opens and returns a system logger. If the user program is running // Opens and returns a system logger. If the user program is running
// interactively rather then as a service, the returned logger will write to // interactively rather then as a service, the returned logger will write to
// os.Stderr. If errs is non-nil errors will be sent on errs as well as // os.Stderr. If errs is non-nil errors will be sent on errs as well as
// returned from Logger's functions. // returned from Logger's functions.
Logger(errs chan<- error) (Logger, error) Logger(errs chan<- error) (Logger, error)
// SystemLogger opens and returns a system logger. If errs is non-nil errors // SystemLogger opens and returns a system logger. If errs is non-nil errors
// will be sent on errs as well as returned from Logger's functions. // will be sent on errs as well as returned from Logger's functions.
SystemLogger(errs chan<- error) (Logger, error) SystemLogger(errs chan<- error) (Logger, error)
// String displays the name of the service. The display name if present, // String displays the name of the service. The display name if present,
// otherwise the name. // otherwise the name.
String() string String() string
} }
// ControlAction list valid string texts to use in Control. // ControlAction list valid string texts to use in Control.
var ControlAction = [5]string{"start", "stop", "restart", "install", "uninstall"} var ControlAction = [5]string{"start", "stop", "restart", "install", "uninstall"}
// Control issues control functions to the service from a given action string. // Control issues control functions to the service from a given action string.
func Control(s Service, action string) error { func Control(s Service, action string) error {
var err error var err error
switch action { switch action {
case ControlAction[0]: case ControlAction[0]:
err = s.Start() err = s.Start()
case ControlAction[1]: case ControlAction[1]:
err = s.Stop() err = s.Stop()
case ControlAction[2]: case ControlAction[2]:
err = s.Restart() err = s.Restart()
case ControlAction[3]: case ControlAction[3]:
err = s.Install() err = s.Install()
case ControlAction[4]: case ControlAction[4]:
err = s.Uninstall() err = s.Uninstall()
default: default:
err = fmt.Errorf("Unknown action %s", action) err = fmt.Errorf("Unknown action %s", action)
} }
if err != nil { if err != nil {
return fmt.Errorf("Failed to %s %v: %v", action, s, err) return fmt.Errorf("Failed to %s %v: %v", action, s, err)
} }
return nil return nil
} }
// Logger writes to the system log. // Logger writes to the system log.
type Logger interface { type Logger interface {
Error(v ...interface{}) error Error(v ...interface{}) error
Warning(v ...interface{}) error Warning(v ...interface{}) error
Info(v ...interface{}) error Info(v ...interface{}) error
Errorf(format string, a ...interface{}) error Errorf(format string, a ...interface{}) error
Warningf(format string, a ...interface{}) error Warningf(format string, a ...interface{}) error
Infof(format string, a ...interface{}) error Infof(format string, a ...interface{}) error
} }