mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-05-20 13:56:45 +00:00

* Add windows to the CI * Cast syscall.Stdin into an integer * DataDir -> AppDir in service_windows.go * Rename mempool-limits package to something non-main * Close database after re-assigining to it * Up rpcTimout to 10 seconds
120 lines
3.3 KiB
Go
120 lines
3.3 KiB
Go
// Copyright (c) 2013-2016 The btcsuite developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package winservice
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/btcsuite/winsvc/eventlog"
|
|
"github.com/btcsuite/winsvc/svc"
|
|
"github.com/kaspanet/kaspad/infrastructure/config"
|
|
"github.com/kaspanet/kaspad/infrastructure/os/signal"
|
|
"github.com/kaspanet/kaspad/version"
|
|
)
|
|
|
|
// Service houses the main service handler which handles all service
|
|
// updates and launching the application's main.
|
|
type Service struct {
|
|
main MainFunc
|
|
description *ServiceDescription
|
|
cfg *config.Config
|
|
eventLog *eventlog.Log
|
|
}
|
|
|
|
func newService(main MainFunc, description *ServiceDescription, cfg *config.Config) *Service {
|
|
return &Service{
|
|
main: main,
|
|
description: description,
|
|
cfg: cfg,
|
|
}
|
|
}
|
|
|
|
// Start starts the srevice
|
|
func (s *Service) Start() error {
|
|
elog, err := eventlog.Open(s.description.Name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
s.eventLog = elog
|
|
defer s.eventLog.Close()
|
|
|
|
err = svc.Run(s.description.Name, &Service{})
|
|
if err != nil {
|
|
s.eventLog.Error(1, fmt.Sprintf("Service start failed: %s", err))
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Execute is the main entry point the winsvc package calls when receiving
|
|
// information from the Windows service control manager. It launches the
|
|
// long-running kaspadMain (which is the real meat of kaspad), handles service
|
|
// change requests, and notifies the service control manager of changes.
|
|
func (s *Service) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (bool, uint32) {
|
|
// Service start is pending.
|
|
const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown
|
|
changes <- svc.Status{State: svc.StartPending}
|
|
|
|
// Start kaspadMain in a separate goroutine so the service can start
|
|
// quickly. Shutdown (along with a potential error) is reported via
|
|
// doneChan. startedChan is notified once kaspad is started so this can
|
|
// be properly logged
|
|
doneChan := make(chan error)
|
|
startedChan := make(chan struct{})
|
|
spawn("kaspadMain-windows", func() {
|
|
err := s.main(startedChan)
|
|
doneChan <- err
|
|
})
|
|
|
|
// Service is now started.
|
|
changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
|
|
loop:
|
|
for {
|
|
select {
|
|
case c := <-r:
|
|
switch c.Cmd {
|
|
case svc.Interrogate:
|
|
changes <- c.CurrentStatus
|
|
|
|
case svc.Stop, svc.Shutdown:
|
|
// Service stop is pending. Don't accept any
|
|
// more commands while pending.
|
|
changes <- svc.Status{State: svc.StopPending}
|
|
|
|
// Signal the main function to exit.
|
|
signal.ShutdownRequestChannel <- struct{}{}
|
|
|
|
default:
|
|
s.eventLog.Error(1, fmt.Sprintf("Unexpected control "+
|
|
"request #%d.", c))
|
|
}
|
|
|
|
case <-startedChan:
|
|
s.logServiceStart()
|
|
|
|
case err := <-doneChan:
|
|
if err != nil {
|
|
s.eventLog.Error(1, err.Error())
|
|
}
|
|
break loop
|
|
}
|
|
}
|
|
|
|
// Service is now stopped.
|
|
changes <- svc.Status{State: svc.Stopped}
|
|
return false, 0
|
|
}
|
|
|
|
// logServiceStart logs information about kaspad when the main server has
|
|
// been started to the Windows event log.
|
|
func (s *Service) logServiceStart() {
|
|
var message string
|
|
message += fmt.Sprintf("%s version %s\n", s.description.DisplayName, version.Version())
|
|
message += fmt.Sprintf("Configuration file: %s\n", s.cfg.ConfigFile)
|
|
message += fmt.Sprintf("Application directory: %s\n", s.cfg.AppDir)
|
|
message += fmt.Sprintf("Logs directory: %s\n", s.cfg.LogDir)
|
|
}
|