/* Copyright (c) 2019 Ben Morrison (gbmor) This file is part of Getwtxt. Getwtxt is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Getwtxt is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Getwtxt. If not, see . */ package svc // import "git.sr.ht/~gbmor/getwtxt/svc" import ( "bytes" "html/template" "io/ioutil" "os" "sync" "time" ) // These functions and types pertain to the // in-memory data being used by the registry // service, such as: // - static assets (index.html, style.css) // - the registry itself (users, etc) // - list of other registries submitted // RemoteRegistries holds a list of remote registries to // periodically scrape for new users. The remote registries // must have been added via POST like a user. type RemoteRegistries struct { List []string } // staticAssets holda the rendered landing page // as a byte slice, its on-disk mod time, the // assets/style.css file as a byte slice, and // its on-disk mod time. type staticAssets struct { mu sync.RWMutex index []byte indexMod time.Time css []byte cssMod time.Time } // Renders the landing page template using // the info supplied in the configuration // file's "Instance" section. func initTemplates() *template.Template { confObj.Mu.RLock() defer confObj.Mu.RUnlock() return template.Must(template.ParseFiles(confObj.AssetsDir + "/tmpl/index.html")) } func cacheUpdate() { // This clusterfuck of mutex read locks is // necessary to avoid deadlock. This mess // also avoids a panic that would occur // should twtxtCache be written to during // this loop. twtxtCache.Mu.RLock() for k := range twtxtCache.Users { twtxtCache.Mu.RUnlock() errLog("", twtxtCache.UpdateUser(k)) twtxtCache.Mu.RLock() } twtxtCache.Mu.RUnlock() for _, v := range remoteRegistries.List { errLog("Error refreshing local copy of remote registry data: ", twtxtCache.CrawlRemoteRegistry(v)) } } // pingAssets checks if the local static assets // need to be re-cached. If they do, they are // pulled back into memory from disk. func pingAssets() { confObj.Mu.RLock() defer confObj.Mu.RUnlock() staticCache.mu.Lock() defer staticCache.mu.Unlock() cssStat, err := os.Stat(confObj.AssetsDir + "/style.css") errLog("", err) indexStat, err := os.Stat(confObj.AssetsDir + "/tmpl/index.html") errLog("", err) if !staticCache.indexMod.Equal(indexStat.ModTime()) { tmpls = initTemplates() var b []byte buf := bytes.NewBuffer(b) errLog("", tmpls.ExecuteTemplate(buf, "index.html", confObj.Instance)) staticCache.index = buf.Bytes() staticCache.indexMod = indexStat.ModTime() } if !staticCache.cssMod.Equal(cssStat.ModTime()) { css, err := ioutil.ReadFile(confObj.AssetsDir + "/style.css") errLog("", err) staticCache.css = css staticCache.cssMod = cssStat.ModTime() } }