summaryrefslogtreecommitdiff
path: root/core/core.go
blob: b5acf4648acde722d477dcf90028e428fe9a6a72 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Copyright (C) 2021 nytpu
// SPDX-License-Identifier: AGPL-3.0-only
// For more license details, see LICENSE or <https://www.gnu.org/licenses/agpl-3.0.html>.

// 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 = TranslateString("# %s\n\n", "files.feed_default_header", nil)
	}

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