mirror of
https://gitee.com/rainbond/Rainbond.git
synced 2024-12-04 20:57:38 +08:00
168 lines
4.4 KiB
Go
168 lines
4.4 KiB
Go
// RAINBOND, Application Management Platform
|
|
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version. For any non-GPL usage of Rainbond,
|
|
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
|
|
// must be obtained first.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package windows
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/windows"
|
|
"golang.org/x/sys/windows/svc"
|
|
"golang.org/x/sys/windows/svc/eventlog"
|
|
"golang.org/x/sys/windows/svc/mgr"
|
|
)
|
|
|
|
//RegisterService register a service
|
|
func RegisterService(serviceName, execPath, displayName string, depends, args []string) error {
|
|
m, err := mgr.Connect()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer m.Disconnect()
|
|
c := mgr.Config{
|
|
ServiceType: windows.SERVICE_WIN32_OWN_PROCESS,
|
|
StartType: mgr.StartAutomatic,
|
|
ErrorControl: mgr.ErrorNormal,
|
|
Dependencies: depends,
|
|
DisplayName: displayName,
|
|
}
|
|
|
|
s, err := m.CreateService(serviceName, execPath, c, args...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer s.Close()
|
|
|
|
// See http://stackoverflow.com/questions/35151052/how-do-i-configure-failure-actions-of-a-windows-service-written-in-go
|
|
const (
|
|
scActionNone = 0
|
|
scActionRestart = 1
|
|
scActionReboot = 2
|
|
scActionRunCommand = 3
|
|
|
|
serviceConfigFailureActions = 2
|
|
)
|
|
|
|
type serviceFailureActions struct {
|
|
ResetPeriod uint32
|
|
RebootMsg *uint16
|
|
Command *uint16
|
|
ActionsCount uint32
|
|
Actions uintptr
|
|
}
|
|
|
|
type scAction struct {
|
|
Type uint32
|
|
Delay uint32
|
|
}
|
|
t := []scAction{
|
|
{Type: scActionRestart, Delay: uint32(60 * time.Second / time.Millisecond)},
|
|
{Type: scActionRestart, Delay: uint32(60 * time.Second / time.Millisecond)},
|
|
{Type: scActionNone},
|
|
}
|
|
lpInfo := serviceFailureActions{ResetPeriod: uint32(24 * time.Hour / time.Second), ActionsCount: uint32(3), Actions: uintptr(unsafe.Pointer(&t[0]))}
|
|
err = windows.ChangeServiceConfig2(s.Handle, serviceConfigFailureActions, (*byte)(unsafe.Pointer(&lpInfo)))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return eventlog.Install(serviceName, execPath, false, eventlog.Info|eventlog.Warning|eventlog.Error)
|
|
}
|
|
|
|
//UnRegisterService unres
|
|
func UnRegisterService(serviceName string) error {
|
|
m, err := mgr.Connect()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer m.Disconnect()
|
|
s, err := m.OpenService(serviceName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer s.Close()
|
|
eventlog.Remove(serviceName)
|
|
err = s.Delete()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
//StartService start a windows service
|
|
func StartService(serviceName string) error {
|
|
m, err := mgr.Connect()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer m.Disconnect()
|
|
s, err := m.OpenService(serviceName)
|
|
if err != nil {
|
|
return fmt.Errorf("could not open service: %v", err)
|
|
}
|
|
defer s.Close()
|
|
err = s.Start()
|
|
if err != nil {
|
|
return fmt.Errorf("could not start service: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
//StopService stop a windows service
|
|
func StopService(serviceName string) error {
|
|
return controlService(serviceName, svc.Stop, svc.Stopped)
|
|
}
|
|
|
|
//RestartService restart a windows service
|
|
func RestartService(serviceName string) error {
|
|
if err := controlService(serviceName, svc.Stop, svc.Stopped); err != nil {
|
|
return err
|
|
}
|
|
return StartService(serviceName)
|
|
}
|
|
|
|
func controlService(name string, c svc.Cmd, to svc.State) error {
|
|
m, err := mgr.Connect()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer m.Disconnect()
|
|
s, err := m.OpenService(name)
|
|
if err != nil {
|
|
return fmt.Errorf("could not access service: %v", err)
|
|
}
|
|
defer s.Close()
|
|
status, err := s.Control(c)
|
|
if err != nil {
|
|
return fmt.Errorf("could not send control=%d: %v", c, err)
|
|
}
|
|
timeout := time.Now().Add(10 * time.Second)
|
|
for status.State != to {
|
|
if timeout.Before(time.Now()) {
|
|
return fmt.Errorf("timeout waiting for service to go to state=%d", to)
|
|
}
|
|
time.Sleep(300 * time.Millisecond)
|
|
status, err = s.Query()
|
|
if err != nil {
|
|
return fmt.Errorf("could not retrieve service status: %v", err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|