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 |
} |