github.com/ssetin/penguincast@v0.2.0/src/server/server.go (about)

     1  // Package iceserver - icecast streaming server
     2  package iceserver
     3  
     4  import (
     5  	"context"
     6  	"log"
     7  	"net/http"
     8  	"os"
     9  	"os/signal"
    10  	"path"
    11  	"strconv"
    12  	"strings"
    13  	"sync"
    14  	"sync/atomic"
    15  	"time"
    16  
    17  	"github.com/ssetin/PenguinCast/src/fastStat"
    18  )
    19  
    20  const (
    21  	cServerName = "PenguinCast"
    22  	cVersion    = "0.2.0"
    23  )
    24  
    25  var (
    26  	vCommands = [...]string{"metadata"}
    27  )
    28  
    29  // IceServer ...
    30  type IceServer struct {
    31  	serverName string
    32  	version    string
    33  
    34  	Props Properties
    35  
    36  	mux            sync.Mutex
    37  	Started        int32
    38  	StartedTime    time.Time
    39  	ListenersCount int32
    40  	SourcesCount   int32
    41  
    42  	statReader fastStat.ProcStatsReader
    43  	// for monitor
    44  	cpuUsage float64
    45  	memUsage int
    46  
    47  	srv           *http.Server
    48  	poolManager   PoolManager
    49  	logError      *log.Logger
    50  	logErrorFile  *os.File
    51  	logAccess     *log.Logger
    52  	logAccessFile *os.File
    53  	statFile      *os.File
    54  }
    55  
    56  // Init - Load params from config.json
    57  func (i *IceServer) Init() error {
    58  	var err error
    59  
    60  	i.serverName = cServerName
    61  	i.version = cVersion
    62  
    63  	i.ListenersCount = 0
    64  	i.SourcesCount = 0
    65  	i.Started = 0
    66  
    67  	log.Println("Init " + i.serverName + " " + i.version)
    68  
    69  	err = i.initConfig()
    70  	if err != nil {
    71  		return err
    72  	}
    73  	err = i.initLog()
    74  	if err != nil {
    75  		return err
    76  	}
    77  	err = i.initMounts()
    78  	if err != nil {
    79  		return err
    80  	}
    81  
    82  	i.srv = &http.Server{
    83  		Addr: ":" + strconv.Itoa(i.Props.Socket.Port),
    84  	}
    85  
    86  	if i.Props.Logging.UseStat {
    87  		i.statReader.Init()
    88  		go i.processStats()
    89  	}
    90  
    91  	return nil
    92  }
    93  
    94  func (i *IceServer) initMounts() error {
    95  	var err error
    96  	for idx := range i.Props.Mounts {
    97  		err = i.Props.Mounts[idx].Init(i)
    98  		if err != nil {
    99  			return err
   100  		}
   101  	}
   102  	return nil
   103  }
   104  
   105  func (i *IceServer) incListeners() {
   106  	atomic.AddInt32(&i.ListenersCount, 1)
   107  }
   108  
   109  func (i *IceServer) decListeners() {
   110  	if atomic.LoadInt32(&i.ListenersCount) > 0 {
   111  		atomic.AddInt32(&i.ListenersCount, -1)
   112  	}
   113  }
   114  
   115  func (i *IceServer) checkListeners() bool {
   116  	clientsLimit := atomic.LoadInt32(&i.Props.Limits.Clients)
   117  	if atomic.LoadInt32(&i.ListenersCount) > clientsLimit {
   118  		return false
   119  	}
   120  	return true
   121  }
   122  
   123  func (i *IceServer) incSources() {
   124  	atomic.AddInt32(&i.SourcesCount, 1)
   125  }
   126  
   127  func (i *IceServer) decSources() {
   128  	if atomic.LoadInt32(&i.SourcesCount) > 0 {
   129  		atomic.AddInt32(&i.SourcesCount, -1)
   130  	}
   131  }
   132  
   133  func (i *IceServer) checkSources() bool {
   134  	sourcesLimit := atomic.LoadInt32(&i.Props.Limits.Sources)
   135  	if atomic.LoadInt32(&i.SourcesCount) > sourcesLimit {
   136  		return false
   137  	}
   138  	return true
   139  }
   140  
   141  // Close - finish
   142  func (i *IceServer) Close() {
   143  
   144  	if err := i.srv.Shutdown(context.Background()); err != nil {
   145  		i.printError(1, err.Error())
   146  		log.Printf("Error: %s\n", err.Error())
   147  	} else {
   148  		log.Println("Stopped")
   149  	}
   150  
   151  	for idx := range i.Props.Mounts {
   152  		i.Props.Mounts[idx].Close()
   153  	}
   154  
   155  	i.statReader.Close()
   156  	i.logErrorFile.Close()
   157  	i.logAccessFile.Close()
   158  	if i.statFile != nil {
   159  		i.statFile.Close()
   160  	}
   161  }
   162  
   163  func (i *IceServer) checkIsMount(page string) int {
   164  	for idx := range i.Props.Mounts {
   165  		if i.Props.Mounts[idx].Name == page {
   166  			return idx
   167  		}
   168  	}
   169  	return -1
   170  }
   171  
   172  func (i *IceServer) checkIsCommand(page string, r *http.Request) int {
   173  	for idx := range vCommands {
   174  		if vCommands[idx] == page && r.URL.Query().Get("mode") == "updinfo" {
   175  			return idx
   176  		}
   177  	}
   178  	return -1
   179  }
   180  
   181  func (i *IceServer) handler(w http.ResponseWriter, r *http.Request) {
   182  	if i.Props.Logging.Loglevel == 4 {
   183  		i.logHeaders(w, r)
   184  	}
   185  
   186  	page, mountidx, cmdidx, err := i.checkPage(w, r)
   187  	if err != nil {
   188  		i.printError(1, err.Error())
   189  		return
   190  	}
   191  
   192  	if mountidx >= 0 {
   193  		i.openMount(mountidx, w, r)
   194  		return
   195  	}
   196  
   197  	if cmdidx >= 0 {
   198  		i.runCommand(cmdidx, w, r)
   199  		return
   200  	}
   201  
   202  	if strings.HasSuffix(page, "info.html") || strings.HasSuffix(page, "info.json") || strings.HasSuffix(page, "monitor.html") {
   203  		i.renderPage(w, r, page)
   204  	} else {
   205  		http.ServeFile(w, r, page)
   206  	}
   207  }
   208  
   209  /*
   210  	runCommand
   211  */
   212  func (i *IceServer) runCommand(idx int, w http.ResponseWriter, r *http.Request) {
   213  	if idx == 0 {
   214  		mountname := path.Base(r.URL.Query().Get("mount"))
   215  		i.printError(4, "runCommand 0 with "+mountname)
   216  		midx := i.checkIsMount(mountname)
   217  		if midx >= 0 {
   218  			i.Props.Mounts[midx].updateMeta(w, r)
   219  		}
   220  	}
   221  
   222  }
   223  
   224  func (i *IceServer) wrapHandlerWithStreaming(wrappedHandler http.Handler) http.Handler {
   225  	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
   226  		//streamWriter := newStreamResponseWritter(w)
   227  		wrappedHandler.ServeHTTP(w, req)
   228  	})
   229  }
   230  
   231  /*Start - start listening port ...*/
   232  func (i *IceServer) Start() {
   233  	if atomic.LoadInt32(&i.Started) == 1 {
   234  		return
   235  	}
   236  
   237  	stop := make(chan os.Signal, 1)
   238  	signal.Notify(stop, os.Interrupt, os.Kill)
   239  
   240  	if i.Props.Logging.UseMonitor {
   241  		http.HandleFunc("/updateMonitor", func(w http.ResponseWriter, r *http.Request) {
   242  			ws, err := upgrader.Upgrade(w, r, nil)
   243  			if err != nil {
   244  				log.Fatal(err)
   245  			}
   246  			go i.sendMonitorInfo(ws)
   247  		})
   248  	}
   249  
   250  	//streamedHandler := i.wrapHandlerWithStreaming(http.HandlerFunc(i.handler))
   251  	//http.Handle("/", streamedHandler)
   252  	http.HandleFunc("/", i.handler)
   253  
   254  	go func() {
   255  		i.mux.Lock()
   256  		i.StartedTime = time.Now()
   257  		i.mux.Unlock()
   258  		atomic.StoreInt32(&i.Started, 1)
   259  		log.Print("Started on " + i.srv.Addr)
   260  
   261  		if err := i.srv.ListenAndServe(); err != http.ErrServerClosed {
   262  			log.Fatal(err)
   263  		}
   264  
   265  	}()
   266  
   267  	<-stop
   268  	atomic.StoreInt32(&i.Started, 0)
   269  }