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 }