| @@ -0,0 +1,20 @@ | |||||
| Copyright (c) 2015 Daniel Theophanes | |||||
| This software is provided 'as-is', without any express or implied | |||||
| warranty. In no event will the authors be held liable for any damages | |||||
| arising from the use of this software. | |||||
| Permission is granted to anyone to use this software for any purpose, | |||||
| including commercial applications, and to alter it and redistribute it | |||||
| freely, subject to the following restrictions: | |||||
| 1. The origin of this software must not be misrepresented; you must not | |||||
| claim that you wrote the original software. If you use this software | |||||
| in a product, an acknowledgment in the product documentation would be | |||||
| appreciated but is not required. | |||||
| 2. Altered source versions must be plainly marked as such, and must not be | |||||
| misrepresented as being the original software. | |||||
| 3. This notice may not be removed or altered from any source | |||||
| distribution. | |||||
| @@ -0,0 +1,18 @@ | |||||
| ### Minimal windows service stub | |||||
| Programs designed to run from most *nix style operating systems | |||||
| can import this package to enable running programs as services without modifying | |||||
| them. | |||||
| ``` | |||||
| import _ "github.com/kardianos/minwinsvc" | |||||
| ``` | |||||
| If you need more control over the exit behavior, set | |||||
| ``` | |||||
| minwinsvc.SetOnExit(func() { | |||||
| // Do something. | |||||
| // Within 10 seconds call: | |||||
| os.Exit(0) | |||||
| }) | |||||
| ``` | |||||
| @@ -0,0 +1,18 @@ | |||||
| // Copyright 2015 Daniel Theophanes. | |||||
| // Use of this source code is governed by a zlib-style | |||||
| // license that can be found in the LICENSE file.package service | |||||
| // Minimal non-invasive windows only service stub. | |||||
| // | |||||
| // Import to allow running as a windows service. | |||||
| // import _ "github.com/kardianos/minwinsvc" | |||||
| // This will detect if running as a windows service | |||||
| // and install required callbacks for windows. | |||||
| package minwinsvc | |||||
| // SetOnExit sets the function to be called when the windows service | |||||
| // requests an exit. If this is not called, or if it is called where | |||||
| // f == nil, then it defaults to calling "os.Exit(0)". | |||||
| func SetOnExit(f func()) { | |||||
| setOnExit(f) | |||||
| } | |||||
| @@ -0,0 +1,11 @@ | |||||
| // Copyright 2015 Daniel Theophanes. | |||||
| // Use of this source code is governed by a zlib-style | |||||
| // license that can be found in the LICENSE file.package service | |||||
| //+build !windows | |||||
| package minwinsvc | |||||
| func setOnExit(f func()) { | |||||
| // Nothing. | |||||
| } | |||||
| @@ -0,0 +1,70 @@ | |||||
| // Copyright 2015 Daniel Theophanes. | |||||
| // Use of this source code is governed by a zlib-style | |||||
| // license that can be found in the LICENSE file.package service | |||||
| //+build windows | |||||
| package minwinsvc | |||||
| import ( | |||||
| "os" | |||||
| "sync" | |||||
| "golang.org/x/sys/windows/svc" | |||||
| ) | |||||
| var ( | |||||
| onExit func() | |||||
| guard sync.Mutex | |||||
| ) | |||||
| func init() { | |||||
| interactive, err := svc.IsAnInteractiveSession() | |||||
| if err != nil { | |||||
| panic(err) | |||||
| } | |||||
| if interactive { | |||||
| return | |||||
| } | |||||
| go func() { | |||||
| _ = svc.Run("", runner{}) | |||||
| guard.Lock() | |||||
| f := onExit | |||||
| guard.Unlock() | |||||
| // Don't hold this lock in user code. | |||||
| if f != nil { | |||||
| f() | |||||
| } | |||||
| // Make sure we exit. | |||||
| os.Exit(0) | |||||
| }() | |||||
| } | |||||
| func setOnExit(f func()) { | |||||
| guard.Lock() | |||||
| onExit = f | |||||
| guard.Unlock() | |||||
| } | |||||
| type runner struct{} | |||||
| func (runner) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (bool, uint32) { | |||||
| const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown | |||||
| changes <- svc.Status{State: svc.StartPending} | |||||
| changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted} | |||||
| for { | |||||
| c := <-r | |||||
| switch c.Cmd { | |||||
| case svc.Interrogate: | |||||
| changes <- c.CurrentStatus | |||||
| case svc.Stop, svc.Shutdown: | |||||
| changes <- svc.Status{State: svc.StopPending} | |||||
| return false, 0 | |||||
| } | |||||
| } | |||||
| return false, 0 | |||||
| } | |||||