getwtxt/getwtxt

View on GitHub
svc/cache.go

Summary

Maintainability
A
0 mins
Test Coverage
/*
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 <https://www.gnu.org/licenses/>.
*/

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()
    }
}