-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhttp.go
138 lines (116 loc) · 2.94 KB
/
http.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
* Copyright (C) 2017 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package web
import (
"fmt"
"log"
"net"
"net/http"
"strings"
"time"
telnet "github.com/reiver/go-telnet"
)
var address = ":8080"
var listener net.Listener
var done chan bool
type tcpKeepAliveListener struct {
*net.TCPListener
}
// Accept accepts incoming tcp connections
func (ln tcpKeepAliveListener) Accept() (net.Conn, error) {
tc, err := ln.AcceptTCP()
if err != nil {
return tc, err
}
tc.SetKeepAlive(true)
tc.SetKeepAlivePeriod(3 * time.Minute)
return tc, nil
}
// listenAndServe starts http server in port 8080. Stops any previous one if needed
func listenAndServe(handler http.Handler) error {
if running() {
// stop previous instance before starting new one
err := stop()
if err != nil {
return fmt.Errorf("Could not stop the current running instance before starting a new one %v", err)
}
}
srv := &http.Server{Addr: address, Handler: handler}
// channel needed to communicate real server shutdown, as after calling listener.Close()
// it can take several milliseconds to really stop the listening.
done = make(chan bool)
var err error
listener, err = net.Listen("tcp", address)
if err != nil {
return err
}
// launch goroutine to check server state changes after startup is triggered
go func() {
retries := 10
idle := 10 * time.Millisecond
for ; !running() && retries > 0; retries-- {
time.Sleep(idle)
idle *= 2
}
if retries == 0 {
log.Print("Server could not be started")
return
}
}()
// launching server in a goroutine for not blocking
go func() {
if listener != nil {
err := srv.Serve(tcpKeepAliveListener{listener.(*net.TCPListener)})
if err != nil {
log.Printf("HTTP Server closing - %v", err)
}
// notify server real stop
done <- true
}
close(done)
}()
return nil
}
// stop stops current http server
func stop() error {
if !running() {
return fmt.Errorf("Already stopped")
}
if listener == nil {
return fmt.Errorf("Already closed")
}
err := listener.Close()
if err != nil {
return err
}
listener = nil
// wait for server real shutdown confirmation
<-done
return nil
}
func running() bool {
if strings.HasPrefix(address, ":") {
address = "localhost" + address
}
// telnet to check server is alive
caller := telnet.StandardCaller
err := telnet.DialToAndCall(address, caller)
if err != nil {
return false
}
return true
}