| 1 |
// Copyright 2012-2018 The NATS Authors |
| 2 |
// Licensed under the Apache License, Version 2.0 (the "License"); |
| 3 |
// you may not use this file except in compliance with the License. |
| 4 |
// You may obtain a copy of the License at |
| 5 |
|
| 6 |
// http://www.apache.org/licenses/LICENSE-2.0 |
| 7 |
|
| 8 |
// Unless required by applicable law or agreed to in writing, software |
| 9 |
// distributed under the License is distributed on an "AS IS" BASIS, |
| 10 |
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 11 |
// See the License for the specific language governing permissions and |
| 12 |
// limitations under the License. |
| 13 |
|
| 14 |
package server |
| 15 |
|
| 16 |
import ( |
| 17 |
|
| 18 |
|
| 19 |
|
| 20 |
" golang.org/x/sys/windows/svc " |
| 21 |
" golang.org/x/sys/windows/svc/debug " |
| 22 |
) |
| 23 |
|
| 24 |
const ( |
| 25 |
serviceName = |
| 26 |
reopenLogCode = 128 |
| 27 |
reopenLogCmd = svc. Cmd (reopenLogCode) |
| 28 |
acceptReopenLog = svc. Accepted (reopenLogCode) |
| 29 |
) |
| 30 |
|
| 31 |
// winServiceWrapper implements the svc.Handler interface for implementing |
| 32 |
// gnatsd as a Windows service. |
| 33 |
type winServiceWrapper struct { |
| 34 |
server *Server |
| 35 |
} |
| 36 |
|
| 37 |
var dockerized = false |
| 38 |
|
| 39 |
func init () { |
| 40 |
if v , exists := os.LookupEnv (); exists && v == { |
| 41 |
dockerized = true |
| 42 |
} |
| 43 |
} |
| 44 |
|
| 45 |
// Execute will be called by the package code at the start of |
| 46 |
// the service, and the service will exit once Execute completes. |
| 47 |
// Inside Execute you must read service change requests from r and |
| 48 |
// act accordingly. You must keep service control manager up to date |
| 49 |
// about state of your service by writing into s as required. |
| 50 |
// args contains service name followed by argument strings passed |
| 51 |
|
| 52 |
// You can provide service exit code in exitCode return parameter, |
| 53 |
// with 0 being "no error". You can also indicate if exit code, |
| 54 |
// if any, is service specific or not by using svcSpecificEC |
| 55 |
|
| 56 |
func (w *winServiceWrapper ) Execute (args []string, changes <-chan svc.ChangeRequest, |
| 57 |
status chan<- svc.Status) (bool, uint32) { |
| 58 |
|
| 59 |
status <- svc.Status {State: svc.StartPending } |
| 60 |
go w.server .Start () |
| 61 |
|
| 62 |
// Wait for accept loop(s) to be started |
| 63 |
if !w.server .ReadyForConnections (10 * time.Second ) { |
| 64 |
|
| 65 |
return false , 1 |
| 66 |
} |
| 67 |
|
| 68 |
status <- svc.Status { |
| 69 |
State: svc. Running , |
| 70 |
Accepts: svc. AcceptStop | svc.AcceptShutdown | svc.AcceptParamChange | acceptReopenLog, |
| 71 |
} |
| 72 |
|
| 73 |
loop: |
| 74 |
for change := range changes { |
| 75 |
switch change.Cmd { |
| 76 |
case svc.Interrogate : |
| 77 |
status <- change.CurrentStatus |
| 78 |
case svc.Stop , svc.Shutdown : |
| 79 |
w. server .Shutdown () |
| 80 |
break loop |
| 81 |
case reopenLogCmd: |
| 82 |
// File log re-open for rotating file logs. |
| 83 |
w. server .ReOpenLogFile () |
| 84 |
case svc.ParamChange : |
| 85 |
if err := w.server .Reload (); err != nil { |
| 86 |
w. server .Errorf (" Failed to reload server configuration: %s " , err) |
| 87 |
} |
| 88 |
default : |
| 89 |
w. server .Debugf (" Unexpected control request: %v " , change.Cmd ) |
| 90 |
} |
| 91 |
} |
| 92 |
|
| 93 |
status <- svc.Status {State: svc.StopPending } |
| 94 |
return false , 0 |
| 95 |
} |
| 96 |
|
| 97 |
// Run starts the NATS server as a Windows service. |
| 98 |
func Run (server *Server ) error { |
| 99 |
if dockerized { |
| 100 |
server. Start () |
| 101 |
return nil |
| 102 |
} |
| 103 |
run := svc.Run |
| 104 |
isInteractive , err := svc.IsAnInteractiveSession () |
| 105 |
if err != nil { |
| 106 |
return err |
| 107 |
} |
| 108 |
if isInteractive { |
| 109 |
run = debug. Run |
| 110 |
} |
| 111 |
return run (serviceName, &winServiceWrapper{server}) |
| 112 |
} |
| 113 |
|
| 114 |
// isWindowsService indicates if NATS is running as a Windows service. |
| 115 |
func isWindowsService () bool { |
| 116 |
if dockerized { |
| 117 |
return false |
| 118 |
} |
| 119 |
isInteractive , _ := svc.IsAnInteractiveSession () |
| 120 |
return !isInteractive |
| 121 |
} |