github.com/wtsi-ssg/wrstat/v4@v4.5.1/server/server.go (about)

     1  /*******************************************************************************
     2   * Copyright (c) 2022 Genome Research Ltd.
     3   *
     4   * Authors:
     5   *	- Sendu Bala <sb10@sanger.ac.uk>
     6   *
     7   * Permission is hereby granted, free of charge, to any person obtaining
     8   * a copy of this software and associated documentation files (the
     9   * "Software"), to deal in the Software without restriction, including
    10   * without limitation the rights to use, copy, modify, merge, publish,
    11   * distribute, sublicense, and/or sell copies of the Software, and to
    12   * permit persons to whom the Software is furnished to do so, subject to
    13   * the following conditions:
    14   *
    15   * The above copyright notice and this permission notice shall be included
    16   * in all copies or substantial portions of the Software.
    17   *
    18   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    19   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    20   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    21   * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    22   * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    23   * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    24   * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    25   ******************************************************************************/
    26  
    27  // package server provides a web server for a REST API and website.
    28  
    29  package server
    30  
    31  import (
    32  	"embed"
    33  	"io"
    34  	"sync"
    35  	"time"
    36  
    37  	gas "github.com/wtsi-hgi/go-authserver"
    38  	"github.com/wtsi-ssg/wrstat/v4/basedirs"
    39  	"github.com/wtsi-ssg/wrstat/v4/dgut"
    40  	"github.com/wtsi-ssg/wrstat/v4/watch"
    41  )
    42  
    43  //go:embed static
    44  var staticFS embed.FS
    45  
    46  const (
    47  	wherePath = "/where"
    48  
    49  	// EndPointWhere is the endpoint for making where queries if authorization
    50  	// isn't implemented.
    51  	EndPointWhere = gas.EndPointREST + wherePath
    52  
    53  	// EndPointAuthWhere is the endpoint for making where queries if
    54  	// authorization is implemented.
    55  	EndPointAuthWhere = gas.EndPointAuth + wherePath
    56  
    57  	groupAreasPaths = "/group-areas"
    58  
    59  	// EndPointAuthGroupAreas is the endpoint for making queries on what the
    60  	// group areas are, which is available if authorization is implemented.
    61  	EndPointAuthGroupAreas = gas.EndPointAuth + groupAreasPaths
    62  
    63  	basedirsPath            = "/basedirs"
    64  	basedirsUsagePath       = basedirsPath + "/usage"
    65  	basedirsGroupUsagePath  = basedirsUsagePath + "/groups"
    66  	basedirsUserUsagePath   = basedirsUsagePath + "/users"
    67  	basedirsSubdirPath      = basedirsPath + "/subdirs"
    68  	basedirsGroupSubdirPath = basedirsSubdirPath + "/group"
    69  	basedirsUserSubdirPath  = basedirsSubdirPath + "/user"
    70  	basedirsHistoryPath     = basedirsPath + "/history"
    71  
    72  	// EndPointBasedir* are the endpoints for making base directory related
    73  	// queries if authorization isn't implemented.
    74  	EndPointBasedirUsageGroup  = gas.EndPointREST + basedirsGroupUsagePath
    75  	EndPointBasedirUsageUser   = gas.EndPointREST + basedirsUserUsagePath
    76  	EndPointBasedirSubdirGroup = gas.EndPointREST + basedirsGroupSubdirPath
    77  	EndPointBasedirSubdirUser  = gas.EndPointREST + basedirsUserSubdirPath
    78  	EndPointBasedirHistory     = gas.EndPointREST + basedirsHistoryPath
    79  
    80  	// EndPointAuthBasedir* are the endpoints for making base directory related
    81  	// queries if authorization is implemented.
    82  	EndPointAuthBasedirUsageGroup  = gas.EndPointAuth + basedirsGroupUsagePath
    83  	EndPointAuthBasedirUsageUser   = gas.EndPointAuth + basedirsUserUsagePath
    84  	EndPointAuthBasedirSubdirGroup = gas.EndPointAuth + basedirsGroupSubdirPath
    85  	EndPointAuthBasedirSubdirUser  = gas.EndPointAuth + basedirsUserSubdirPath
    86  	EndPointAuthBasedirHistory     = gas.EndPointAuth + basedirsHistoryPath
    87  
    88  	// TreePath is the path to the static tree website.
    89  	TreePath = "/tree"
    90  
    91  	// EndPointAuthTree is the endpoint for making treemap queries when
    92  	// authorization is implemented.
    93  	EndPointAuthTree = gas.EndPointAuth + TreePath
    94  
    95  	defaultDir    = "/"
    96  	defaultSplits = "2"
    97  	unknown       = "#unknown"
    98  )
    99  
   100  // Server is used to start a web server that provides a REST API to the dgut
   101  // package's database, and a website that displays the information nicely.
   102  type Server struct {
   103  	gas.Server
   104  	tree           *dgut.Tree
   105  	treeMutex      sync.RWMutex
   106  	whiteCB        WhiteListCallback
   107  	uidToNameCache map[uint32]string
   108  	gidToNameCache map[uint32]string
   109  	userToGIDs     map[string][]string
   110  	dgutPaths      []string
   111  	dgutWatcher    *watch.Watcher
   112  	dataTimeStamp  time.Time
   113  	areas          map[string][]string
   114  
   115  	basedirsMutex   sync.RWMutex
   116  	basedirs        *basedirs.BaseDirReader
   117  	basedirsPath    string
   118  	ownersPath      string
   119  	basedirsWatcher *watch.Watcher
   120  }
   121  
   122  // New creates a Server which can serve a REST API and website.
   123  //
   124  // It logs to the given io.Writer, which could for example be syslog using the
   125  // log/syslog pkg with syslog.new(syslog.LOG_INFO, "tag").
   126  func New(logWriter io.Writer) *Server {
   127  	s := &Server{
   128  		Server:         *gas.New(logWriter),
   129  		uidToNameCache: make(map[uint32]string),
   130  		gidToNameCache: make(map[uint32]string),
   131  		userToGIDs:     make(map[string][]string),
   132  	}
   133  
   134  	s.SetStopCallBack(s.stop)
   135  
   136  	return s
   137  }
   138  
   139  // stop is called when the server is Stop()ped, cleaning up our additional
   140  // properties.
   141  func (s *Server) stop() {
   142  	s.treeMutex.Lock()
   143  	defer s.treeMutex.Unlock()
   144  
   145  	if s.dgutWatcher != nil {
   146  		s.dgutWatcher.Stop()
   147  		s.dgutWatcher = nil
   148  	}
   149  
   150  	if s.basedirsWatcher != nil {
   151  		s.basedirsWatcher.Stop()
   152  		s.basedirsWatcher = nil
   153  	}
   154  
   155  	if s.tree != nil {
   156  		s.tree.Close()
   157  		s.tree = nil
   158  	}
   159  }