Files
gf/net/ghttp/ghttp_server.go

704 lines
19 KiB
Go
Raw Normal View History

// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
2017-12-29 16:03:30 +08:00
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
2017-12-29 16:03:30 +08:00
2017-11-23 10:21:28 +08:00
package ghttp
import (
2019-06-19 09:06:52 +08:00
"bytes"
"context"
"fmt"
"net/http"
"os"
"runtime"
"strings"
"sync"
"time"
"github.com/olekukonko/tablewriter"
"github.com/olekukonko/tablewriter/renderer"
"github.com/olekukonko/tablewriter/tw"
2021-10-11 21:41:56 +08:00
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/container/gset"
2021-10-11 21:41:56 +08:00
"github.com/gogf/gf/v2/container/gtype"
2021-11-13 23:23:55 +08:00
"github.com/gogf/gf/v2/debug/gdebug"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/internal/intlog"
"github.com/gogf/gf/v2/net/ghttp/internal/graceful"
2022-03-19 17:58:21 +08:00
"github.com/gogf/gf/v2/net/ghttp/internal/swaggerui"
2022-05-24 18:53:10 +08:00
"github.com/gogf/gf/v2/net/goai"
2023-03-08 14:12:51 +08:00
"github.com/gogf/gf/v2/net/gsvc"
2021-10-11 21:41:56 +08:00
"github.com/gogf/gf/v2/os/gcache"
2023-03-08 14:12:51 +08:00
"github.com/gogf/gf/v2/os/gctx"
2021-10-11 21:41:56 +08:00
"github.com/gogf/gf/v2/os/genv"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/os/gproc"
2021-11-13 23:23:55 +08:00
"github.com/gogf/gf/v2/os/gsession"
2021-10-11 21:41:56 +08:00
"github.com/gogf/gf/v2/os/gtimer"
"github.com/gogf/gf/v2/text/gregex"
2021-11-13 23:23:55 +08:00
"github.com/gogf/gf/v2/text/gstr"
2021-10-11 21:41:56 +08:00
"github.com/gogf/gf/v2/util/gconv"
2017-11-23 10:21:28 +08:00
)
func init() {
2022-03-19 17:58:21 +08:00
// Initialize the method map.
for _, v := range strings.Split(supportedHttpMethods, ",") {
2019-06-19 09:06:52 +08:00
methodsMap[v] = struct{}{}
}
}
// serverProcessInit initializes some process configurations, which can only be done once.
2019-02-20 16:07:11 +08:00
func serverProcessInit() {
var ctx = context.TODO()
if !serverProcessInitialized.Cas(false, true) {
2019-06-19 09:06:52 +08:00
return
}
2022-03-19 17:58:21 +08:00
// This means it is a restart server. It should kill its parent before starting its listening,
// to avoid duplicated port listening in two processes.
if !genv.Get(adminActionRestartEnvKey).IsEmpty() {
if p, err := os.FindProcess(gproc.PPid()); err == nil {
if err = p.Kill(); err != nil {
intlog.Errorf(ctx, `%+v`, err)
}
if _, err = p.Wait(); err != nil {
intlog.Errorf(ctx, `%+v`, err)
}
2019-06-19 09:06:52 +08:00
} else {
glog.Error(ctx, err)
2019-06-19 09:06:52 +08:00
}
}
// Process message handler.
2022-03-19 17:58:21 +08:00
// It enabled only a graceful feature is enabled.
2019-06-19 09:06:52 +08:00
if gracefulEnabled {
intlog.Printf(ctx, "pid[%d]: graceful reload feature is enabled", gproc.Pid())
2019-06-19 09:06:52 +08:00
go handleProcessMessage()
} else {
intlog.Printf(ctx, "pid[%d]: graceful reload feature is disabled", gproc.Pid())
2019-06-19 09:06:52 +08:00
}
// It's an ugly calling for better initializing the main package path
// in source development environment. It is useful only be used in main goroutine.
2022-03-19 17:58:21 +08:00
// It fails to retrieve the main package path in asynchronous goroutines.
2019-06-19 09:06:52 +08:00
gfile.MainPkgPath()
2018-05-10 23:52:09 +08:00
}
// GetServer creates and returns a server instance using given name and default configurations.
// Note that the parameter `name` should be unique for different servers. It returns an existing
// server instance if given `name` is already existing in the server mapping.
refactor: interface{} to any and reflect.Ptr to reflect.Pointer (#4395) This pull request standardizes the use of the Go 1.18+ `any` type alias instead of `interface{}` throughout the codebase. The change improves code readability and aligns with modern Go best practices. The update touches many files, including core data structures, code generation templates, logging utilities, and test data, ensuring consistency across all usages. **Type alias migration to `any`:** * Replaced all instances of `interface{}` with `any` in core data structures such as `garray` and in generated model structs (e.g., `TableUser`, `User1`, `User2`) to modernize type usage. [[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31) [[2]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19) [[3]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18) [[4]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19) [[5]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19) [[6]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19) * Updated function signatures, method parameters, and return types from `interface{}` to `any` in various parts of the codebase, including code generation, service logic, and logging utilities (e.g., `mlog`). [[1]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55) [[2]](diffhunk://#diff-2b1953fb78cf3593d8c2c7d911e95b65fd0b847c30ed0b4d167d16fe6d781235L54-R74) [[3]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73) [[4]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41) [[5]](diffhunk://#diff-c5d51d56f487779a2b6207c7ad26c7a20bbadcc846ce094fe60ab4cabff58c51L107-R107) [[6]](diffhunk://#diff-f96e6a9fdb416eb1804ceaba1fe0ac637bff22c43837f8bb849c2366ce72d4a1L116-R121) [[7]](diffhunk://#diff-f94c83a1b08ae060d9346f4a6031fc4a7b9a0b894e02d9afaa09018b6598eac0L112-R112) [[8]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L36-R36) [[9]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L74-R74) [[10]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L96-R96) **Generated code and templates:** * Adjusted generated files and code generation templates to output `any` instead of `interface{}` for relevant struct fields and function signatures, ensuring that new code generation aligns with the updated convention. [[1]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19) [[2]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18) [[3]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19) [[4]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19) [[5]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19) [[6]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55) [[7]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73) [[8]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41) **Container and utility updates:** * Refactored the `garray` container implementation and related constructors/methods to use `[]any` instead of `[]interface{}`, along with corresponding function signatures. [[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31) [[2]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L52-R52) [[3]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L62-R62) [[4]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L73-R86) [[5]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L96-R97) [[6]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L107-R114) [[7]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L124-R124) [[8]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L135-R143) [[9]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L167-R167) These changes collectively modernize the codebase and prepare it for future Go developments by using the idiomatic `any` type.
2025-08-28 16:53:19 +08:00
func GetServer(name ...any) *Server {
serverName := DefaultServerName
2019-07-28 17:37:13 +08:00
if len(name) > 0 && name[0] != "" {
2019-09-04 19:23:19 +08:00
serverName = gconv.String(name[0])
2019-06-19 09:06:52 +08:00
}
refactor: interface{} to any and reflect.Ptr to reflect.Pointer (#4395) This pull request standardizes the use of the Go 1.18+ `any` type alias instead of `interface{}` throughout the codebase. The change improves code readability and aligns with modern Go best practices. The update touches many files, including core data structures, code generation templates, logging utilities, and test data, ensuring consistency across all usages. **Type alias migration to `any`:** * Replaced all instances of `interface{}` with `any` in core data structures such as `garray` and in generated model structs (e.g., `TableUser`, `User1`, `User2`) to modernize type usage. [[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31) [[2]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19) [[3]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18) [[4]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19) [[5]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19) [[6]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19) * Updated function signatures, method parameters, and return types from `interface{}` to `any` in various parts of the codebase, including code generation, service logic, and logging utilities (e.g., `mlog`). [[1]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55) [[2]](diffhunk://#diff-2b1953fb78cf3593d8c2c7d911e95b65fd0b847c30ed0b4d167d16fe6d781235L54-R74) [[3]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73) [[4]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41) [[5]](diffhunk://#diff-c5d51d56f487779a2b6207c7ad26c7a20bbadcc846ce094fe60ab4cabff58c51L107-R107) [[6]](diffhunk://#diff-f96e6a9fdb416eb1804ceaba1fe0ac637bff22c43837f8bb849c2366ce72d4a1L116-R121) [[7]](diffhunk://#diff-f94c83a1b08ae060d9346f4a6031fc4a7b9a0b894e02d9afaa09018b6598eac0L112-R112) [[8]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L36-R36) [[9]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L74-R74) [[10]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L96-R96) **Generated code and templates:** * Adjusted generated files and code generation templates to output `any` instead of `interface{}` for relevant struct fields and function signatures, ensuring that new code generation aligns with the updated convention. [[1]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19) [[2]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18) [[3]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19) [[4]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19) [[5]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19) [[6]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55) [[7]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73) [[8]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41) **Container and utility updates:** * Refactored the `garray` container implementation and related constructors/methods to use `[]any` instead of `[]interface{}`, along with corresponding function signatures. [[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31) [[2]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L52-R52) [[3]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L62-R62) [[4]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L73-R86) [[5]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L96-R97) [[6]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L107-R114) [[7]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L124-R124) [[8]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L135-R143) [[9]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L167-R167) These changes collectively modernize the codebase and prepare it for future Go developments by using the idiomatic `any` type.
2025-08-28 16:53:19 +08:00
v := serverMapping.GetOrSetFuncLock(serverName, func() any {
2023-03-08 14:12:51 +08:00
s := &Server{
instance: serverName,
plugins: make([]Plugin, 0),
servers: make([]*graceful.Server, 0),
2023-03-08 14:12:51 +08:00
closeChan: make(chan struct{}, 10000),
serverCount: gtype.NewInt(),
statusHandlerMap: make(map[string][]HandlerFunc),
refactor: interface{} to any and reflect.Ptr to reflect.Pointer (#4395) This pull request standardizes the use of the Go 1.18+ `any` type alias instead of `interface{}` throughout the codebase. The change improves code readability and aligns with modern Go best practices. The update touches many files, including core data structures, code generation templates, logging utilities, and test data, ensuring consistency across all usages. **Type alias migration to `any`:** * Replaced all instances of `interface{}` with `any` in core data structures such as `garray` and in generated model structs (e.g., `TableUser`, `User1`, `User2`) to modernize type usage. [[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31) [[2]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19) [[3]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18) [[4]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19) [[5]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19) [[6]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19) * Updated function signatures, method parameters, and return types from `interface{}` to `any` in various parts of the codebase, including code generation, service logic, and logging utilities (e.g., `mlog`). [[1]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55) [[2]](diffhunk://#diff-2b1953fb78cf3593d8c2c7d911e95b65fd0b847c30ed0b4d167d16fe6d781235L54-R74) [[3]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73) [[4]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41) [[5]](diffhunk://#diff-c5d51d56f487779a2b6207c7ad26c7a20bbadcc846ce094fe60ab4cabff58c51L107-R107) [[6]](diffhunk://#diff-f96e6a9fdb416eb1804ceaba1fe0ac637bff22c43837f8bb849c2366ce72d4a1L116-R121) [[7]](diffhunk://#diff-f94c83a1b08ae060d9346f4a6031fc4a7b9a0b894e02d9afaa09018b6598eac0L112-R112) [[8]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L36-R36) [[9]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L74-R74) [[10]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L96-R96) **Generated code and templates:** * Adjusted generated files and code generation templates to output `any` instead of `interface{}` for relevant struct fields and function signatures, ensuring that new code generation aligns with the updated convention. [[1]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19) [[2]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18) [[3]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19) [[4]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19) [[5]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19) [[6]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55) [[7]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73) [[8]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41) **Container and utility updates:** * Refactored the `garray` container implementation and related constructors/methods to use `[]any` instead of `[]interface{}`, along with corresponding function signatures. [[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31) [[2]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L52-R52) [[3]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L62-R62) [[4]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L73-R86) [[5]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L96-R97) [[6]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L107-R114) [[7]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L124-R124) [[8]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L135-R143) [[9]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L167-R167) These changes collectively modernize the codebase and prepare it for future Go developments by using the idiomatic `any` type.
2025-08-28 16:53:19 +08:00
serveTree: make(map[string]any),
2023-03-08 14:12:51 +08:00
serveCache: gcache.New(),
routesMap: make(map[string][]*HandlerItem),
openapi: goai.New(),
registrar: gsvc.GetRegistry(),
}
// Initialize the server using default configurations.
if err := s.SetConfig(NewConfig()); err != nil {
panic(gerror.WrapCode(gcode.CodeInvalidConfiguration, err, ""))
}
// It enables OpenTelemetry for server in default.
s.Use(internalMiddlewareServerTracing)
return s
})
return v.(*Server)
2017-12-07 14:57:16 +08:00
}
// Start starts listening on configured port.
// This function does not block the process, you can use function Wait blocking the process.
func (s *Server) Start() error {
2023-03-08 14:12:51 +08:00
var ctx = gctx.GetInitCtx()
2021-09-27 21:27:24 +08:00
// Swagger UI.
if s.config.SwaggerPath != "" {
2021-10-13 22:28:49 +08:00
swaggerui.Init()
s.AddStaticPath(s.config.SwaggerPath, swaggerUIPackedPath)
s.BindHookHandler(s.config.SwaggerPath+"/*", HookBeforeServe, s.swaggerUI)
}
// OpenApi specification json producing handler.
if s.config.OpenApiPath != "" {
s.BindHandler(s.config.OpenApiPath, s.openapiSpec)
}
// Register group routes.
2021-09-27 21:27:24 +08:00
s.handlePreBindItems(ctx)
// Server process initialization, which can only be initialized once.
2019-06-19 09:06:52 +08:00
serverProcessInit()
// Server can only be run once.
2020-12-14 13:26:48 +08:00
if s.Status() == ServerStatusRunning {
return gerror.NewCode(gcode.CodeInvalidOperation, "server is already running")
2019-06-19 09:06:52 +08:00
}
// Logging path setting check.
if s.config.LogPath != "" && s.config.LogPath != s.config.Logger.GetPath() {
if err := s.config.Logger.SetPath(s.config.LogPath); err != nil {
return err
}
2019-06-19 09:06:52 +08:00
}
// Default session storage.
if s.config.SessionStorage == nil {
sessionStoragePath := ""
if s.config.SessionPath != "" {
sessionStoragePath = gfile.Join(s.config.SessionPath, s.config.Name)
if !gfile.Exists(sessionStoragePath) {
if err := gfile.Mkdir(sessionStoragePath); err != nil {
return gerror.Wrapf(err, `mkdir failed for "%s"`, sessionStoragePath)
}
}
}
s.config.SessionStorage = gsession.NewStorageFile(sessionStoragePath, s.config.SessionMaxAge)
}
// Initialize session manager when start running.
s.sessionManager = gsession.New(
s.config.SessionMaxAge,
s.config.SessionStorage,
)
// PProf feature.
if s.config.PProfEnabled {
s.EnablePProf(s.config.PProfPattern)
}
// Default HTTP handler.
2019-06-19 09:06:52 +08:00
if s.config.Handler == nil {
s.config.Handler = s.ServeHTTP
2019-06-19 09:06:52 +08:00
}
// Install external plugins.
for _, p := range s.plugins {
if err := p.Install(s); err != nil {
s.Logger().Fatalf(ctx, `%+v`, err)
}
}
// Check the group routes again for internally registered routes.
2021-09-27 21:27:24 +08:00
s.handlePreBindItems(ctx)
2022-03-19 17:58:21 +08:00
// If there's no route registered and no static service enabled,
// it then returns an error of invalid usage of server.
if len(s.routesMap) == 0 && !s.config.FileServerEnabled {
2021-07-20 23:02:02 +08:00
return gerror.NewCode(
gcode.CodeInvalidOperation,
2021-07-20 23:02:02 +08:00
`there's no route set or static feature enabled, did you forget import the router?`,
)
}
// ================================================================================================
// Start the HTTP server.
// ================================================================================================
2019-06-19 09:06:52 +08:00
reloaded := false
fdMapStr := genv.Get(adminActionReloadEnvKey).String()
2019-06-19 09:06:52 +08:00
if len(fdMapStr) > 0 {
sfm := bufferToServerFdMap([]byte(fdMapStr))
if v, ok := sfm[s.config.Name]; ok {
2019-06-19 09:06:52 +08:00
s.startServer(v)
reloaded = true
}
}
if !reloaded {
s.startServer(nil)
}
// Swagger UI info.
if s.config.SwaggerPath != "" {
s.Logger().Infof(
ctx,
`swagger ui is serving at address: %s%s/`,
s.getLocalListenedAddress(),
s.config.SwaggerPath,
)
}
// OpenApi specification info.
if s.config.OpenApiPath != "" {
s.Logger().Infof(
ctx,
`openapi specification is serving at address: %s%s`,
s.getLocalListenedAddress(),
s.config.OpenApiPath,
)
} else {
if s.config.SwaggerPath != "" {
s.Logger().Warning(
ctx,
`openapi specification is disabled but swagger ui is serving, which might make no sense`,
)
} else {
s.Logger().Info(
ctx,
`openapi specification is disabled`,
)
}
}
// If this is a child process, it then notifies its parent exit.
2019-06-19 09:06:52 +08:00
if gproc.IsChild() {
var gracefulTimeout = time.Duration(s.config.GracefulTimeout) * time.Second
gtimer.SetTimeout(ctx, gracefulTimeout, func(ctx context.Context) {
intlog.Printf(
ctx,
`pid[%d]: notice parent server graceful shuttingdown, ppid: %d`,
gproc.Pid(), gproc.PPid(),
)
2020-12-15 20:16:17 +08:00
if err := gproc.Send(gproc.PPid(), []byte("exit"), adminGProcCommGroup); err != nil {
intlog.Errorf(ctx, `server error in process communication: %+v`, err)
2019-06-19 09:06:52 +08:00
}
})
}
s.initOpenApi()
s.doServiceRegister()
s.doRouterMapDump()
2019-06-19 09:06:52 +08:00
return nil
}
func (s *Server) getLocalListenedAddress() string {
return fmt.Sprintf(`http://127.0.0.1:%d`, s.GetListenedPort())
}
// doRouterMapDump checks and dumps the router map to the log.
func (s *Server) doRouterMapDump() {
if !s.config.DumpRouterMap {
return
}
2021-09-27 21:27:24 +08:00
var (
2021-12-18 12:36:34 +08:00
ctx = context.TODO()
routes = s.GetRoutes()
2021-12-18 12:36:34 +08:00
isJustDefaultServerAndDomain = true
headers = []string{
"SERVER", "DOMAIN", "ADDRESS", "METHOD", "ROUTE", "HANDLER", "MIDDLEWARE",
}
2021-09-27 21:27:24 +08:00
)
for _, item := range routes {
2021-12-18 12:36:34 +08:00
if item.Server != DefaultServerName || item.Domain != DefaultDomainName {
isJustDefaultServerAndDomain = false
break
}
}
if isJustDefaultServerAndDomain {
headers = []string{"ADDRESS", "METHOD", "ROUTE", "HANDLER", "MIDDLEWARE"}
}
if len(routes) > 0 {
buffer := bytes.NewBuffer(nil)
table := tablewriter.NewTable(buffer,
tablewriter.WithRenderer(renderer.NewBlueprint(
tw.Rendition{
Settings: tw.Settings{
Separators: tw.Separators{BetweenRows: tw.On},
},
Symbols: tw.NewSymbolCustom("HTTP").WithCenter("|"),
})),
)
table.Header(headers)
2018-10-17 16:56:50 +08:00
for _, item := range routes {
var (
data = make([]string, 0)
handlerName = gstr.TrimRightStr(item.Handler.Name, "-fm")
middlewares = gstr.SplitAndTrim(item.Middleware, ",")
)
// No printing special internal middleware that may lead confused.
if gstr.SubStrFromREx(handlerName, ".") == noPrintInternalRoute {
continue
}
for k, v := range middlewares {
middlewares[k] = gstr.TrimRightStr(v, "-fm")
}
item.Middleware = gstr.Join(middlewares, "\n")
2021-12-18 12:36:34 +08:00
if isJustDefaultServerAndDomain {
data = append(
data,
item.Address,
item.Method,
item.Route,
handlerName,
2021-12-18 12:36:34 +08:00
item.Middleware,
)
} else {
data = append(
data,
item.Server,
item.Domain,
item.Address,
item.Method,
item.Route,
handlerName,
2021-12-18 12:36:34 +08:00
item.Middleware,
)
}
2025-09-01 15:33:50 +08:00
_ = table.Append(data)
}
2025-09-01 15:33:50 +08:00
_ = table.Render()
2021-09-27 21:27:24 +08:00
s.config.Logger.Header(false).Printf(ctx, "\n%s", buffer.String())
2019-06-19 09:06:52 +08:00
}
}
2019-06-19 09:06:52 +08:00
// GetOpenApi returns the OpenApi specification management object of the current server.
func (s *Server) GetOpenApi() *goai.OpenApiV3 {
return s.openapi
}
// GetRoutes retrieves and returns the router array.
func (s *Server) GetRoutes() []RouterItem {
var (
m = make(map[string]*garray.SortedArray)
routeFilterSet = gset.NewStrSet()
address = s.GetListenedAddress()
)
if s.config.HTTPSAddr != "" {
if len(address) > 0 {
address += ","
}
address += "tls" + s.config.HTTPSAddr
}
2022-05-06 20:25:21 +08:00
for k, handlerItems := range s.routesMap {
2019-06-19 09:06:52 +08:00
array, _ := gregex.MatchString(`(.*?)%([A-Z]+):(.+)@(.+)`, k)
for index := len(handlerItems) - 1; index >= 0; index-- {
var (
handlerItem = handlerItems[index]
item = RouterItem{
Server: s.config.Name,
Address: address,
Domain: array[4],
Type: handlerItem.Type,
Middleware: array[1],
Method: array[2],
Route: array[3],
Priority: index,
Handler: handlerItem,
}
)
switch item.Handler.Type {
case HandlerTypeObject, HandlerTypeHandler:
item.IsServiceHandler = true
case HandlerTypeMiddleware:
item.Middleware = "GLOBAL MIDDLEWARE"
}
// Repeated route filtering for dump.
var setKey = fmt.Sprintf(
`%s|%s|%s|%s`,
item.Method, item.Route, item.Domain, item.Type,
)
if !routeFilterSet.AddIfNotExist(setKey) {
continue
}
if len(item.Handler.Middleware) > 0 {
for _, v := range item.Handler.Middleware {
if item.Middleware != "" {
2021-05-02 08:10:35 +08:00
item.Middleware += ","
}
item.Middleware += gdebug.FuncName(v)
}
2019-06-19 09:06:52 +08:00
}
2021-05-01 09:04:16 +08:00
// If the domain does not exist in the dump map, it creates the map.
// The value of the map is a custom sorted array.
if _, ok := m[item.Domain]; !ok {
// Sort in ASC order.
refactor: interface{} to any and reflect.Ptr to reflect.Pointer (#4395) This pull request standardizes the use of the Go 1.18+ `any` type alias instead of `interface{}` throughout the codebase. The change improves code readability and aligns with modern Go best practices. The update touches many files, including core data structures, code generation templates, logging utilities, and test data, ensuring consistency across all usages. **Type alias migration to `any`:** * Replaced all instances of `interface{}` with `any` in core data structures such as `garray` and in generated model structs (e.g., `TableUser`, `User1`, `User2`) to modernize type usage. [[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31) [[2]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19) [[3]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18) [[4]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19) [[5]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19) [[6]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19) * Updated function signatures, method parameters, and return types from `interface{}` to `any` in various parts of the codebase, including code generation, service logic, and logging utilities (e.g., `mlog`). [[1]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55) [[2]](diffhunk://#diff-2b1953fb78cf3593d8c2c7d911e95b65fd0b847c30ed0b4d167d16fe6d781235L54-R74) [[3]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73) [[4]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41) [[5]](diffhunk://#diff-c5d51d56f487779a2b6207c7ad26c7a20bbadcc846ce094fe60ab4cabff58c51L107-R107) [[6]](diffhunk://#diff-f96e6a9fdb416eb1804ceaba1fe0ac637bff22c43837f8bb849c2366ce72d4a1L116-R121) [[7]](diffhunk://#diff-f94c83a1b08ae060d9346f4a6031fc4a7b9a0b894e02d9afaa09018b6598eac0L112-R112) [[8]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L36-R36) [[9]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L74-R74) [[10]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L96-R96) **Generated code and templates:** * Adjusted generated files and code generation templates to output `any` instead of `interface{}` for relevant struct fields and function signatures, ensuring that new code generation aligns with the updated convention. [[1]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19) [[2]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18) [[3]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19) [[4]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19) [[5]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19) [[6]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55) [[7]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73) [[8]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41) **Container and utility updates:** * Refactored the `garray` container implementation and related constructors/methods to use `[]any` instead of `[]interface{}`, along with corresponding function signatures. [[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31) [[2]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L52-R52) [[3]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L62-R62) [[4]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L73-R86) [[5]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L96-R97) [[6]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L107-R114) [[7]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L124-R124) [[8]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L135-R143) [[9]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L167-R167) These changes collectively modernize the codebase and prepare it for future Go developments by using the idiomatic `any` type.
2025-08-28 16:53:19 +08:00
m[item.Domain] = garray.NewSortedArray(func(v1, v2 any) int {
item1 := v1.(RouterItem)
item2 := v2.(RouterItem)
2019-06-19 09:06:52 +08:00
r := 0
if r = strings.Compare(item1.Domain, item2.Domain); r == 0 {
if r = strings.Compare(item1.Route, item2.Route); r == 0 {
if r = strings.Compare(item1.Method, item2.Method); r == 0 {
if item1.Handler.Type == HandlerTypeMiddleware && item2.Handler.Type != HandlerTypeMiddleware {
return -1
} else if item1.Handler.Type == HandlerTypeMiddleware && item2.Handler.Type == HandlerTypeMiddleware {
return 1
} else if r = strings.Compare(item1.Middleware, item2.Middleware); r == 0 {
r = item2.Priority - item1.Priority
2019-06-19 09:06:52 +08:00
}
}
}
}
return r
})
2019-06-19 09:06:52 +08:00
}
m[item.Domain].Add(item)
2019-06-19 09:06:52 +08:00
}
}
routerArray := make([]RouterItem, 0, 128)
for _, array := range m {
for _, v := range array.Slice() {
routerArray = append(routerArray, v.(RouterItem))
2019-06-19 09:06:52 +08:00
}
}
return routerArray
}
// Run starts server listening in blocking way.
// It's commonly used for single server situation.
func (s *Server) Run() {
var ctx = context.TODO()
2019-06-19 09:06:52 +08:00
if err := s.Start(); err != nil {
s.Logger().Fatalf(ctx, `%+v`, err)
2019-06-19 09:06:52 +08:00
}
// Signal handler in asynchronous way.
go handleProcessSignal()
// Blocking using the channel for graceful restart.
2019-06-19 09:06:52 +08:00
<-s.closeChan
// Shutdown the server
_ = s.Shutdown()
2018-05-10 19:16:41 +08:00
}
2018-05-10 17:48:47 +08:00
// Wait blocks to wait for all servers done.
// It's commonly used in multiple server situation.
func Wait() {
var ctx = context.TODO()
// Signal handler in asynchronous way.
go handleProcessSignal()
<-allShutdownChan
// Remove plugins.
refactor: interface{} to any and reflect.Ptr to reflect.Pointer (#4395) This pull request standardizes the use of the Go 1.18+ `any` type alias instead of `interface{}` throughout the codebase. The change improves code readability and aligns with modern Go best practices. The update touches many files, including core data structures, code generation templates, logging utilities, and test data, ensuring consistency across all usages. **Type alias migration to `any`:** * Replaced all instances of `interface{}` with `any` in core data structures such as `garray` and in generated model structs (e.g., `TableUser`, `User1`, `User2`) to modernize type usage. [[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31) [[2]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19) [[3]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18) [[4]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19) [[5]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19) [[6]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19) * Updated function signatures, method parameters, and return types from `interface{}` to `any` in various parts of the codebase, including code generation, service logic, and logging utilities (e.g., `mlog`). [[1]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55) [[2]](diffhunk://#diff-2b1953fb78cf3593d8c2c7d911e95b65fd0b847c30ed0b4d167d16fe6d781235L54-R74) [[3]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73) [[4]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41) [[5]](diffhunk://#diff-c5d51d56f487779a2b6207c7ad26c7a20bbadcc846ce094fe60ab4cabff58c51L107-R107) [[6]](diffhunk://#diff-f96e6a9fdb416eb1804ceaba1fe0ac637bff22c43837f8bb849c2366ce72d4a1L116-R121) [[7]](diffhunk://#diff-f94c83a1b08ae060d9346f4a6031fc4a7b9a0b894e02d9afaa09018b6598eac0L112-R112) [[8]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L36-R36) [[9]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L74-R74) [[10]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L96-R96) **Generated code and templates:** * Adjusted generated files and code generation templates to output `any` instead of `interface{}` for relevant struct fields and function signatures, ensuring that new code generation aligns with the updated convention. [[1]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19) [[2]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18) [[3]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19) [[4]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19) [[5]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19) [[6]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55) [[7]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73) [[8]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41) **Container and utility updates:** * Refactored the `garray` container implementation and related constructors/methods to use `[]any` instead of `[]interface{}`, along with corresponding function signatures. [[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31) [[2]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L52-R52) [[3]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L62-R62) [[4]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L73-R86) [[5]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L96-R97) [[6]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L107-R114) [[7]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L124-R124) [[8]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L135-R143) [[9]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L167-R167) These changes collectively modernize the codebase and prepare it for future Go developments by using the idiomatic `any` type.
2025-08-28 16:53:19 +08:00
serverMapping.Iterator(func(k string, v any) bool {
s := v.(*Server)
if len(s.plugins) > 0 {
for _, p := range s.plugins {
2021-09-27 21:27:24 +08:00
intlog.Printf(ctx, `remove plugin: %s`, p.Name())
if err := p.Remove(); err != nil {
intlog.Errorf(ctx, `%+v`, err)
2021-09-27 21:27:24 +08:00
}
}
}
return true
})
glog.Infof(ctx, "pid[%d]: all servers shutdown", gproc.Pid())
}
// startServer starts the underlying server listening.
2018-05-10 23:52:09 +08:00
func (s *Server) startServer(fdMap listenerFdMap) {
2021-09-27 21:27:24 +08:00
var (
ctx = context.TODO()
httpsEnabled bool
)
// HTTPS
if s.config.TLSConfig != nil || (s.config.HTTPSCertPath != "" && s.config.HTTPSKeyPath != "") {
2019-06-19 09:06:52 +08:00
if len(s.config.HTTPSAddr) == 0 {
if len(s.config.Address) > 0 {
s.config.HTTPSAddr = s.config.Address
s.config.Address = ""
2019-06-19 09:06:52 +08:00
} else {
s.config.HTTPSAddr = defaultHttpsAddr
2019-06-19 09:06:52 +08:00
}
}
httpsEnabled = len(s.config.HTTPSAddr) > 0
var array []string
if v, ok := fdMap["https"]; ok && len(v) > 0 {
array = strings.Split(v, ",")
} else {
array = strings.Split(s.config.HTTPSAddr, ",")
}
for _, v := range array {
if len(v) == 0 {
continue
}
2022-01-13 20:57:13 +08:00
var (
fd = 0
itemFunc = v
addrAndFd = strings.Split(v, "#")
)
if len(addrAndFd) > 1 {
itemFunc = addrAndFd[0]
2021-09-27 21:27:24 +08:00
// The Windows OS does not support socket file descriptor passing
// from parent process.
2019-06-19 09:06:52 +08:00
if runtime.GOOS != "windows" {
2022-01-13 20:57:13 +08:00
fd = gconv.Int(addrAndFd[1])
2019-06-19 09:06:52 +08:00
}
}
if fd > 0 {
s.servers = append(s.servers, s.newGracefulServer(itemFunc, fd))
2019-06-19 09:06:52 +08:00
} else {
s.servers = append(s.servers, s.newGracefulServer(itemFunc, 0))
2019-06-19 09:06:52 +08:00
}
s.servers[len(s.servers)-1].SetIsHttps(true)
2019-06-19 09:06:52 +08:00
}
}
// HTTP
if !httpsEnabled && len(s.config.Address) == 0 {
s.config.Address = defaultHttpAddr
2019-06-19 09:06:52 +08:00
}
var array []string
if v, ok := fdMap["http"]; ok && len(v) > 0 {
array = gstr.SplitAndTrim(v, ",")
2019-06-19 09:06:52 +08:00
} else {
array = gstr.SplitAndTrim(s.config.Address, ",")
2019-06-19 09:06:52 +08:00
}
for _, v := range array {
if len(v) == 0 {
continue
}
2022-01-13 20:57:13 +08:00
var (
fd = 0
itemFunc = v
addrAndFd = strings.Split(v, "#")
)
if len(addrAndFd) > 1 {
itemFunc = addrAndFd[0]
2022-03-19 17:58:21 +08:00
// The Window OS does not support socket file descriptor passing
// from the parent process.
2019-06-19 09:06:52 +08:00
if runtime.GOOS != "windows" {
2022-01-13 20:57:13 +08:00
fd = gconv.Int(addrAndFd[1])
2019-06-19 09:06:52 +08:00
}
}
if fd > 0 {
s.servers = append(s.servers, s.newGracefulServer(itemFunc, fd))
2019-06-19 09:06:52 +08:00
} else {
s.servers = append(s.servers, s.newGracefulServer(itemFunc, 0))
2019-06-19 09:06:52 +08:00
}
}
2021-05-15 18:13:51 +08:00
// Start listening asynchronously.
2019-06-19 09:06:52 +08:00
serverRunning.Add(1)
var wg = &sync.WaitGroup{}
for _, gs := range s.servers {
wg.Add(1)
go s.startGracefulServer(ctx, wg, gs)
2019-06-19 09:06:52 +08:00
}
wg.Wait()
2018-08-01 13:04:15 +08:00
}
2018-04-23 19:22:59 +08:00
func (s *Server) startGracefulServer(ctx context.Context, wg *sync.WaitGroup, server *graceful.Server) {
s.serverCount.Add(1)
var err error
// Create listener.
if server.IsHttps() {
err = server.CreateListenerTLS(
s.config.HTTPSCertPath, s.config.HTTPSKeyPath, s.config.TLSConfig,
)
} else {
err = server.CreateListener()
}
if err != nil {
s.Logger().Fatalf(ctx, `%+v`, err)
}
wg.Done()
// Start listening and serving in blocking way.
err = server.Serve(ctx)
// The process exits if the server is closed with none closing error.
if err != nil && !strings.EqualFold(http.ErrServerClosed.Error(), err.Error()) {
s.Logger().Fatalf(ctx, `%+v`, err)
}
// If all the underlying servers' shutdown, the process exits.
if s.serverCount.Add(-1) < 1 {
s.closeChan <- struct{}{}
if serverRunning.Add(-1) < 1 {
serverMapping.Remove(s.instance)
allShutdownChan <- struct{}{}
}
}
}
// Status retrieves and returns the server status.
func (s *Server) Status() ServerStatus {
2019-06-19 09:06:52 +08:00
if serverRunning.Val() == 0 {
2020-12-14 13:26:48 +08:00
return ServerStatusStopped
2019-06-19 09:06:52 +08:00
}
// If any underlying server is running, the server status is running.
2019-06-19 09:06:52 +08:00
for _, v := range s.servers {
if v.Status() == ServerStatusRunning {
2020-12-14 13:26:48 +08:00
return ServerStatusRunning
2019-06-19 09:06:52 +08:00
}
}
2020-12-14 13:26:48 +08:00
return ServerStatusStopped
}
// getListenerFdMap retrieves and returns the socket file descriptors.
// The key of the returned map is "http" and "https".
2018-05-10 23:52:09 +08:00
func (s *Server) getListenerFdMap() map[string]string {
2019-06-19 09:06:52 +08:00
m := map[string]string{
"https": "",
"http": "",
}
for _, v := range s.servers {
str := v.GetAddress() + "#" + gconv.String(v.Fd()) + ","
if v.IsHttps() {
if len(m["https"]) > 0 {
m["https"] += ","
}
2019-06-19 09:06:52 +08:00
m["https"] += str
} else {
if len(m["http"]) > 0 {
m["http"] += ","
}
2019-06-19 09:06:52 +08:00
m["http"] += str
}
}
return m
2018-05-10 19:16:41 +08:00
}
// GetListenedPort returns a port currently listened to by the server.
// It prioritizes the HTTP port if both HTTP and HTTPS are enabled.
func (s *Server) GetListenedPort() int {
for _, server := range s.servers {
if !server.IsHttps() {
return server.GetListenedPort()
}
}
for _, server := range s.servers {
if server.IsHttps() {
return server.GetListenedPort()
}
}
return -1
}
// GetListenedHTTPSPort retrieves and returns one port which is listened using TLS by current server.
func (s *Server) GetListenedHTTPSPort() int {
for _, server := range s.servers {
if server.IsHttps() {
return server.GetListenedPort()
}
}
return -1
}
// GetListenedPorts retrieves and returns the ports which are listened by current server.
func (s *Server) GetListenedPorts() []int {
ports := make([]int, 0)
for _, server := range s.servers {
ports = append(ports, server.GetListenedPort())
}
return ports
}
// GetListenedAddress retrieves and returns the address string which are listened by current server.
func (s *Server) GetListenedAddress() string {
if !gstr.Contains(s.config.Address, FreePortAddress) {
return s.config.Address
}
var (
address = s.config.Address
listenedPorts = s.GetListenedPorts()
)
for _, listenedPort := range listenedPorts {
address = gstr.Replace(address, FreePortAddress, fmt.Sprintf(`:%d`, listenedPort), 1)
}
return address
}