···11-// Copyright 2019 The Gitea Authors. All rights reserved.
22-// SPDX-License-Identifier: MIT
33-// This code is heavily inspired by the archived gofacebook/gracenet/net.go handler
44-55-//go:build windows
66-77-package graceful
88-99-import (
1010- "os"
1111- "runtime/pprof"
1212- "strconv"
1313- "time"
1414-1515- "code.gitea.io/gitea/modules/log"
1616- "code.gitea.io/gitea/modules/setting"
1717-1818- "golang.org/x/sys/windows/svc"
1919- "golang.org/x/sys/windows/svc/debug"
2020-)
2121-2222-// WindowsServiceName is the name of the Windows service
2323-var WindowsServiceName = "gitea"
2424-2525-const (
2626- hammerCode = 128
2727- hammerCmd = svc.Cmd(hammerCode)
2828- acceptHammerCode = svc.Accepted(hammerCode)
2929-)
3030-3131-func (g *Manager) start() {
3232- // Now label this and all goroutines created by this goroutine with the gracefulLifecycle manager
3333- pprof.SetGoroutineLabels(g.managerCtx)
3434- defer pprof.SetGoroutineLabels(g.ctx)
3535-3636- if skip, _ := strconv.ParseBool(os.Getenv("SKIP_MINWINSVC")); skip {
3737- log.Trace("Skipping SVC check as SKIP_MINWINSVC is set")
3838- return
3939- }
4040-4141- // Make SVC process
4242- run := svc.Run
4343-4444- //lint:ignore SA1019 We use IsAnInteractiveSession because IsWindowsService has a different permissions profile
4545- isAnInteractiveSession, err := svc.IsAnInteractiveSession() //nolint:staticcheck
4646- if err != nil {
4747- log.Error("Unable to ascertain if running as an Windows Service: %v", err)
4848- return
4949- }
5050- if isAnInteractiveSession {
5151- log.Trace("Not running a service ... using the debug SVC manager")
5252- run = debug.Run
5353- }
5454- go func() {
5555- _ = run(WindowsServiceName, g)
5656- }()
5757-}
5858-5959-// Execute makes Manager implement svc.Handler
6060-func (g *Manager) Execute(args []string, changes <-chan svc.ChangeRequest, status chan<- svc.Status) (svcSpecificEC bool, exitCode uint32) {
6161- if setting.StartupTimeout > 0 {
6262- status <- svc.Status{State: svc.StartPending, WaitHint: uint32(setting.StartupTimeout / time.Millisecond)}
6363- } else {
6464- status <- svc.Status{State: svc.StartPending}
6565- }
6666-6767- log.Trace("Awaiting server start-up")
6868- // Now need to wait for everything to start...
6969- if !g.awaitServer(setting.StartupTimeout) {
7070- log.Trace("... start-up failed ... Stopped")
7171- return false, 1
7272- }
7373-7474- log.Trace("Sending Running state to SVC")
7575-7676- // We need to implement some way of svc.AcceptParamChange/svc.ParamChange
7777- status <- svc.Status{
7878- State: svc.Running,
7979- Accepts: svc.AcceptStop | svc.AcceptShutdown | acceptHammerCode,
8080- }
8181-8282- log.Trace("Started")
8383-8484- waitTime := 30 * time.Second
8585-8686-loop:
8787- for {
8888- select {
8989- case <-g.ctx.Done():
9090- log.Trace("Shutting down")
9191- g.DoGracefulShutdown()
9292- waitTime += setting.GracefulHammerTime
9393- break loop
9494- case <-g.shutdownRequested:
9595- log.Trace("Shutting down")
9696- waitTime += setting.GracefulHammerTime
9797- break loop
9898- case change := <-changes:
9999- switch change.Cmd {
100100- case svc.Interrogate:
101101- log.Trace("SVC sent interrogate")
102102- status <- change.CurrentStatus
103103- case svc.Stop, svc.Shutdown:
104104- log.Trace("SVC requested shutdown - shutting down")
105105- g.DoGracefulShutdown()
106106- waitTime += setting.GracefulHammerTime
107107- break loop
108108- case hammerCode:
109109- log.Trace("SVC requested hammer - shutting down and hammering immediately")
110110- g.DoGracefulShutdown()
111111- g.DoImmediateHammer()
112112- break loop
113113- default:
114114- log.Debug("Unexpected control request: %v", change.Cmd)
115115- }
116116- }
117117- }
118118-119119- log.Trace("Sending StopPending state to SVC")
120120- status <- svc.Status{
121121- State: svc.StopPending,
122122- WaitHint: uint32(waitTime / time.Millisecond),
123123- }
124124-125125-hammerLoop:
126126- for {
127127- select {
128128- case change := <-changes:
129129- switch change.Cmd {
130130- case svc.Interrogate:
131131- log.Trace("SVC sent interrogate")
132132- status <- change.CurrentStatus
133133- case svc.Stop, svc.Shutdown, hammerCmd:
134134- log.Trace("SVC requested hammer - hammering immediately")
135135- g.DoImmediateHammer()
136136- break hammerLoop
137137- default:
138138- log.Debug("Unexpected control request: %v", change.Cmd)
139139- }
140140- case <-g.hammerCtx.Done():
141141- break hammerLoop
142142- }
143143- }
144144-145145- log.Trace("Stopped")
146146- return false, 0
147147-}
148148-149149-func (g *Manager) awaitServer(limit time.Duration) bool {
150150- c := make(chan struct{})
151151- go func() {
152152- g.createServerCond.L.Lock()
153153- for {
154154- if g.createdServer >= numberOfServersToCreate {
155155- g.createServerCond.L.Unlock()
156156- close(c)
157157- return
158158- }
159159- select {
160160- case <-g.IsShutdown():
161161- g.createServerCond.L.Unlock()
162162- return
163163- default:
164164- }
165165- g.createServerCond.Wait()
166166- }
167167- }()
168168-169169- var tc <-chan time.Time
170170- if limit > 0 {
171171- tc = time.After(limit)
172172- }
173173- select {
174174- case <-c:
175175- return true // completed normally
176176- case <-tc:
177177- return false // timed out
178178- case <-g.IsShutdown():
179179- g.createServerCond.Signal()
180180- return false
181181- }
182182-}
183183-184184-func (g *Manager) notify(msg systemdNotifyMsg) {
185185- // Windows doesn't use systemd to notify
186186-}
187187-188188-func KillParent() {
189189- // Windows doesn't need to "kill parent" because there is no graceful restart
190190-}
-19
modules/graceful/net_windows.go
···11-// Copyright 2019 The Gitea Authors. All rights reserved.
22-// SPDX-License-Identifier: MIT
33-44-// This code is heavily inspired by the archived gofacebook/gracenet/net.go handler
55-66-//go:build windows
77-88-package graceful
99-1010-import "net"
1111-1212-// DefaultGetListener obtains a listener for the local network address.
1313-// On windows this is basically just a shim around net.Listen.
1414-func DefaultGetListener(network, address string) (net.Listener, error) {
1515- // Add a deferral to say that we've tried to grab a listener
1616- defer GetManager().InformCleanup()
1717-1818- return net.Listen(network, address)
1919-}
-15
modules/process/manager_windows.go
···11-// Copyright 2022 The Gitea Authors. All rights reserved.
22-// SPDX-License-Identifier: MIT
33-44-//go:build windows
55-66-package process
77-88-import (
99- "os/exec"
1010-)
1111-1212-// SetSysProcAttribute sets the common SysProcAttrs for commands
1313-func SetSysProcAttribute(cmd *exec.Cmd) {
1414- // Do nothing
1515-}
-15
modules/util/file_windows.go
···11-// Copyright 2022 The Gitea Authors. All rights reserved.
22-// SPDX-License-Identifier: MIT
33-44-//go:build windows
55-66-package util
77-88-import (
99- "os"
1010-)
1111-1212-func ApplyUmask(f string, newMode os.FileMode) error {
1313- // do nothing for Windows, because Windows doesn't use umask
1414- return nil
1515-}
-27
routers/private/manager_windows.go
···11-// Copyright 2020 The Gitea Authors. All rights reserved.
22-// SPDX-License-Identifier: MIT
33-44-//go:build windows
55-66-package private
77-88-import (
99- "net/http"
1010-1111- "code.gitea.io/gitea/modules/graceful"
1212- "code.gitea.io/gitea/modules/private"
1313- "code.gitea.io/gitea/services/context"
1414-)
1515-1616-// Restart is not implemented for Windows based servers as they can't fork
1717-func Restart(ctx *context.PrivateContext) {
1818- ctx.JSON(http.StatusNotImplemented, private.Response{
1919- UserMsg: "windows servers cannot be gracefully restarted - shutdown and restart manually",
2020- })
2121-}
2222-2323-// Shutdown causes the server to perform a graceful shutdown
2424-func Shutdown(ctx *context.PrivateContext) {
2525- graceful.GetManager().DoGracefulShutdown()
2626- ctx.PlainText(http.StatusOK, "success")
2727-}
-19
services/auth/sspiauth_windows.go
···11-// Copyright 2023 The Gitea Authors. All rights reserved.
22-// SPDX-License-Identifier: MIT
33-44-//go:build windows
55-66-package auth
77-88-import (
99- "github.com/quasoft/websspi"
1010-)
1111-1212-type SSPIUserInfo = websspi.UserInfo
1313-1414-func sspiAuthInit() error {
1515- var err error
1616- config := websspi.NewConfig()
1717- sspiAuth, err = websspi.New(config)
1818- return err
1919-}