加入summary 优化http监听逻辑,实现基本身份认证

This commit is contained in:
dexter
2022-03-01 20:42:25 +08:00
parent 37586d4a0b
commit abe2cdd1fc
11 changed files with 326 additions and 64 deletions

View File

@@ -169,6 +169,9 @@ func Struct2Config(s any) (config Config) {
} }
for i, j := 0, t.NumField(); i < j; i++ { for i, j := 0, t.NumField(); i < j; i++ {
ft := t.Field(i) ft := t.Field(i)
if !ft.IsExported() {
continue
}
name := strings.ToLower(ft.Name) name := strings.ToLower(ft.Name)
switch ft.Type.Kind() { switch ft.Type.Kind() {
case reflect.Struct: case reflect.Struct:

View File

@@ -4,27 +4,69 @@ import (
"context" "context"
"net/http" "net/http"
. "github.com/logrusorgru/aurora"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"m7s.live/engine/v4/log"
"m7s.live/engine/v4/util"
) )
var _ HTTPConfig = (*HTTP)(nil)
type HTTP struct { type HTTP struct {
ListenAddr string ListenAddr string
ListenAddrTLS string ListenAddrTLS string
CertFile string CertFile string
KeyFile string KeyFile string
CORS bool //是否自动添加CORS头 CORS bool //是否自动添加CORS头
UserName string
Password string
mux *http.ServeMux
}
type HTTPConfig interface {
InitMux()
GetHTTPConfig() *HTTP
Listen(ctx context.Context) error
HandleFunc(string, func(http.ResponseWriter, *http.Request))
}
func (config *HTTP) InitMux() {
hasOwnTLS := config.ListenAddrTLS != "" && config.ListenAddrTLS != Global.ListenAddrTLS
hasOwnHTTP := config.ListenAddr != "" && config.ListenAddr != Global.ListenAddr
if hasOwnTLS || hasOwnHTTP {
config.mux = http.NewServeMux()
}
}
func (config *HTTP) HandleFunc(path string, f func(http.ResponseWriter, *http.Request)) {
if config.mux != nil {
if config.CORS {
f = util.CORS(f)
}
if config.UserName != "" && config.Password != "" {
f = util.BasicAuth(config.UserName, config.Password, f)
}
config.mux.HandleFunc(path, f)
}
}
func (config *HTTP) GetHTTPConfig() *HTTP {
return config
} }
// ListenAddrs Listen http and https // ListenAddrs Listen http and https
func (config *HTTP) Listen(ctx context.Context, plugin HTTPPlugin) error { func (config *HTTP) Listen(ctx context.Context) error {
var g errgroup.Group var g errgroup.Group
if config.ListenAddrTLS != "" { if config.ListenAddrTLS != "" && (config == &Global.HTTP || config.ListenAddrTLS != Global.ListenAddrTLS) {
g.Go(func() error { g.Go(func() error {
return http.ListenAndServeTLS(config.ListenAddrTLS, config.CertFile, config.KeyFile, plugin) log.Info("🌐 https listen at ", Blink(config.ListenAddrTLS))
return http.ListenAndServeTLS(config.ListenAddrTLS, config.CertFile, config.KeyFile, config.mux)
}) })
} }
if config.ListenAddr != "" { if config.ListenAddr != "" && (config == &Global.HTTP || config.ListenAddr != Global.ListenAddr) {
g.Go(func() error { return http.ListenAndServe(config.ListenAddr, plugin) }) g.Go(func() error {
log.Info("🌐 http listen at ", Blink(config.ListenAddr))
return http.ListenAndServe(config.ListenAddr, config.mux)
})
} }
g.Go(func() error { g.Go(func() error {
<-ctx.Done() <-ctx.Done()

View File

@@ -1,5 +1,7 @@
package config package config
import "net/http"
type PublishConfig interface { type PublishConfig interface {
GetPublishConfig() *Publish GetPublishConfig() *Publish
} }
@@ -77,10 +79,12 @@ type Engine struct {
EnableRTP bool //启用RTP格式rtsp、gb18181等协议使用 EnableRTP bool //启用RTP格式rtsp、gb18181等协议使用
EnableFLV bool //开启FLV格式hdl协议使用 EnableFLV bool //开启FLV格式hdl协议使用
} }
func (cfg *Engine) OnEvent(event any) {
}
var Global = &Engine{ var Global = &Engine{
Publish{true, true, false, 10, 0}, Publish{true, true, false, 10, 0},
Subscribe{true, true, false, 10}, Subscribe{true, true, false, 10},
HTTP{ListenAddr: ":8080", CORS: true}, HTTP{ListenAddr: ":8080", CORS: true, mux: http.DefaultServeMux},
false, true, true, true, false, true, true, true,
} }

12
go.mod
View File

@@ -8,6 +8,7 @@ require (
github.com/logrusorgru/aurora v2.0.3+incompatible github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/pion/rtp v1.7.4 github.com/pion/rtp v1.7.4
github.com/q191201771/naza v0.19.1 github.com/q191201771/naza v0.19.1
github.com/shirou/gopsutil/v3 v3.22.1
go.uber.org/zap v1.21.0 go.uber.org/zap v1.21.0
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
@@ -21,4 +22,13 @@ require (
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
) )
require github.com/pion/randutil v0.1.0 // indirect require (
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/tklauser/go-sysconf v0.3.9 // indirect
github.com/tklauser/numcpus v0.3.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 // indirect
)

31
go.sum
View File

@@ -9,12 +9,18 @@ github.com/cnotch/queue v0.0.0-20200326024423-6e88bdbf2ad4/go.mod h1:zOssjAlNusO
github.com/cnotch/queue v0.0.0-20201224060551-4191569ce8f6/go.mod h1:zOssjAlNusOxvtaqT+EMA+Iyi8rrtKr4/XfzN1Fgoeg= github.com/cnotch/queue v0.0.0-20201224060551-4191569ce8f6/go.mod h1:zOssjAlNusOxvtaqT+EMA+Iyi8rrtKr4/XfzN1Fgoeg=
github.com/cnotch/scheduler v0.0.0-20200522024700-1d2da93eefc5/go.mod h1:F4GE3SZkJZ8an1Y0ZCqvSM3jeozNuKzoC67erG1PhIo= github.com/cnotch/scheduler v0.0.0-20200522024700-1d2da93eefc5/go.mod h1:F4GE3SZkJZ8an1Y0ZCqvSM3jeozNuKzoC67erG1PhIo=
github.com/cnotch/xlog v0.0.0-20201208005456-cfda439cd3a0/go.mod h1:RW9oHsR79ffl3sR3yMGgxYupMn2btzdtJUwoxFPUE5E= github.com/cnotch/xlog v0.0.0-20201208005456-cfda439cd3a0/go.mod h1:RW9oHsR79ffl3sR3yMGgxYupMn2btzdtJUwoxFPUE5E=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emitter-io/address v1.0.0/go.mod h1:GfZb5+S/o8694B1GMGK2imUYQyn2skszMvGNA5D84Ug= github.com/emitter-io/address v1.0.0/go.mod h1:GfZb5+S/o8694B1GMGK2imUYQyn2skszMvGNA5D84Ug=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@@ -24,11 +30,15 @@ github.com/kelindar/rate v1.0.0/go.mod h1:AjT4G+hTItNwt30lucEGZIz8y7Uk5zPho6vurI
github.com/kelindar/tcp v1.0.0/go.mod h1:JB5hj1cshLU60XrLij2BBxW3JQ4hOye8vqbyvuKb52k= github.com/kelindar/tcp v1.0.0/go.mod h1:JB5hj1cshLU60XrLij2BBxW3JQ4hOye8vqbyvuKb52k=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -42,9 +52,14 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/q191201771/naza v0.19.1 h1:4KLcxT2CHztO+7miPRtBG3FFgadSQYQw1gPPPKN7rnY= github.com/q191201771/naza v0.19.1 h1:4KLcxT2CHztO+7miPRtBG3FFgadSQYQw1gPPPKN7rnY=
github.com/q191201771/naza v0.19.1/go.mod h1:5LeGupZZFtYP1g/S203n9vXoUNVdlRnPIfM6rExjqt0= github.com/q191201771/naza v0.19.1/go.mod h1:5LeGupZZFtYP1g/S203n9vXoUNVdlRnPIfM6rExjqt0=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/shirou/gopsutil/v3 v3.22.1 h1:33y31Q8J32+KstqPfscvFwBlNJ6xLaBy4xqBXzlYV5w=
github.com/shirou/gopsutil/v3 v3.22.1/go.mod h1:WapW1AOOPlHyXr+yOyw3uYx36enocrtSoSBy0L5vUHY=
github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518/go.mod h1:CKI4AZ4XmGV240rTHfO0hfE83S6/a3/Q1siZJ/vXf7A= github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518/go.mod h1:CKI4AZ4XmGV240rTHfO0hfE83S6/a3/Q1siZJ/vXf7A=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@@ -52,7 +67,13 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tklauser/go-sysconf v0.3.9 h1:JeUVdAOWhhxVcU6Eqr/ATFHgXk/mmiItdKeJPev3vTo=
github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
github.com/tklauser/numcpus v0.3.0 h1:ILuRUQBtssgnxw0XXIjKUC56fgnOrFoQQ/4+DeU2biQ=
github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
@@ -78,10 +99,15 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -92,10 +118,14 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
@@ -103,6 +133,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

22
http.go
View File

@@ -3,28 +3,22 @@ package engine
import ( import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"time"
. "github.com/logrusorgru/aurora"
"go.uber.org/zap"
"m7s.live/engine/v4/config" "m7s.live/engine/v4/config"
"m7s.live/engine/v4/log" "m7s.live/engine/v4/util"
) )
type GlobalConfig struct { type GlobalConfig struct {
*http.ServeMux
*config.Engine *config.Engine
} }
func (cfg *GlobalConfig) OnEvent(event any) { func (config *GlobalConfig) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
switch event.(type) { rw.Write([]byte("Monibuca API Server"))
case FirstConfig: }
log.Info(Green("api server start at"), BrightBlue(cfg.ListenAddr), BrightBlue(cfg.ListenAddrTLS))
cfg.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { func (config *GlobalConfig) API_summary(rw http.ResponseWriter, r *http.Request) {
log.Debug("visit", zap.String("path", "/"), zap.String("remote", r.RemoteAddr)) util.ReturnJson(summary.collect, time.Second, rw, r)
w.Write([]byte("Monibuca API Server"))
})
go cfg.Listen(Engine, cfg)
}
} }
func (config *GlobalConfig) API_sysInfo(rw http.ResponseWriter, r *http.Request) { func (config *GlobalConfig) API_sysInfo(rw http.ResponseWriter, r *http.Request) {

View File

@@ -8,7 +8,6 @@ import (
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"runtime" "runtime"
"time" "time"
@@ -30,13 +29,10 @@ var (
Plugins = make(map[string]*Plugin) // Plugins 所有的插件配置 Plugins = make(map[string]*Plugin) // Plugins 所有的插件配置
EngineConfig = &GlobalConfig{ EngineConfig = &GlobalConfig{
Engine: config.Global, Engine: config.Global,
ServeMux: http.DefaultServeMux,
} }
settingDir string //配置缓存目录,该目录按照插件名称作为文件名存储修改过的配置 settingDir string //配置缓存目录,该目录按照插件名称作为文件名存储修改过的配置
Engine = InstallPlugin(EngineConfig) //复用安装插件逻辑将全局配置信息注入并启动server Engine = InstallPlugin(EngineConfig) //复用安装插件逻辑将全局配置信息注入并启动server
toolManForGetHandlerFuncType http.HandlerFunc //专门用来获取HandlerFunc类型的工具人 MergeConfigs = []string{"Publish", "Subscribe", "HTTP"} //需要合并配置的属性项,插件若没有配置则使用全局配置
handlerFuncType = reflect.TypeOf(toolManForGetHandlerFuncType) //供反射使用的Handler类型的类型
MergeConfigs = []string{"Publish", "Subscribe"} //需要合并配置的属性项,插件若没有配置则使用全局配置
EventBus = make(chan any, 10) EventBus = make(chan any, 10)
) )
@@ -73,7 +69,7 @@ func Run(ctx context.Context, configFile string) (err error) {
Engine.registerHandler() Engine.registerHandler()
// 使得RawConfig具备全量配置信息用于合并到插件配置中 // 使得RawConfig具备全量配置信息用于合并到插件配置中
Engine.RawConfig = config.Struct2Config(EngineConfig.Engine) Engine.RawConfig = config.Struct2Config(EngineConfig.Engine)
go EngineConfig.OnEvent(FirstConfig(Engine.RawConfig)) go EngineConfig.Listen(Engine)
for name, plugin := range Plugins { for name, plugin := range Plugins {
plugin.RawConfig = cg.GetChild(name) plugin.RawConfig = cg.GetChild(name)
plugin.assign() plugin.assign()

View File

@@ -55,30 +55,28 @@ type Plugin struct {
*zap.Logger *zap.Logger
} }
func (opt *Plugin) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) { func (opt *Plugin) logHandler(pattern string, handler func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
return func(rw http.ResponseWriter, r *http.Request) {
opt.Debug("visit", zap.String("path", pattern), zap.String("remote", r.RemoteAddr))
handler(rw, r)
}
}
func (opt *Plugin) handleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
if opt == nil { if opt == nil {
return return
} }
var cors bool conf, ok := opt.Config.(config.HTTPConfig)
if v, ok := opt.RawConfig["cors"]; ok {
cors = v.(bool)
} else if EngineConfig.CORS {
cors = true
}
if !strings.HasPrefix(pattern, "/") { if !strings.HasPrefix(pattern, "/") {
pattern = "/" + pattern pattern = "/" + pattern
} }
opt.Info("http handle added:" + pattern)
if ok {
conf.HandleFunc(pattern, opt.logHandler(pattern, handler))
}
if opt != Engine { if opt != Engine {
pattern = "/" + strings.ToLower(opt.Name) + pattern pattern = "/" + strings.ToLower(opt.Name) + pattern
EngineConfig.HandleFunc(pattern, opt.logHandler(pattern, handler))
} }
opt.Info("http handle added:" + pattern)
EngineConfig.HandleFunc(pattern, func(rw http.ResponseWriter, r *http.Request) {
if cors {
util.CORS(rw, r)
}
opt.Debug("visit", zap.String("path", pattern), zap.String("remote", r.RemoteAddr))
handler(rw, r)
})
} }
// 读取独立配置合并入总配置中 // 读取独立配置合并入总配置中
@@ -111,6 +109,10 @@ func (opt *Plugin) assign() {
} }
} }
} }
if conf, ok := opt.Config.(config.HTTPConfig); ok {
httpConf := conf.GetHTTPConfig()
httpConf.InitMux()
}
opt.registerHandler() opt.registerHandler()
opt.run() opt.run()
} }
@@ -120,6 +122,12 @@ func (opt *Plugin) run() {
opt.RawConfig.Unmarshal(opt.Config) opt.RawConfig.Unmarshal(opt.Config)
opt.Debug("config", zap.Any("config", opt.Config)) opt.Debug("config", zap.Any("config", opt.Config))
opt.Config.OnEvent(FirstConfig(opt.RawConfig)) opt.Config.OnEvent(FirstConfig(opt.RawConfig))
if conf, ok := opt.Config.(config.HTTPConfig); ok {
httpconf := conf.GetHTTPConfig()
if httpconf.ListenAddr != "" && httpconf.ListenAddr != EngineConfig.ListenAddr {
go conf.Listen(opt)
}
}
} }
// Update 热更新配置 // Update 热更新配置
@@ -133,16 +141,13 @@ func (opt *Plugin) registerHandler() {
v := reflect.ValueOf(opt.Config) v := reflect.ValueOf(opt.Config)
// 注册http响应 // 注册http响应
for i, j := 0, t.NumMethod(); i < j; i++ { for i, j := 0, t.NumMethod(); i < j; i++ {
mt := t.Method(i) name := t.Method(i).Name
mv := v.Method(i) if handler, ok := v.Method(i).Interface().(func(http.ResponseWriter, *http.Request)); ok {
if mv.CanConvert(handlerFuncType) {
patten := "/" patten := "/"
if mt.Name != "ServeHTTP" { if name != "ServeHTTP" {
patten = strings.ToLower(strings.ReplaceAll(mt.Name, "_", "/")) patten = strings.ToLower(strings.ReplaceAll(name, "_", "/"))
} else if opt == Engine {
continue
} }
opt.HandleFunc(patten, mv.Interface().(func(http.ResponseWriter, *http.Request))) opt.handleFunc(patten, handler)
} }
} }
} }

View File

@@ -40,6 +40,8 @@ type Puller struct {
} }
// 是否需要重连 // 是否需要重连
func (pub *Puller) Reconnect() bool { func (pub *Puller) Reconnect() (ok bool) {
return pub.Config.RePull == -1 || pub.ReConnectCount <= pub.Config.RePull ok = pub.Config.RePull == -1 || pub.ReConnectCount <= pub.Config.RePull
pub.ReConnectCount++
return
} }

123
summary.go Normal file
View File

@@ -0,0 +1,123 @@
package engine
import (
"sync/atomic"
"time"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/disk"
"github.com/shirou/gopsutil/v3/mem"
"github.com/shirou/gopsutil/v3/net"
"m7s.live/engine/v4/log"
"m7s.live/engine/v4/util"
)
var summary Summary
var children util.Map[string, *Summary]
func init() {
children.Init()
go summary.Start()
}
// ServerSummary 系统摘要定义
type Summary struct {
Address string
Memory struct {
Total uint64
Free uint64
Used uint64
Usage float64
}
CPUUsage float64
HardDisk struct {
Total uint64
Free uint64
Used uint64
Usage float64
}
NetWork []NetWorkInfo
Streams []*Stream
lastNetWork []net.IOCountersStat
ref int32
}
// NetWorkInfo 网速信息
type NetWorkInfo struct {
Name string
Receive uint64
Sent uint64
ReceiveSpeed uint64
SentSpeed uint64
}
//StartSummary 开始定时采集数据,每秒一次
func (s *Summary) Start() {
for range time.Tick(time.Second) {
if s.ref > 0 {
summary.collect()
}
}
}
func (s *Summary) Point() *Summary {
return s
}
// Running 是否正在采集数据
func (s *Summary) Running() bool {
return s.ref > 0
}
// Add 增加订阅者
func (s *Summary) Add() {
if atomic.AddInt32(&s.ref, 1) == 1 {
log.Info("start report summary")
}
}
// Done 删除订阅者
func (s *Summary) Done() {
if atomic.AddInt32(&s.ref, -1) == 0 {
log.Info("stop report summary")
s.lastNetWork = nil
}
}
// Report 上报数据
func (s *Summary) Report(slave *Summary) {
children.Set(slave.Address, slave)
}
func (s *Summary) collect() *Summary{
v, _ := mem.VirtualMemory()
d, _ := disk.Usage("/")
nv, _ := net.IOCounters(true)
s.Memory.Total = v.Total >> 20
s.Memory.Free = v.Available >> 20
s.Memory.Used = v.Used >> 20
s.Memory.Usage = v.UsedPercent
if cc, _ := cpu.Percent(time.Second, false); len(cc) > 0 {
s.CPUUsage = cc[0]
}
s.HardDisk.Free = d.Free >> 30
s.HardDisk.Total = d.Total >> 30
s.HardDisk.Used = d.Used >> 30
s.HardDisk.Usage = d.UsedPercent
s.NetWork = []NetWorkInfo{}
for i, n := range nv {
info := NetWorkInfo{
Name: n.Name,
Receive: n.BytesRecv,
Sent: n.BytesSent,
}
if s.lastNetWork != nil && len(s.lastNetWork) > i {
info.ReceiveSpeed = n.BytesRecv - s.lastNetWork[i].BytesRecv
info.SentSpeed = n.BytesSent - s.lastNetWork[i].BytesSent
}
s.NetWork = append(s.NetWork, info)
}
s.lastNetWork = nv
s.Streams = Streams.ToList()
return s
}

View File

@@ -2,6 +2,8 @@ package util
import ( import (
"context" "context"
"crypto/sha256"
"crypto/subtle"
"encoding/json" "encoding/json"
"net" "net"
"net/http" "net/http"
@@ -69,7 +71,8 @@ func ListenUDP(address string, networkBuffer int) (*net.UDPConn, error) {
return conn, err return conn, err
} }
func CORS(w http.ResponseWriter, r *http.Request) { func CORS(next http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Credentials", "true") w.Header().Set("Access-Control-Allow-Credentials", "true")
origin := r.Header["Origin"] origin := r.Header["Origin"]
if len(origin) == 0 { if len(origin) == 0 {
@@ -77,4 +80,53 @@ func CORS(w http.ResponseWriter, r *http.Request) {
} else { } else {
w.Header().Set("Access-Control-Allow-Origin", origin[0]) w.Header().Set("Access-Control-Allow-Origin", origin[0])
} }
if next != nil {
next.ServeHTTP(w, r)
}
})
}
func BasicAuth(u, p string, next http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Extract the username and password from the request
// Authorization header. If no Authentication header is present
// or the header value is invalid, then the 'ok' return value
// will be false.
username, password, ok := r.BasicAuth()
if ok {
// Calculate SHA-256 hashes for the provided and expected
// usernames and passwords.
usernameHash := sha256.Sum256([]byte(username))
passwordHash := sha256.Sum256([]byte(password))
expectedUsernameHash := sha256.Sum256([]byte(u))
expectedPasswordHash := sha256.Sum256([]byte(p))
// 使用 subtle.ConstantTimeCompare() 进行校验
// the provided username and password hashes equal the
// expected username and password hashes. ConstantTimeCompare
// 如果值相等则返回1否则返回0。
// Importantly, we should to do the work to evaluate both the
// username and password before checking the return values to
// 避免泄露信息。
usernameMatch := (subtle.ConstantTimeCompare(usernameHash[:], expectedUsernameHash[:]) == 1)
passwordMatch := (subtle.ConstantTimeCompare(passwordHash[:], expectedPasswordHash[:]) == 1)
// If the username and password are correct, then call
// the next handler in the chain. Make sure to return
// afterwards, so that none of the code below is run.
if usernameMatch && passwordMatch {
if next != nil {
next.ServeHTTP(w, r)
}
return
}
}
// If the Authentication header is not present, is invalid, or the
// username or password is wrong, then set a WWW-Authenticate
// header to inform the client that we expect them to use basic
// authentication and send a 401 Unauthorized response.
w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
http.Error(w, "Unauthorized", http.StatusUnauthorized)
})
} }