// Copyright (C) 2021 nytpu // SPDX-License-Identifier: AGPL-3.0-only // For more license details, see LICENSE or . // This file incorporates code from makeworld's amfora: // https://github.com/makeworld-the-better-one/amfora/blob/master/subscriptions/structs.go // Original source is Copyright 2020 makeworld and is licensed under the // terms of the GNU General Public License Version 3.0. // https://www.gnu.org/licenses/gpl-3.0-standalone.html // package core implements the structs and other necessary resources for storing // and managing feeds and pages package core import ( "encoding/json" "fmt" "io/ioutil" "os" "path/filepath" "sync" "golang.nytpu.com/comitium/localizations" ) // Global instance of FullData var Data = FullData{ FeedsMu: &sync.RWMutex{}, PagesMu: &sync.RWMutex{}, // Maps are created in init() } // the Header of feeds.gmi. // set in Init, either to the contents of header.gmi or to the default string var Header string // Timeout for requests var Timeout int var Localizer *localizations.Localizer // have to do this instead of the automatically called init() because // initialization stuff requires parsing of command line args first func Init(dataPath string, localizer *localizations.Localizer) error { Localizer = localizer // initialize comitium.json & data maps f, err := os.Open(filepath.Join(dataPath, "comitium.json")) if err == nil { // File exists and could be opened fi, err := f.Stat() if err == nil && fi.Size() > 0 { // File is not empty jsonBytes, err := ioutil.ReadAll(f) f.Close() if err != nil { return fmt.Errorf("read comitium.json error: %w", err) } err = json.Unmarshal(jsonBytes, &Data) if err != nil { return fmt.Errorf("comitium.json is corrupted: %w", err) } } f.Close() } else if !os.IsNotExist(err) { // There's an error opening the file, but it's not bc is doesn't exist return fmt.Errorf("open comitium.json error: %w", err) } if Data.Feeds == nil { Data.Feeds = make(map[string]*Feed) } if Data.Pages == nil { Data.Pages = make(map[string]*Page) } // initialize header.gmi f, err = os.Open(filepath.Join(dataPath, "header.gmi")) if err == nil { fi, err := f.Stat() if err == nil && fi.Size() > 0 { headerBytes, err := ioutil.ReadAll(f) f.Close() if err != nil { return fmt.Errorf("read header.gmi error: %w", err) } Header = string(headerBytes) } f.Close() } else if !os.IsNotExist(err) { return fmt.Errorf("open header.gmi error: %w", err) } if Header == "" { Header = `# comitium subscriptions ` } Timeout = 10 return nil } func (d *FullData) WriteJSON(dataPath string) error { // use .new so if there's a corruption when writing the old file is intact path := filepath.Join(dataPath, "comitium.json.new") d.RLock() jsonBytes, err := json.MarshalIndent(&d, "", "\t") d.RUnlock() if err != nil { return err } err = ioutil.WriteFile(path, jsonBytes, 0666) if err != nil { return err } // if full write was successful then overwrite original err = os.Rename(path, filepath.Join(dataPath, "comitium.json")) return err } // TranslateString takes a template string, a localizer tag, and a localizer // replacement set and will get the localized string from the localizer tag, // replace everything using the localizer replacements, and then substitute that // string into the template string. func TranslateString(template, localizerTag string, replacements *localizations.Replacements) string { return fmt.Sprintf(template, Localizer.Get(localizerTag, replacements)) }