2021-01-06 01:00:49 +08:00
|
|
|
// 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,
|
2019-02-02 16:18:25 +08:00
|
|
|
// 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"
|
2021-06-26 16:23:54 +08:00
|
|
|
"context"
|
2021-10-03 00:22:06 +08:00
|
|
|
"fmt"
|
2019-06-22 11:03:50 +08:00
|
|
|
"net/http"
|
|
|
|
|
"os"
|
|
|
|
|
"runtime"
|
|
|
|
|
"strings"
|
2022-10-08 21:45:21 +08:00
|
|
|
"sync"
|
2019-06-22 11:03:50 +08:00
|
|
|
"time"
|
|
|
|
|
|
2021-11-16 19:43:02 +08:00
|
|
|
"github.com/olekukonko/tablewriter"
|
2025-09-01 12:20:22 +08:00
|
|
|
"github.com/olekukonko/tablewriter/renderer"
|
|
|
|
|
"github.com/olekukonko/tablewriter/tw"
|
2021-11-16 19:43:02 +08:00
|
|
|
|
2021-10-11 21:41:56 +08:00
|
|
|
"github.com/gogf/gf/v2/container/garray"
|
2023-11-02 09:48:39 +08:00
|
|
|
"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"
|
2024-12-10 09:52:48 +08:00
|
|
|
"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
|
|
|
)
|
|
|
|
|
|
2019-03-01 23:45:55 +08:00
|
|
|
func init() {
|
2022-03-19 17:58:21 +08:00
|
|
|
// Initialize the method map.
|
2021-01-19 19:33:21 +08:00
|
|
|
for _, v := range strings.Split(supportedHttpMethods, ",") {
|
2019-06-19 09:06:52 +08:00
|
|
|
methodsMap[v] = struct{}{}
|
|
|
|
|
}
|
2019-03-01 23:45:55 +08:00
|
|
|
}
|
|
|
|
|
|
2020-04-29 00:14:29 +08:00
|
|
|
// serverProcessInit initializes some process configurations, which can only be done once.
|
2019-02-20 16:07:11 +08:00
|
|
|
func serverProcessInit() {
|
2022-01-27 16:50:31 +08:00
|
|
|
var ctx = context.TODO()
|
2020-11-08 15:44:04 +08:00
|
|
|
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,
|
2020-04-29 00:14:29 +08:00
|
|
|
// to avoid duplicated port listening in two processes.
|
2021-10-21 18:22:47 +08:00
|
|
|
if !genv.Get(adminActionRestartEnvKey).IsEmpty() {
|
2021-10-03 00:22:06 +08:00
|
|
|
if p, err := os.FindProcess(gproc.PPid()); err == nil {
|
|
|
|
|
if err = p.Kill(); err != nil {
|
2022-01-28 14:51:49 +08:00
|
|
|
intlog.Errorf(ctx, `%+v`, err)
|
2021-10-03 00:22:06 +08:00
|
|
|
}
|
|
|
|
|
if _, err = p.Wait(); err != nil {
|
2022-01-28 14:51:49 +08:00
|
|
|
intlog.Errorf(ctx, `%+v`, err)
|
2021-10-03 00:22:06 +08:00
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
} else {
|
2021-10-03 00:22:06 +08:00
|
|
|
glog.Error(ctx, err)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-29 00:14:29 +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 {
|
2022-10-11 19:20:39 +08:00
|
|
|
intlog.Printf(ctx, "pid[%d]: graceful reload feature is enabled", gproc.Pid())
|
2019-06-19 09:06:52 +08:00
|
|
|
go handleProcessMessage()
|
2020-07-25 13:50:04 +08:00
|
|
|
} else {
|
2022-10-11 19:20:39 +08:00
|
|
|
intlog.Printf(ctx, "pid[%d]: graceful reload feature is disabled", gproc.Pid())
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
|
|
2020-04-29 00:14:29 +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
|
|
|
}
|
|
|
|
|
|
2020-04-29 00:14:29 +08:00
|
|
|
// GetServer creates and returns a server instance using given name and default configurations.
|
2021-10-21 18:22:47 +08:00
|
|
|
// 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 {
|
2021-09-19 10:01:09 +08:00
|
|
|
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),
|
2024-12-10 09:52:48 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2020-04-29 00:14:29 +08:00
|
|
|
// Start starts listening on configured port.
|
|
|
|
|
// This function does not block the process, you can use function Wait blocking the process.
|
2018-05-13 14:04:37 +08:00
|
|
|
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
|
|
|
|
2021-10-03 00:22:06 +08:00
|
|
|
// Swagger UI.
|
|
|
|
|
if s.config.SwaggerPath != "" {
|
2021-10-13 22:28:49 +08:00
|
|
|
swaggerui.Init()
|
2022-03-23 14:48:34 +08:00
|
|
|
s.AddStaticPath(s.config.SwaggerPath, swaggerUIPackedPath)
|
2021-10-03 00:22:06 +08:00
|
|
|
s.BindHookHandler(s.config.SwaggerPath+"/*", HookBeforeServe, s.swaggerUI)
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-02 22:34:39 +08:00
|
|
|
// OpenApi specification json producing handler.
|
|
|
|
|
if s.config.OpenApiPath != "" {
|
2021-10-03 00:22:06 +08:00
|
|
|
s.BindHandler(s.config.OpenApiPath, s.openapiSpec)
|
2021-10-02 22:34:39 +08:00
|
|
|
}
|
2022-10-11 19:20:39 +08:00
|
|
|
|
2019-12-04 13:55:08 +08:00
|
|
|
// Register group routes.
|
2021-09-27 21:27:24 +08:00
|
|
|
s.handlePreBindItems(ctx)
|
2019-08-06 20:40:04 +08:00
|
|
|
|
2019-12-04 13:55:08 +08:00
|
|
|
// Server process initialization, which can only be initialized once.
|
2019-06-19 09:06:52 +08:00
|
|
|
serverProcessInit()
|
|
|
|
|
|
2019-12-04 13:55:08 +08:00
|
|
|
// Server can only be run once.
|
2020-12-14 13:26:48 +08:00
|
|
|
if s.Status() == ServerStatusRunning {
|
2021-08-24 21:18:59 +08:00
|
|
|
return gerror.NewCode(gcode.CodeInvalidOperation, "server is already running")
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
|
|
2019-12-04 13:55:08 +08:00
|
|
|
// Logging path setting check.
|
2021-01-06 01:00:49 +08:00
|
|
|
if s.config.LogPath != "" && s.config.LogPath != s.config.Logger.GetPath() {
|
2019-11-08 19:52:49 +08:00
|
|
|
if err := s.config.Logger.SetPath(s.config.LogPath); err != nil {
|
2021-01-06 01:00:49 +08:00
|
|
|
return err
|
2019-11-08 19:52:49 +08:00
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2019-10-29 16:45:42 +08:00
|
|
|
// Default session storage.
|
|
|
|
|
if s.config.SessionStorage == nil {
|
2022-06-28 15:47:16 +08:00
|
|
|
sessionStoragePath := ""
|
2019-11-07 20:42:13 +08:00
|
|
|
if s.config.SessionPath != "" {
|
2022-06-28 15:47:16 +08:00
|
|
|
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)
|
2019-11-07 20:42:13 +08:00
|
|
|
}
|
2019-11-07 20:36:33 +08:00
|
|
|
}
|
|
|
|
|
}
|
2022-06-28 15:47:16 +08:00
|
|
|
s.config.SessionStorage = gsession.NewStorageFile(sessionStoragePath, s.config.SessionMaxAge)
|
2019-10-29 16:45:42 +08:00
|
|
|
}
|
|
|
|
|
// Initialize session manager when start running.
|
2019-11-07 20:36:33 +08:00
|
|
|
s.sessionManager = gsession.New(
|
|
|
|
|
s.config.SessionMaxAge,
|
|
|
|
|
s.config.SessionStorage,
|
|
|
|
|
)
|
2019-10-29 16:45:42 +08:00
|
|
|
|
2019-11-07 16:40:34 +08:00
|
|
|
// 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 {
|
2022-02-22 14:12:09 +08:00
|
|
|
s.config.Handler = s.ServeHTTP
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
|
|
2020-01-21 17:18:03 +08:00
|
|
|
// Install external plugins.
|
|
|
|
|
for _, p := range s.plugins {
|
|
|
|
|
if err := p.Install(s); err != nil {
|
2021-10-06 12:12:59 +08:00
|
|
|
s.Logger().Fatalf(ctx, `%+v`, err)
|
2020-01-21 17:18:03 +08:00
|
|
|
}
|
|
|
|
|
}
|
2023-01-06 14:15:30 +08:00
|
|
|
// Check the group routes again for internally registered routes.
|
2021-09-27 21:27:24 +08:00
|
|
|
s.handlePreBindItems(ctx)
|
2020-01-21 17:18:03 +08:00
|
|
|
|
2022-03-19 17:58:21 +08:00
|
|
|
// If there's no route registered and no static service enabled,
|
2020-09-17 23:27:10 +08:00
|
|
|
// 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(
|
2021-08-24 21:18:59 +08:00
|
|
|
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?`,
|
|
|
|
|
)
|
2020-09-17 23:27:10 +08:00
|
|
|
}
|
2022-10-08 21:45:21 +08:00
|
|
|
// ================================================================================================
|
2019-11-07 16:40:34 +08:00
|
|
|
// Start the HTTP server.
|
2022-10-08 21:45:21 +08:00
|
|
|
// ================================================================================================
|
2019-06-19 09:06:52 +08:00
|
|
|
reloaded := false
|
2021-10-21 18:22:47 +08:00
|
|
|
fdMapStr := genv.Get(adminActionReloadEnvKey).String()
|
2019-06-19 09:06:52 +08:00
|
|
|
if len(fdMapStr) > 0 {
|
|
|
|
|
sfm := bufferToServerFdMap([]byte(fdMapStr))
|
2022-01-27 16:50:31 +08:00
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-11 19:20:39 +08:00
|
|
|
// 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`,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-04 13:55:08 +08:00
|
|
|
// If this is a child process, it then notifies its parent exit.
|
2019-06-19 09:06:52 +08:00
|
|
|
if gproc.IsChild() {
|
2024-09-19 14:10:16 +08:00
|
|
|
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 {
|
2022-01-28 14:51:49 +08:00
|
|
|
intlog.Errorf(ctx, `server error in process communication: %+v`, err)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
2021-10-02 22:34:39 +08:00
|
|
|
s.initOpenApi()
|
2022-01-27 16:50:31 +08:00
|
|
|
s.doServiceRegister()
|
2022-10-08 21:45:21 +08:00
|
|
|
s.doRouterMapDump()
|
2023-03-13 19:21:56 +08:00
|
|
|
|
2019-06-19 09:06:52 +08:00
|
|
|
return nil
|
2018-05-13 14:04:37 +08:00
|
|
|
}
|
2018-04-27 22:12:11 +08:00
|
|
|
|
2022-10-08 21:45:21 +08:00
|
|
|
func (s *Server) getLocalListenedAddress() string {
|
|
|
|
|
return fmt.Sprintf(`http://127.0.0.1:%d`, s.GetListenedPort())
|
2021-10-03 00:22:06 +08:00
|
|
|
}
|
|
|
|
|
|
2022-10-08 21:45:21 +08:00
|
|
|
// doRouterMapDump checks and dumps the router map to the log.
|
|
|
|
|
func (s *Server) doRouterMapDump() {
|
2023-01-06 14:15:30 +08:00
|
|
|
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()
|
2021-12-18 18:25:04 +08:00
|
|
|
routes = s.GetRoutes()
|
2021-12-18 12:36:34 +08:00
|
|
|
isJustDefaultServerAndDomain = true
|
2022-10-08 21:45:21 +08:00
|
|
|
headers = []string{
|
|
|
|
|
"SERVER", "DOMAIN", "ADDRESS", "METHOD", "ROUTE", "HANDLER", "MIDDLEWARE",
|
|
|
|
|
}
|
2021-09-27 21:27:24 +08:00
|
|
|
)
|
2021-12-18 18:25:04 +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"}
|
|
|
|
|
}
|
2023-01-06 14:15:30 +08:00
|
|
|
if len(routes) > 0 {
|
2019-12-04 13:55:08 +08:00
|
|
|
buffer := bytes.NewBuffer(nil)
|
2025-09-01 12:20:22 +08:00
|
|
|
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
|
|
|
|
2021-12-18 18:25:04 +08:00
|
|
|
for _, item := range routes {
|
2021-12-18 12:54:09 +08:00
|
|
|
var (
|
|
|
|
|
data = make([]string, 0)
|
|
|
|
|
handlerName = gstr.TrimRightStr(item.Handler.Name, "-fm")
|
|
|
|
|
middlewares = gstr.SplitAndTrim(item.Middleware, ",")
|
|
|
|
|
)
|
2024-01-22 21:05:40 +08:00
|
|
|
|
|
|
|
|
// No printing special internal middleware that may lead confused.
|
|
|
|
|
if gstr.SubStrFromREx(handlerName, ".") == noPrintInternalRoute {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2021-12-18 12:54:09 +08:00
|
|
|
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,
|
2021-12-18 12:54:09 +08:00
|
|
|
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,
|
2021-12-18 12:54:09 +08:00
|
|
|
handlerName,
|
2021-12-18 12:36:34 +08:00
|
|
|
item.Middleware,
|
|
|
|
|
)
|
|
|
|
|
}
|
2025-09-01 15:33:50 +08:00
|
|
|
_ = table.Append(data)
|
2019-12-04 13:55:08 +08:00
|
|
|
}
|
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-12-04 13:55:08 +08:00
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
|
2024-12-11 10:14:12 +08:00
|
|
|
// GetOpenApi returns the OpenApi specification management object of the current server.
|
2021-10-02 22:34:39 +08:00
|
|
|
func (s *Server) GetOpenApi() *goai.OpenApiV3 {
|
|
|
|
|
return s.openapi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetRoutes retrieves and returns the router array.
|
|
|
|
|
func (s *Server) GetRoutes() []RouterItem {
|
2021-12-18 18:25:04 +08:00
|
|
|
var (
|
2023-11-02 09:48:39 +08:00
|
|
|
m = make(map[string]*garray.SortedArray)
|
|
|
|
|
routeFilterSet = gset.NewStrSet()
|
|
|
|
|
address = s.GetListenedAddress()
|
2021-12-18 18:25:04 +08:00
|
|
|
)
|
2019-12-09 21:53:44 +08:00
|
|
|
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)
|
2023-11-02 09:48:39 +08:00
|
|
|
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,
|
|
|
|
|
}
|
|
|
|
|
)
|
2021-10-02 22:34:39 +08:00
|
|
|
switch item.Handler.Type {
|
2021-10-06 14:22:58 +08:00
|
|
|
case HandlerTypeObject, HandlerTypeHandler:
|
2019-12-09 23:19:39 +08:00
|
|
|
item.IsServiceHandler = true
|
2021-10-02 22:34:39 +08:00
|
|
|
|
2021-10-06 14:22:58 +08:00
|
|
|
case HandlerTypeMiddleware:
|
2019-12-04 13:55:08 +08:00
|
|
|
item.Middleware = "GLOBAL MIDDLEWARE"
|
2019-12-04 10:03:03 +08:00
|
|
|
}
|
2023-11-02 09:48:39 +08:00
|
|
|
// 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
|
|
|
|
|
}
|
2021-10-02 22:34:39 +08:00
|
|
|
if len(item.Handler.Middleware) > 0 {
|
|
|
|
|
for _, v := range item.Handler.Middleware {
|
2019-12-04 13:55:08 +08:00
|
|
|
if item.Middleware != "" {
|
2021-05-02 08:10:35 +08:00
|
|
|
item.Middleware += ","
|
2019-12-04 10:03:03 +08:00
|
|
|
}
|
2019-12-04 13:55:08 +08:00
|
|
|
item.Middleware += gdebug.FuncName(v)
|
2019-12-04 10:03:03 +08:00
|
|
|
}
|
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.
|
2019-12-04 10:03:03 +08:00
|
|
|
// The value of the map is a custom sorted array.
|
2019-12-04 13:55:08 +08:00
|
|
|
if _, ok := m[item.Domain]; !ok {
|
2019-12-04 10:03:03 +08:00
|
|
|
// 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 {
|
2019-12-04 13:55:08 +08:00
|
|
|
item1 := v1.(RouterItem)
|
|
|
|
|
item2 := v2.(RouterItem)
|
2019-06-19 09:06:52 +08:00
|
|
|
r := 0
|
2019-12-04 13:55:08 +08:00
|
|
|
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 {
|
2021-10-06 14:22:58 +08:00
|
|
|
if item1.Handler.Type == HandlerTypeMiddleware && item2.Handler.Type != HandlerTypeMiddleware {
|
2019-08-03 23:57:20 +08:00
|
|
|
return -1
|
2021-10-06 14:22:58 +08:00
|
|
|
} else if item1.Handler.Type == HandlerTypeMiddleware && item2.Handler.Type == HandlerTypeMiddleware {
|
2019-08-03 23:57:20 +08:00
|
|
|
return 1
|
2019-12-04 13:55:08 +08:00
|
|
|
} 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-07-23 23:20:27 +08:00
|
|
|
})
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2019-12-04 13:55:08 +08:00
|
|
|
m[item.Domain].Add(item)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
|
}
|
2021-12-18 18:25:04 +08:00
|
|
|
|
2019-12-10 12:28:55 +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
|
|
|
}
|
|
|
|
|
}
|
2019-12-10 12:28:55 +08:00
|
|
|
return routerArray
|
2018-10-17 10:09:42 +08:00
|
|
|
}
|
|
|
|
|
|
2019-12-04 13:55:08 +08:00
|
|
|
// Run starts server listening in blocking way.
|
2020-03-04 17:29:23 +08:00
|
|
|
// It's commonly used for single server situation.
|
2019-06-22 11:03:50 +08:00
|
|
|
func (s *Server) Run() {
|
2022-01-27 16:50:31 +08:00
|
|
|
var ctx = context.TODO()
|
|
|
|
|
|
2019-06-19 09:06:52 +08:00
|
|
|
if err := s.Start(); err != nil {
|
2021-10-06 12:12:59 +08:00
|
|
|
s.Logger().Fatalf(ctx, `%+v`, err)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2023-03-13 19:21:56 +08:00
|
|
|
|
2023-07-06 21:29:33 +08:00
|
|
|
// Signal handler in asynchronous way.
|
|
|
|
|
go handleProcessSignal()
|
2023-03-13 19:21:56 +08:00
|
|
|
|
2024-12-11 10:14:12 +08:00
|
|
|
// Blocking using the channel for graceful restart.
|
2019-06-19 09:06:52 +08:00
|
|
|
<-s.closeChan
|
2024-12-26 10:18:47 +08:00
|
|
|
|
|
|
|
|
// Shutdown the server
|
|
|
|
|
_ = s.Shutdown()
|
2018-05-10 19:16:41 +08:00
|
|
|
}
|
2018-05-10 17:48:47 +08:00
|
|
|
|
2019-12-04 13:55:08 +08:00
|
|
|
// Wait blocks to wait for all servers done.
|
2022-01-27 16:50:31 +08:00
|
|
|
// It's commonly used in multiple server situation.
|
2018-05-13 14:04:37 +08:00
|
|
|
func Wait() {
|
2022-01-27 16:50:31 +08:00
|
|
|
var ctx = context.TODO()
|
|
|
|
|
|
2023-07-19 20:06:06 +08:00
|
|
|
// Signal handler in asynchronous way.
|
|
|
|
|
go handleProcessSignal()
|
|
|
|
|
|
2022-10-08 21:45:21 +08:00
|
|
|
<-allShutdownChan
|
2023-10-09 20:03:45 +08:00
|
|
|
|
2020-03-04 17:29:23 +08:00
|
|
|
// 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 {
|
2020-03-04 17:29:23 +08:00
|
|
|
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 {
|
2022-01-28 14:51:49 +08:00
|
|
|
intlog.Errorf(ctx, `%+v`, err)
|
2021-09-27 21:27:24 +08:00
|
|
|
}
|
2020-03-04 17:29:23 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
})
|
2022-01-28 16:00:16 +08:00
|
|
|
glog.Infof(ctx, "pid[%d]: all servers shutdown", gproc.Pid())
|
2018-05-13 14:04:37 +08:00
|
|
|
}
|
|
|
|
|
|
2020-04-29 00:14:29 +08:00
|
|
|
// 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
|
|
|
|
|
)
|
2020-04-29 00:14:29 +08:00
|
|
|
// HTTPS
|
2019-11-07 16:40:34 +08:00
|
|
|
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 {
|
2019-11-07 11:32:25 +08:00
|
|
|
if len(s.config.Address) > 0 {
|
|
|
|
|
s.config.HTTPSAddr = s.config.Address
|
|
|
|
|
s.config.Address = ""
|
2019-06-19 09:06:52 +08:00
|
|
|
} else {
|
2021-01-12 00:42:33 +08:00
|
|
|
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
|
2020-04-29 00:14:29 +08:00
|
|
|
// 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 {
|
2019-08-03 15:54:12 +08:00
|
|
|
s.servers = append(s.servers, s.newGracefulServer(itemFunc, fd))
|
2019-06-19 09:06:52 +08:00
|
|
|
} else {
|
2024-12-10 09:52:48 +08:00
|
|
|
s.servers = append(s.servers, s.newGracefulServer(itemFunc, 0))
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2024-12-10 09:52:48 +08:00
|
|
|
s.servers[len(s.servers)-1].SetIsHttps(true)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// HTTP
|
2019-11-07 11:32:25 +08:00
|
|
|
if !httpsEnabled && len(s.config.Address) == 0 {
|
2021-01-12 00:42:33 +08:00
|
|
|
s.config.Address = defaultHttpAddr
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
|
|
|
|
var array []string
|
|
|
|
|
if v, ok := fdMap["http"]; ok && len(v) > 0 {
|
2023-04-23 21:58:17 +08:00
|
|
|
array = gstr.SplitAndTrim(v, ",")
|
2019-06-19 09:06:52 +08:00
|
|
|
} else {
|
2023-04-23 21:58:17 +08:00
|
|
|
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 {
|
2019-08-03 15:54:12 +08:00
|
|
|
s.servers = append(s.servers, s.newGracefulServer(itemFunc, fd))
|
2019-06-19 09:06:52 +08:00
|
|
|
} else {
|
2024-12-10 09:52:48 +08:00
|
|
|
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)
|
2024-05-22 21:14:43 +08:00
|
|
|
var wg = &sync.WaitGroup{}
|
|
|
|
|
for _, gs := range s.servers {
|
2022-10-08 21:45:21 +08:00
|
|
|
wg.Add(1)
|
2024-05-22 21:14:43 +08:00
|
|
|
go s.startGracefulServer(ctx, wg, gs)
|
2019-06-19 09:06:52 +08:00
|
|
|
}
|
2022-10-08 21:45:21 +08:00
|
|
|
wg.Wait()
|
2018-08-01 13:04:15 +08:00
|
|
|
}
|
2018-04-23 19:22:59 +08:00
|
|
|
|
2024-12-10 09:52:48 +08:00
|
|
|
func (s *Server) startGracefulServer(ctx context.Context, wg *sync.WaitGroup, server *graceful.Server) {
|
2024-05-22 21:14:43 +08:00
|
|
|
s.serverCount.Add(1)
|
|
|
|
|
var err error
|
|
|
|
|
// Create listener.
|
2024-12-10 09:52:48 +08:00
|
|
|
if server.IsHttps() {
|
2024-05-22 21:14:43 +08:00
|
|
|
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{}{}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-29 00:14:29 +08:00
|
|
|
// Status retrieves and returns the server status.
|
2023-07-06 21:29:33 +08:00
|
|
|
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
|
|
|
}
|
2020-04-29 00:14:29 +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 {
|
2024-12-10 09:52:48 +08:00
|
|
|
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
|
2018-05-08 23:38:09 +08:00
|
|
|
}
|
|
|
|
|
|
2020-04-29 00:14:29 +08:00
|
|
|
// 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 {
|
2024-12-10 09:52:48 +08:00
|
|
|
str := v.GetAddress() + "#" + gconv.String(v.Fd()) + ","
|
|
|
|
|
if v.IsHttps() {
|
2020-04-29 00:14:29 +08:00
|
|
|
if len(m["https"]) > 0 {
|
|
|
|
|
m["https"] += ","
|
|
|
|
|
}
|
2019-06-19 09:06:52 +08:00
|
|
|
m["https"] += str
|
|
|
|
|
} else {
|
2020-04-29 00:14:29 +08:00
|
|
|
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
|
|
|
}
|
2022-02-22 14:12:09 +08:00
|
|
|
|
2024-12-11 10:14:12 +08:00
|
|
|
// GetListenedPort returns a port currently listened to by the server.
|
|
|
|
|
// It prioritizes the HTTP port if both HTTP and HTTPS are enabled.
|
2022-02-22 14:12:09 +08:00
|
|
|
func (s *Server) GetListenedPort() int {
|
2024-12-10 09:52:48 +08:00
|
|
|
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()
|
|
|
|
|
}
|
2022-02-22 14:12:09 +08:00
|
|
|
}
|
2024-12-10 09:52:48 +08:00
|
|
|
return -1
|
2022-02-22 14:12:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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 {
|
2022-02-22 20:49:09 +08:00
|
|
|
ports = append(ports, server.GetListenedPort())
|
2022-02-22 14:12:09 +08:00
|
|
|
}
|
|
|
|
|
return ports
|
|
|
|
|
}
|
2022-10-08 21:45:21 +08:00
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
}
|