fix: #4
parent
7aec30d473
commit
f309009a76
|
@ -3,12 +3,14 @@ package main
|
|||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"kumoly.io/lib/klog"
|
||||
"kumoly.io/lib/ksrv"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"kumoly.io/lib/guard"
|
||||
"kumoly.io/tools/gterm"
|
||||
)
|
||||
|
||||
|
@ -27,17 +29,20 @@ var Version = "0.0.0"
|
|||
var Build = "alpha"
|
||||
|
||||
var (
|
||||
flagAllowIP string
|
||||
flagAllowIPNet string
|
||||
flagAppName string
|
||||
flagAddr string
|
||||
flagShell string
|
||||
flagDir string
|
||||
flagLogLevel int
|
||||
flagLogPretty bool
|
||||
flagDev bool
|
||||
flagVer bool
|
||||
flagArgs arrayFlags
|
||||
flagProfile bool
|
||||
flagSalt string
|
||||
flagUsr string
|
||||
flagPasswd string
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -47,11 +52,14 @@ func init() {
|
|||
flag.StringVar(&flagDir, "dir", "", "the working dir that the shell will start from")
|
||||
flag.Var(&flagArgs, "arg", "additional args to pass to cmd, multiple args can be passed, ex. -arg a -arg b")
|
||||
flag.BoolVar(&flagDev, "dev", false, "set the system to development mode")
|
||||
flag.IntVar(&flagLogLevel, "log-level", 9, "log level, error:1 debug:2 warn:4 info:8")
|
||||
flag.StringVar(&flagAllowIP, "allow", "", "restrict ip")
|
||||
flag.IntVar(&flagLogLevel, "log-level", 1, "log level [-1(trace):5(panic)] 7 to disable")
|
||||
flag.StringVar(&flagAllowIPNet, "allow", "", "restrict ip in a specific ip net")
|
||||
flag.BoolVar(&flagProfile, "profile", false, "print default profile, could be invoked with <(..)")
|
||||
flag.StringVar(&flagSalt, "salt", "", "add salt to encoded keyparam")
|
||||
flag.BoolVar(&flagVer, "v", false, "show version")
|
||||
flag.BoolVar(&flagLogPretty, "pretty", false, "log message in human readable format (the original log is json)")
|
||||
flag.StringVar(&flagUsr, "usr", "", "username, use basic auth for authentication if user and password are set")
|
||||
flag.StringVar(&flagPasswd, "passwd", "", "password, use basic auth for authentication if user and password are set")
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, "Usage: gterm [options]\n")
|
||||
|
@ -70,8 +78,18 @@ func main() {
|
|||
return
|
||||
}
|
||||
|
||||
klog.LEVEL = klog.Llevel(flagLogLevel)
|
||||
klog.PROD = !flagDev
|
||||
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
|
||||
zerolog.SetGlobalLevel(zerolog.Level(flagLogLevel))
|
||||
if flagLogPretty {
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{
|
||||
Out: os.Stdout,
|
||||
TimeFormat: "2006/01/02 15:04:05",
|
||||
})
|
||||
}
|
||||
if flagDev {
|
||||
log.Logger = log.With().Caller().Logger()
|
||||
}
|
||||
log.Logger = log.With().Str("mod", "gtrem").Logger()
|
||||
|
||||
g := gterm.New()
|
||||
g.AppName = flagAppName
|
||||
|
@ -80,33 +98,25 @@ func main() {
|
|||
g.Dir = flagDir
|
||||
g.Salt = flagSalt
|
||||
|
||||
gd := guard.New()
|
||||
if flagAllowIPNet != "" {
|
||||
_, ipnet, err := net.ParseCIDR(flagAllowIPNet)
|
||||
if err != nil {
|
||||
log.Panic().Err(err).Msg("")
|
||||
}
|
||||
gd.AllowIPNet = ipnet
|
||||
}
|
||||
if flagUsr != "" && flagPasswd != "" {
|
||||
gd.SetBasicAuth(flagUsr, flagPasswd)
|
||||
}
|
||||
|
||||
server := &http.Server{
|
||||
Addr: flagAddr,
|
||||
Handler: Middleware(g),
|
||||
Handler: gd.Guard(g),
|
||||
}
|
||||
klog.Info("gterm starting at ", flagAddr)
|
||||
log.Info().Msgf("gterm starting at %s", flagAddr)
|
||||
err := server.ListenAndServe()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Middleware(next http.Handler) http.Handler {
|
||||
log := klog.Sub(flagAppName)
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
ip := ksrv.GetIP(r)
|
||||
if flagAllowIP != "" {
|
||||
if !ksrv.MatchIPGlob(ip, flagAllowIP) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
w.Write([]byte("permission denied"))
|
||||
}
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
log.Debug(ip, " ", r.URL.String())
|
||||
})
|
||||
}
|
||||
|
|
4
go.mod
4
go.mod
|
@ -5,7 +5,8 @@ go 1.17
|
|||
require (
|
||||
github.com/creack/pty v1.1.17
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
kumoly.io/lib/klog v0.0.8
|
||||
github.com/rs/zerolog v1.26.0
|
||||
kumoly.io/lib/guard v0.1.1
|
||||
kumoly.io/lib/ksrv v0.0.2-0.20211112060911-0d61b343a298
|
||||
kumoly.io/lib/xorencrypt v0.1.0
|
||||
)
|
||||
|
@ -13,4 +14,5 @@ require (
|
|||
require (
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect
|
||||
kumoly.io/lib/klog v0.0.8 // indirect
|
||||
)
|
||||
|
|
33
go.sum
33
go.sum
|
@ -1,12 +1,45 @@
|
|||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
|
||||
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.26.0 h1:ORM4ibhEZeTeQlCojCK2kPz1ogAY4bGs4tD+SaAdGaE=
|
||||
github.com/rs/zerolog v1.26.0/go.mod h1:yBiM87lvSqX8h0Ww4sdzNSkVYZ8dL2xjZJG1lAuGZEo=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b h1:1VkfZQv42XQlA/jchYumAnv1UPo6RgF9rJFkTgZIxO4=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
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-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
kumoly.io/lib/guard v0.1.0 h1:PvFM0bcWbgfZQv4QfRwDmrK9FAjv9QYwfJY3Ffg6JA0=
|
||||
kumoly.io/lib/guard v0.1.0/go.mod h1:yWg9RDSI6YXkOPmP6Ad93aMqzlxhgW8LOe/ZRjjYX3U=
|
||||
kumoly.io/lib/guard v0.1.1 h1:aUcn0qVtX6TqRhp7bWSjIRlbWRWtuK0cjCArILTbAcY=
|
||||
kumoly.io/lib/guard v0.1.1/go.mod h1:yWg9RDSI6YXkOPmP6Ad93aMqzlxhgW8LOe/ZRjjYX3U=
|
||||
kumoly.io/lib/klog v0.0.8 h1:6hTfDlZh7KGnPrd2tUrauCKRImSnyyN9DHXpey3Czn8=
|
||||
kumoly.io/lib/klog v0.0.8/go.mod h1:Snm+c1xRrh/RbXsxQf7UGYbAJGPcIa6bEEN+CmzJh7M=
|
||||
kumoly.io/lib/ksrv v0.0.2-0.20211112060911-0d61b343a298 h1:0raqoIXmNpD6s1SrJbieAyIIkDyhe+aqfaXvx8wenrI=
|
||||
|
|
57
gterm.go
57
gterm.go
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
"github.com/creack/pty"
|
||||
"github.com/gorilla/websocket"
|
||||
"kumoly.io/lib/klog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"kumoly.io/lib/ksrv"
|
||||
"kumoly.io/lib/ksrv/engine"
|
||||
"kumoly.io/lib/xorencrypt"
|
||||
|
@ -75,13 +75,12 @@ func New() *GTerm {
|
|||
// }
|
||||
go func() {
|
||||
//print pool
|
||||
log := klog.Sub("gterm")
|
||||
for {
|
||||
cons := []string{}
|
||||
for k := range pool {
|
||||
cons = append(cons, k)
|
||||
}
|
||||
log.Info("current connections: ", cons)
|
||||
log.Info().Interface("connections", cons).Msg("")
|
||||
time.Sleep(5 * time.Minute)
|
||||
}
|
||||
}()
|
||||
|
@ -150,7 +149,7 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
|
|||
close(pool[id])
|
||||
delete(pool, id)
|
||||
}()
|
||||
l := klog.Sub(id)
|
||||
l := log.With().Str("id", id).Logger()
|
||||
|
||||
var cmd *exec.Cmd
|
||||
|
||||
|
@ -159,10 +158,10 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
|
|||
req := &NewCmdRequest{}
|
||||
err := json.Unmarshal([]byte(param), req)
|
||||
if err != nil {
|
||||
l.ErrorF(klog.H{"base": newCmd, "decrypt": param}, err)
|
||||
l.Error().Err(err).Str("base", newCmd).Str("decrypt", param).Msg("cmd decode failed")
|
||||
cmd = g.defaultCmd()
|
||||
} else {
|
||||
l.Info("starting cmd => ", l.M(fmt.Sprintf("%+v", req), klog.FgHiGreen))
|
||||
l.Info().Interface("cmd", req).Msg("starting cmd")
|
||||
cmd = exec.Command(req.Cmd, req.Args...)
|
||||
cmd.Env = append(req.Envs, "TERM=xterm-256color")
|
||||
cmd.Dir = req.Dir
|
||||
|
@ -178,28 +177,28 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
l.Error(err)
|
||||
l.Error().Err(err).Msg("upgrade error")
|
||||
return
|
||||
}
|
||||
l.Info("connection established.")
|
||||
l.Info().Msg("connection established.")
|
||||
|
||||
tty, err := pty.Start(cmd)
|
||||
if err != nil {
|
||||
l.Error(err)
|
||||
l.Error().Err(err).Msg("start tty error")
|
||||
conn.WriteMessage(websocket.TextMessage, []byte(err.Error()))
|
||||
}
|
||||
defer func() {
|
||||
if err := cmd.Process.Kill(); err != nil {
|
||||
l.Error(err)
|
||||
l.Error().Err(err).Msg("proccess kill error")
|
||||
}
|
||||
if _, err := cmd.Process.Wait(); err != nil {
|
||||
l.Error(err)
|
||||
l.Error().Err(err).Msg("proccess wait error")
|
||||
}
|
||||
if err := tty.Close(); err != nil {
|
||||
l.Error(err)
|
||||
l.Error().Err(err).Msg("tty close error")
|
||||
}
|
||||
if err := conn.Close(); err != nil {
|
||||
l.Error(err)
|
||||
l.Error().Err(err).Msg("conn close error")
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -215,16 +214,16 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
|
|||
go func() {
|
||||
for {
|
||||
if err := conn.WriteMessage(websocket.PingMessage, []byte("keepalive")); err != nil {
|
||||
l.Warn("failed to write ping message")
|
||||
l.Warn().Msg("failed to write ping message")
|
||||
return
|
||||
}
|
||||
time.Sleep(g.Timeout / 2)
|
||||
if time.Since(lastPongTime) > g.Timeout {
|
||||
l.Warn("failed to get response from ping, triggering disconnect now...")
|
||||
l.Warn().Msg("failed to get response from ping, triggering disconnect now...")
|
||||
waiter <- struct{}{}
|
||||
return
|
||||
}
|
||||
l.Debug("received response from ping successfully")
|
||||
l.Debug().Msg("received response from ping successfully")
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -242,19 +241,19 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
|
|||
buffer := make([]byte, g.BufferSize)
|
||||
readLength, err := tty.Read(buffer)
|
||||
if err != nil {
|
||||
l.Warn("failed to read from tty: ", err)
|
||||
l.Warn().Err(err).Msg("failed to read from tty")
|
||||
if err := conn.WriteMessage(websocket.TextMessage, []byte("bye!")); err != nil {
|
||||
l.Warn("failed to send termination message from tty to xterm.js: ", err)
|
||||
l.Warn().Err(err).Msg("failed to send termination message from tty to xterm.js")
|
||||
}
|
||||
waiter <- struct{}{}
|
||||
return
|
||||
}
|
||||
if err := conn.WriteMessage(websocket.BinaryMessage, buffer[:readLength]); err != nil {
|
||||
l.Warn("failed to send ", readLength, " bytes from tty to xterm.js")
|
||||
l.Warn().Msgf("failed to send %s bytes from tty to xterm.js", readLength)
|
||||
errorCounter++
|
||||
continue
|
||||
}
|
||||
l.Debug("sent message of size ", readLength, " bytes from tty to xterm.js")
|
||||
l.Debug().Msgf("sent message of size %s bytes from tty to xterm.js", readLength)
|
||||
errorCounter = 0
|
||||
}
|
||||
}()
|
||||
|
@ -266,7 +265,7 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
|
|||
messageType, data, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
if !connectionClosed {
|
||||
l.Warn("failed to get next reader: ", err)
|
||||
l.Warn().Err(err).Msg("failed to get next reader")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -276,11 +275,11 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
|
|||
if !ok {
|
||||
dataType = "uunknown"
|
||||
}
|
||||
l.Debug(fmt.Sprintf("received %s (type: %v) message of size %v byte(s) from xterm.js with key sequence: %v", dataType, messageType, dataLength, dataBuffer))
|
||||
l.Debug().Msgf("received %s (type: %v) message of size %v byte(s) from xterm.js with key sequence: %v", dataType, messageType, dataLength, dataBuffer)
|
||||
|
||||
// process
|
||||
if dataLength == -1 { // invalid
|
||||
l.Warn("failed to get the correct number of bytes read, ignoring message")
|
||||
l.Warn().Msg("failed to get the correct number of bytes read, ignoring message")
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -290,15 +289,15 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
|
|||
ttySize := &TTYSize{}
|
||||
resizeMessage := bytes.Trim(dataBuffer[1:], " \n\r\t\x00\x01")
|
||||
if err := json.Unmarshal(resizeMessage, ttySize); err != nil {
|
||||
l.Warn(fmt.Sprintf("failed to unmarshal received resize message '%s': %s", string(resizeMessage), err))
|
||||
l.Warn().Err(err).Msgf("failed to unmarshal received resize message '%s'", string(resizeMessage))
|
||||
continue
|
||||
}
|
||||
l.DebugF(klog.H{"rows": ttySize.Rows, "columns": ttySize.Cols}, "resizing tty...")
|
||||
l.Debug().Int("rows", int(ttySize.Rows)).Int("columns", int(ttySize.Cols)).Msg("resizing tty...")
|
||||
if err := pty.Setsize(tty, &pty.Winsize{
|
||||
Rows: ttySize.Rows,
|
||||
Cols: ttySize.Cols,
|
||||
}); err != nil {
|
||||
l.Warn("failed to resize tty, error: ", err)
|
||||
l.Warn().Err(err).Msg("failed to resize tty")
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
@ -307,16 +306,16 @@ func (g *GTerm) WS(w http.ResponseWriter, r *http.Request) {
|
|||
// write to tty
|
||||
bytesWritten, err := tty.Write(dataBuffer)
|
||||
if err != nil {
|
||||
l.Warn(fmt.Sprintf("failed to write %v bytes to tty: %s", len(dataBuffer), err))
|
||||
l.Warn().Err(err).Msgf("failed to write %v bytes to tty", len(dataBuffer))
|
||||
continue
|
||||
}
|
||||
l.Debug(bytesWritten, " bytes written to tty...")
|
||||
l.Debug().Msgf("%d bytes written to tty...", bytesWritten)
|
||||
}
|
||||
}()
|
||||
|
||||
<-waiter
|
||||
close(waiter)
|
||||
l.Info("closing connection...")
|
||||
l.Info().Msg("closing connection...")
|
||||
connectionClosed = true
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue