|
@@ -0,0 +1,114 @@
|
|
|
+package go-server
|
|
|
+import (
|
|
|
+ "errors"
|
|
|
+ "fmt"
|
|
|
+ "net"
|
|
|
+ "net/http"
|
|
|
+ "os"
|
|
|
+ "os/signal"
|
|
|
+ "sync"
|
|
|
+ "syscall"
|
|
|
+ "time"
|
|
|
+)
|
|
|
+
|
|
|
+type StoppableListener struct {
|
|
|
+ *net.TCPListener //Wrapped listener
|
|
|
+ stop chan int //Channel used only to indicate listener should shutdown
|
|
|
+}
|
|
|
+
|
|
|
+var quit chan os.Signal
|
|
|
+
|
|
|
+func New(l net.Listener) (*StoppableListener, error) {
|
|
|
+ tcpL, ok := l.(*net.TCPListener)
|
|
|
+
|
|
|
+ if !ok {
|
|
|
+ return nil, errors.New("Cannot wrap listener")
|
|
|
+ }
|
|
|
+
|
|
|
+ retval := &StoppableListener{}
|
|
|
+ retval.TCPListener = tcpL
|
|
|
+ retval.stop = make(chan int)
|
|
|
+
|
|
|
+ return retval, nil
|
|
|
+}
|
|
|
+
|
|
|
+var StoppedError = errors.New("Listener stopped")
|
|
|
+
|
|
|
+func (sl *StoppableListener) Accept() (net.Conn, error) {
|
|
|
+
|
|
|
+ for {
|
|
|
+ //Wait up to one second for a new connection
|
|
|
+ sl.SetDeadline(time.Now().Add(time.Second))
|
|
|
+
|
|
|
+ newConn, err := sl.TCPListener.Accept()
|
|
|
+
|
|
|
+ //Check for the channel being closed
|
|
|
+ select {
|
|
|
+ case <-sl.stop:
|
|
|
+ return nil, StoppedError
|
|
|
+ default:
|
|
|
+ //If the channel is still open, continue as normal
|
|
|
+ }
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ netErr, ok := err.(net.Error)
|
|
|
+
|
|
|
+ //If this is a timeout, then continue to wait for
|
|
|
+ //new connections
|
|
|
+ if ok && netErr.Timeout() && netErr.Temporary() {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return newConn, err
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (sl *StoppableListener) Stop() {
|
|
|
+ close(sl.stop)
|
|
|
+}
|
|
|
+
|
|
|
+func TerminateServer() {
|
|
|
+ quit <- syscall.SIGTERM
|
|
|
+}
|
|
|
+
|
|
|
+func Start(port string, r http.Handler) {
|
|
|
+ orgLst, err := net.Listen("tcp", ":"+port)
|
|
|
+ if err != nil {
|
|
|
+ panic(err)
|
|
|
+ }
|
|
|
+
|
|
|
+ sl, err := New(orgLst)
|
|
|
+ if err != nil {
|
|
|
+ panic(err)
|
|
|
+ }
|
|
|
+
|
|
|
+ server := http.Server{
|
|
|
+ Handler: r,
|
|
|
+ ReadTimeout: 5 * time.Second,
|
|
|
+ WriteTimeout: 10 * time.Second,
|
|
|
+ }
|
|
|
+ server.SetKeepAlivesEnabled(false)
|
|
|
+
|
|
|
+ quit = make(chan os.Signal)
|
|
|
+ signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
|
|
+ var wg sync.WaitGroup
|
|
|
+ go func(wg sync.WaitGroup) {
|
|
|
+ wg.Add(1)
|
|
|
+ defer wg.Done()
|
|
|
+ server.Serve(sl)
|
|
|
+ }(wg)
|
|
|
+
|
|
|
+ fmt.Printf("Started at port : " + port + "\n")
|
|
|
+ select {
|
|
|
+ case signal := <-quit:
|
|
|
+ // wait for a few seconds
|
|
|
+ time.Sleep(1000 * time.Millisecond)
|
|
|
+ fmt.Printf("Got signal:%v\n", signal)
|
|
|
+ }
|
|
|
+ fmt.Printf("Stopping listener\n")
|
|
|
+ sl.Stop()
|
|
|
+ fmt.Printf("Waiting on server\n")
|
|
|
+ wg.Wait()
|
|
|
+}
|
|
|
+
|