github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/integration/messagebus/glue/server.go (about)

     1  /*
     2   *  Glue - Robust Go and Javascript Socket Library
     3   *  Copyright (C) 2015  Roland Singer <roland.singer[at]desertbit.com>
     4   *
     5   *  This program is free software: you can redistribute it and/or modify
     6   *  it under the terms of the GNU General Public License as published by
     7   *  the Free Software Foundation, either version 3 of the License, or
     8   *  (at your option) any later version.
     9   *
    10   *  This program is distributed in the hope that it will be useful,
    11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   *  GNU General Public License for more details.
    14   *
    15   *  You should have received a copy of the GNU General Public License
    16   *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   */
    18  
    19  // Package glue - Robust Go and Javascript Socket Library.
    20  // This library is thread-safe.
    21  package glue
    22  
    23  import (
    24  	"fmt"
    25  	"net"
    26  	"net/http"
    27  	"sync"
    28  	"time"
    29  
    30  	"github.com/mdaxf/iac/integration/messagebus/glue/backend"
    31  	"github.com/mdaxf/iac/integration/messagebus/glue/log"
    32  )
    33  
    34  //####################//
    35  //### Public Types ###//
    36  //####################//
    37  
    38  // OnNewSocketFunc is an event function.
    39  type OnNewSocketFunc func(s *Socket)
    40  
    41  //###################//
    42  //### Server Type ###//
    43  //###################//
    44  
    45  // A Server represents a glue server which handles incoming socket connections.
    46  type Server struct {
    47  	bs      *backend.Server
    48  	options *Options
    49  
    50  	block       bool
    51  	blockMutex  sync.Mutex
    52  	onNewSocket OnNewSocketFunc
    53  
    54  	sockets      map[string]*Socket // A map holding all active current sockets.
    55  	socketsMutex sync.Mutex
    56  }
    57  
    58  // NewServer creates a new glue server instance.
    59  // One variadic arguments specifies the server options.
    60  func NewServer(o ...Options) *Server {
    61  	// Get or create the options.
    62  	var options *Options
    63  	if len(o) > 0 {
    64  		options = &o[0]
    65  	} else {
    66  		options = &Options{}
    67  	}
    68  
    69  	// Set the default option values for unset values.
    70  	options.SetDefaults()
    71  
    72  	// Create a new backend server.
    73  	bs := backend.NewServer(len(options.HTTPHandleURL), options.EnableCORS, options.CheckOrigin)
    74  
    75  	// Create a new server value.
    76  	s := &Server{
    77  		bs:          bs,
    78  		options:     options,
    79  		onNewSocket: func(*Socket) {}, // Initialize with dummy function to remove nil check.
    80  		sockets:     make(map[string]*Socket),
    81  	}
    82  
    83  	// Set the backend server event function.
    84  	bs.OnNewSocketConnection(s.handleOnNewSocketConnection)
    85  
    86  	return s
    87  }
    88  
    89  // Block new incomming connections.
    90  func (s *Server) Block(b bool) {
    91  	s.blockMutex.Lock()
    92  	defer s.blockMutex.Unlock()
    93  
    94  	s.block = b
    95  }
    96  
    97  // IsBlocked returns a boolean whenever new incoming connections should be blocked.
    98  func (s *Server) IsBlocked() bool {
    99  	s.blockMutex.Lock()
   100  	defer s.blockMutex.Unlock()
   101  
   102  	return s.block
   103  }
   104  
   105  // OnNewSocket sets the event function which is
   106  // triggered if a new socket connection was made.
   107  // The event function must not block! As soon as the event function
   108  // returns, the socket is added to the active sockets map.
   109  func (s *Server) OnNewSocket(f OnNewSocketFunc) {
   110  	s.onNewSocket = f
   111  }
   112  
   113  // GetSocket obtains a socket by its ID.
   114  // Returns nil if not found.
   115  func (s *Server) GetSocket(id string) *Socket {
   116  	// Lock the mutex.
   117  	s.socketsMutex.Lock()
   118  	defer s.socketsMutex.Unlock()
   119  
   120  	// Obtain the socket.
   121  	socket, ok := s.sockets[id]
   122  	if !ok {
   123  		return nil
   124  	}
   125  
   126  	return socket
   127  }
   128  
   129  // Sockets returns a list of all current connected sockets.
   130  // Hint: Sockets are added to the active sockets list before the OnNewSocket
   131  // event function is called.
   132  // Use the IsInitialized flag to determind if a socket is not ready yet...
   133  func (s *Server) Sockets() []*Socket {
   134  	// Lock the mutex.
   135  	s.socketsMutex.Lock()
   136  	defer s.socketsMutex.Unlock()
   137  
   138  	// Create the slice.
   139  	list := make([]*Socket, len(s.sockets))
   140  
   141  	// Add all sockets from the map.
   142  	i := 0
   143  	for _, s := range s.sockets {
   144  		list[i] = s
   145  		i++
   146  	}
   147  
   148  	return list
   149  }
   150  
   151  // Release this package. This will block all new incomming socket connections
   152  // and close all current connected sockets.
   153  func (s *Server) Release() {
   154  	// Block all new incomming socket connections.
   155  	s.Block(true)
   156  
   157  	// Wait for a little moment, so new incomming sockets are added
   158  	// to the sockets active list.
   159  	time.Sleep(200 * time.Millisecond)
   160  
   161  	// Close all current connected sockets.
   162  	sockets := s.Sockets()
   163  	for _, s := range sockets {
   164  		s.Close()
   165  	}
   166  }
   167  
   168  // Run starts the server and listens for incoming socket connections.
   169  // This is a blocking method.
   170  func (s *Server) Run() error {
   171  	// Skip if set to none.
   172  	log.L.Debug("start the glue server")
   173  	log.L.Debug("HTTPSocketType: %v", s.options.HTTPSocketType)
   174  	log.L.Debug("HTTPHandleURL: %v", s.options.HTTPHandleURL)
   175  	if s.options.HTTPSocketType != HTTPSocketTypeNone {
   176  		// Set the base glue HTTP handler.
   177  		http.Handle(s.options.HTTPHandleURL, s)
   178  
   179  		// Start the http server.
   180  		if s.options.HTTPSocketType == HTTPSocketTypeUnix {
   181  			// Listen on the unix socket.
   182  			l, err := net.Listen("unix", s.options.HTTPListenAddress)
   183  			if err != nil {
   184  				return fmt.Errorf("Listen: %v", err)
   185  			}
   186  
   187  			// Start the http server.
   188  			err = http.Serve(l, nil)
   189  			if err != nil {
   190  				return fmt.Errorf("Serve: %v", err)
   191  			}
   192  		} else if s.options.HTTPSocketType == HTTPSocketTypeTCP {
   193  			// Start the http server.
   194  			err := http.ListenAndServe(s.options.HTTPListenAddress, nil)
   195  			if err != nil {
   196  				return fmt.Errorf("ListenAndServe: %v", err)
   197  			}
   198  		} else {
   199  			return fmt.Errorf("invalid socket options type: %v", s.options.HTTPSocketType)
   200  		}
   201  	} else {
   202  		// HINT: This is only a placeholder until the internal glue TCP server is implemented.
   203  		w := make(chan struct{})
   204  		<-w
   205  	}
   206  
   207  	return nil
   208  }
   209  
   210  // ServeHTTP implements the HTTP Handler interface of the http package.
   211  func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
   212  	s.bs.ServeHTTP(w, r)
   213  }
   214  
   215  //########################//
   216  //### Server - Private ###//
   217  //########################//
   218  
   219  func (s *Server) handleOnNewSocketConnection(bs backend.BackendSocket) {
   220  	// Close the socket if incomming connections should be blocked.
   221  	if s.IsBlocked() {
   222  		bs.Close()
   223  		return
   224  	}
   225  
   226  	// Create a new socket value.
   227  	// The goroutines are started automatically.
   228  	newSocket(s, bs)
   229  }