github.com/Ryan-Johnson-1315/socketlogger@v0.0.2/server.go (about)

     1  package socketlogger
     2  
     3  import (
     4  	"bufio"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"log"
     9  	"net"
    10  	"time"
    11  )
    12  
    13  type Server interface {
    14  	Bind(c Connection) error
    15  	Shutdown()
    16  
    17  	start()
    18  	buildSocket(c Connection) (net.Conn, error)
    19  	listenForMsgsOnSocket(sock net.Conn, msgs chan SocketMessage)
    20  	getMessageType() SocketMessage
    21  	init(interface{})
    22  	write(chan SocketMessage) // Either log file, csv file or console, implemented in server type
    23  	setFlushChannel(chan bool)
    24  }
    25  
    26  type server struct {
    27  	comms
    28  	msgs         chan SocketMessage
    29  	this         interface{}
    30  	closeSockets chan bool // This channel will notify to close the sockets
    31  	flushed      chan bool // This makes Shutdown() blocking, allowing everything to be written to console/log file
    32  }
    33  
    34  func (s *server) Bind(c Connection) error {
    35  	var err error = nil
    36  	s.sock, err = s.this.(Server).buildSocket(c)
    37  	if err != nil {
    38  		return err
    39  	} else {
    40  		s.start()
    41  		return nil
    42  	}
    43  }
    44  
    45  func (s *server) Shutdown() {
    46  	close(s.closeSockets)
    47  	close(s.msgs) // Notifies writer to finish writing
    48  	<-s.flushed   // Waits for writer to flush all data
    49  }
    50  
    51  func (s *server) init(i interface{}) {
    52  	if inst, ok := i.(Server); !ok {
    53  		panic(fmt.Errorf("instance is not of type Server! Type: %T", inst))
    54  	} else {
    55  		s.msgs = make(chan SocketMessage, 100)
    56  		s.this = i
    57  		s.closeSockets = make(chan bool)
    58  		s.flushed = make(chan bool)
    59  	}
    60  }
    61  
    62  func (s *server) start() {
    63  	s.this.(Server).setFlushChannel(s.flushed)
    64  	go s.this.(Server).write(s.msgs)
    65  	go s.listenForMsgsOnSocket(s.comms.sock, s.msgs)
    66  }
    67  
    68  func (s *server) listenForMsgsOnSocket(sock net.Conn, msgs chan SocketMessage) {
    69  	if sock != nil {
    70  		reader := bufio.NewReaderSize(sock, bufSize)
    71  		dec := json.NewDecoder(reader)
    72  		inst, ok := s.this.(Server)
    73  		if !ok {
    74  			panic(fmt.Errorf("server is not a Sever type. Type %T", inst))
    75  		}
    76  
    77  		decoded := make(chan SocketMessage, 100)
    78  		running := true
    79  		socketDisconnected := make(chan bool)
    80  		go func() {
    81  			for {
    82  				msg := inst.getMessageType()
    83  				if err := dec.Decode(&msg); err != nil {
    84  					if running && err == io.EOF {
    85  						time.Sleep(50 * time.Nanosecond) // Make sure this message gets printed last
    86  						s.msgs <- newLogMessage(MessageLevelDbg, "Socket disconnected %s", sock.RemoteAddr())
    87  					} else if running {
    88  						s.msgs <- newLogMessage(MessageLevelErr, "ERROR!! %v, unexpected error: %v", err, running)
    89  					}
    90  					sock.Close()
    91  					break
    92  				} else {
    93  					decoded <- msg
    94  				}
    95  			}
    96  			socketDisconnected <- true
    97  		}()
    98  
    99  	L:
   100  		for {
   101  			select {
   102  			case msg := <-decoded:
   103  				msgs <- msg
   104  			case <-s.closeSockets:
   105  				running = false
   106  				break L
   107  			}
   108  		}
   109  		sock.Close()
   110  		<-socketDisconnected
   111  	}
   112  }
   113  
   114  type udpserver struct {
   115  	server
   116  }
   117  
   118  func (u *udpserver) buildSocket(c Connection) (net.Conn, error) {
   119  	sock, err := net.ListenUDP(udpProtocol, &net.UDPAddr{
   120  		IP:   net.ParseIP(c.Addr),
   121  		Port: c.Port,
   122  	})
   123  	if err != nil {
   124  		log.Println(newLogMessage(MessageLevelErr, "Could not create %s: %v", "UDP Server", err))
   125  	} else {
   126  		log.Println(newLogMessage(MessageLevelSuccess, "%s listening at %s", "UDP Server", sock.LocalAddr()))
   127  	}
   128  
   129  	return sock, err
   130  }
   131  
   132  type tcpserver struct {
   133  	server
   134  }
   135  
   136  // Satisfies Server interface
   137  func (t *tcpserver) buildSocket(c Connection) (net.Conn, error) {
   138  	var err error
   139  	var listener net.Listener
   140  	listener, err = net.Listen("tcp", fmt.Sprintf("%v:%d", c.Addr, c.Port))
   141  	if err == nil {
   142  		log.Println(newLogMessage(MessageLevelSuccess, "%s listening at %s:%d", "TCP Server", c.Addr, c.Port))
   143  		go func() {
   144  			defer listener.Close()
   145  			for {
   146  				// Listen for an incoming connection.
   147  				conn, err := listener.Accept()
   148  				if err != nil {
   149  					log.Println(newLogMessage(MessageLevelErr, "Error accepting: %v", err.Error()).String())
   150  					continue
   151  				}
   152  
   153  				go t.this.(Server).listenForMsgsOnSocket(conn, t.msgs)
   154  			}
   155  		}()
   156  	}
   157  
   158  	return nil, err
   159  }