aboutsummaryrefslogtreecommitdiff
path: root/include/cache.h
blob: 703c986233dae42b629a8ce65eb66d8beb1c2248 (plain) (blame)
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
#ifndef NEWSBOAT_CACHE_H_
#define NEWSBOAT_CACHE_H_

#include <memory>
#include <mutex>
#include <sqlite3.h>
#include <unordered_set>

#include "configcontainer.h"
#include "filepath.h"

namespace newsboat {

class RssFeed;
class RssIgnores;
class RssItem;

struct SchemaVersion {
	unsigned int major, minor;

	friend bool operator<(const SchemaVersion& l, const SchemaVersion& r)
	{
		return std::tie(l.major, l.minor) < std::tie(r.major, r.minor);
	}
	friend bool operator>(const SchemaVersion& l, const SchemaVersion& r)
	{
		return r < l;
	}
	friend bool operator<=(const SchemaVersion& l, const SchemaVersion& r)
	{
		return !(l > r);
	}
	friend bool operator>=(const SchemaVersion& l, const SchemaVersion& r)
	{
		return !(l < r);
	}
};

const SchemaVersion unknown_version = {0, 0};

using schema_patches = std::map<SchemaVersion, std::vector<std::string>>;

class Cache {
public:
	Cache(const Filepath& cachefile, ConfigContainer& c);
	~Cache();

	static std::unique_ptr<Cache> in_memory(ConfigContainer& c);

	void externalize_rssfeed(RssFeed& feed, bool reset_unread);
	std::shared_ptr<RssFeed> internalize_rssfeed(std::string rssurl,
		RssIgnores* ign);
	void update_rssitem_unread_and_enqueued(RssItem& item,
		const std::string& feedurl);
	/// If requested, removes unreachable data stored in cache.
	/// Returns a list of unreachable feeds.
	std::vector<std::string> cleanup_cache(std::vector<std::shared_ptr<RssFeed>> feeds,
		bool always_clean = false);
	void do_vacuum();
	std::vector<std::shared_ptr<RssItem>> search_for_items(
			const std::string& querystr,
			const std::string& feedurl,
			RssIgnores& ign);
	std::unordered_set<std::string> search_in_items(
		const std::string& querystr,
		const std::unordered_set<std::string>& guids);
	void mark_all_read(const std::string& feedurl = "");
	void mark_all_read(RssFeed& feed);
	void update_rssitem_flags(RssItem* item);
	void fetch_lastmodified(const std::string& uri,
		time_t& t,
		std::string& etag);
	void update_lastmodified(const std::string& uri,
		time_t t,
		const std::string& etag);
	void mark_item_deleted(const std::string& guid, bool b);
	void remove_old_deleted_items(RssFeed* feed);
	void mark_items_read_by_guid(const std::vector<std::string>& guids);
	std::vector<std::string> get_read_item_guids();
	void fetch_descriptions(RssFeed* feed);
	std::string fetch_description(const RssItem& item);

private:
	SchemaVersion get_schema_version();
	void populate_tables();
	void set_pragmas();
	void delete_item_unlocked(const RssItem& item);
	void clean_old_articles();
	void update_rssitem_unlocked(RssItem& item,
		const std::string& feedurl,
		bool reset_unread);

	std::string prepare_query(const std::string& format);
	template<typename... Args>
	std::string prepare_query(const std::string& format,
		const std::string& arg,
		Args... args);
	template<typename T, typename... Args>
	std::string prepare_query(const std::string& format, const T& arg,
		Args... args);

	void run_sql(const std::string& query,
		int (*callback)(void*, int, char**, char**) = nullptr,
		void* callback_argument = nullptr);
	void run_sql_nothrow(const std::string& query,
		int (*callback)(void*, int, char**, char**) = nullptr,
		void* callback_argument = nullptr);
	void run_sql_impl(const std::string& query,
		int (*callback)(void*, int, char**, char**),
		void* callback_argument,
		bool do_throw);

	void close_database();

	sqlite3* db = nullptr;
	ConfigContainer& cfg;
	std::recursive_mutex mtx;
};

} // namespace newsboat

#endif /* NEWSBOAT_CACHE_H_ */