improve policy file handling (now treated as a special kind of cached generated file)

Signed-off-by: kim (grufwub) <grufwub@gmail.com>
master
kim (grufwub) 4 years ago
parent 3de53f5f25
commit e7584fea79

@ -27,6 +27,14 @@ func checkCacheFreshness() {
/* Iterate through paths in cache map to query file last modified times */
for path := range Config.FileCache.CacheMap.Map {
/* Get file pointer, no need for lock as we have write lock */
file := Config.FileCache.CacheMap.Get(path)
/* If this is a generated file, we skip */
if isGeneratedType(file) {
continue
}
stat, err := os.Stat(path)
if err != nil {
/* Log file as not in cache, then delete */
@ -36,12 +44,9 @@ func checkCacheFreshness() {
}
timeModified := stat.ModTime().UnixNano()
/* Get file pointer, no need for lock as we have write lock */
file := Config.FileCache.CacheMap.Get(path)
/* If the file is marked as fresh, but file on disk newer, mark as unfresh */
if file.IsFresh() && file.LastRefresh() < timeModified {
file.SetUnfresh()
if file.Fresh && file.LastRefresh < timeModified {
file.Fresh = false
}
}
@ -49,6 +54,15 @@ func checkCacheFreshness() {
Config.FileCache.CacheMutex.Unlock()
}
func isGeneratedType(file *File) bool {
switch file.contents.(type) {
case *GeneratedFileContents:
return true
default:
return false
}
}
/* FileCache:
* Object to hold and help manage our file cache. Uses a fixed map
* as a means of easily collecting files by path, but also being able
@ -96,26 +110,26 @@ func (fc *FileCache) Fetch(request *FileSystemRequest, newFileContents func(stri
if file != nil {
/* File in cache -- before doing anything get file read lock */
file.RLock()
file.Mutex.RLock()
/* Check file is marked as fresh */
if !file.IsFresh() {
if !file.Fresh {
/* File not fresh! Swap file read for write-lock */
file.RUnlock()
file.Lock()
file.Mutex.RUnlock()
file.Mutex.Lock()
/* Reload file contents from disk */
gophorErr := file.LoadContents()
if gophorErr != nil {
/* Error loading contents, unlock all mutex then return error */
file.Unlock()
file.Mutex.Unlock()
fc.CacheMutex.RUnlock()
return nil, gophorErr
}
/* Updated! Swap back file write for read lock */
file.Unlock()
file.RLock()
file.Mutex.Unlock()
file.Mutex.RLock()
}
} else {
/* Perform filesystem stat ready for checking file size later.
@ -159,7 +173,7 @@ func (fc *FileCache) Fetch(request *FileSystemRequest, newFileContents func(stri
fc.CacheMap.Put(request.Path, file)
/* Before unlocking cache mutex, lock file read for upcoming call to .Contents() */
file.RLock()
file.Mutex.RLock()
/* Swap cache lock back to read */
fc.CacheMutex.Unlock()
@ -168,7 +182,7 @@ func (fc *FileCache) Fetch(request *FileSystemRequest, newFileContents func(stri
/* Read file contents into new variable for return, then unlock file read lock */
b := file.Contents(request)
file.RUnlock()
file.Mutex.RUnlock()
/* Finally we can unlock the cache map read lock, we are done :) */
fc.CacheMutex.RUnlock()

@ -6,6 +6,27 @@ import (
"strings"
)
/* GeneratedFileContents:
* The simplest implementation of FileContents that
* stores some bytes and does nothing else.
*/
type GeneratedFileContents struct {
contents []byte
}
func (fc *GeneratedFileContents) Render(request *FileSystemRequest) []byte {
return fc.contents
}
func (fc *GeneratedFileContents) Load() *GophorError {
/* do nothing */
return nil
}
func (fc *GeneratedFileContents) Clear() {
/* do nothing */
}
/* RegularFileContents:
* Very simple implementation of FileContents that just
* buffered reads from the stored file path, stores the

38
fs.go

@ -31,9 +31,9 @@ type FileSystemRequest struct {
*/
type File struct {
contents FileContents
mutex sync.RWMutex
isFresh bool
lastRefresh int64
Mutex sync.RWMutex
Fresh bool
LastRefresh int64
}
func NewFile(contents FileContents) *File {
@ -60,40 +60,12 @@ func (f *File) LoadContents() *GophorError {
}
/* Update lastRefresh, set fresh, unset deletion (not likely set) */
f.lastRefresh = time.Now().UnixNano()
f.isFresh = true
f.LastRefresh = time.Now().UnixNano()
f.Fresh = true
return nil
}
func (f *File) IsFresh() bool {
return f.isFresh
}
func (f *File) SetUnfresh() {
f.isFresh = false
}
func (f *File) LastRefresh() int64 {
return f.lastRefresh
}
func (f *File) Lock() {
f.mutex.Lock()
}
func (f *File) Unlock() {
f.mutex.Unlock()
}
func (f *File) RLock() {
f.mutex.RLock()
}
func (f *File) RUnlock() {
f.mutex.RUnlock()
}
/* FileContents:
* Interface that provides an adaptable implementation
* for holding onto some level of information about

@ -43,6 +43,8 @@ func main() {
/* Start accepting connections on any supplied listeners */
for _, l := range listeners {
go func() {
Config.LogSystem("Listening on: gopher://%s\n", l.Addr())
for {
newConn, err := l.Accept()
if err != nil {
@ -145,7 +147,6 @@ func setupServer() []*GophorListener {
if err != nil {
Config.LogSystemFatal("Error setting up (unencrypted) listener: %s\n", err.Error())
}
Config.LogSystem("Listening (unencrypted): gopher://%s\n", l.Addr())
listeners = append(listeners, l)
} else {
Config.LogSystemFatal("No valid port to listen on :(\n")
@ -176,6 +177,11 @@ func setupServer() []*GophorListener {
Config.FileCache = new(FileCache)
Config.FileCache.Init(*cacheSize, *cacheFileSizeMax)
/* Before file monitor or any kind of new goroutines started,
* check if we need to cache generated policy files
*/
cachePolicyFiles()
/* Start file cache freshness checker */
go startFileMonitor(fileMonitorSleepTime)

@ -1,5 +1,49 @@
package main
import (
"os"
)
func cachePolicyFiles() {
/* See if caps txt exists, if not generate */
_, err := os.Stat("/caps.txt")
if err != nil {
/* We need to generate the caps txt and manually load into cache */
content := generateCapsTxt()
/* Create new file object from generated file contents */
fileContents := &GeneratedFileContents{ content }
file := NewFile(fileContents)
/* Trigger a load contents just to set it as fresh etc */
file.LoadContents()
/* No need to worry about mutexes here, no other goroutines running yet */
Config.FileCache.CacheMap.Put("/caps.txt", file)
Config.LogSystem("Cached generated policy file: /caps.txt\n")
}
/* See if caps txt exists, if not generate */
_, err = os.Stat("/robots.txt")
if err != nil {
/* We need to generate the caps txt and manually load into cache */
content := generateRobotsTxt()
/* Create new file object from generated file contents */
fileContents := &GeneratedFileContents{ content }
file := NewFile(fileContents)
/* Trigger a load contents just to set it as fresh etc */
file.LoadContents()
/* No need to worry about mutexes here, no other goroutines running yet */
Config.FileCache.CacheMap.Put("/robots.txt", file)
Config.LogSystem("Cached generated policy file: /robots.txt\n")
}
}
func generateCapsTxt() []byte {
text := "CAPS"+DOSLineEnd
text += DOSLineEnd

Loading…
Cancel
Save