]> git.sesse.net Git - ccbs/blob - bigscreen/ccbs_bigscreen.cpp
684f423777db0214390df3ae07634984ad3de814
[ccbs] / bigscreen / ccbs_bigscreen.cpp
1 #include <cstdio>
2 #include <cstring>
3 #include <iconv.h>
4 #include <unistd.h>
5 #include <pqxx/pqxx>
6 #include <ft2build.h>
7 #include FT_FREETYPE_H
8 #include <tinyptc.h>
9
10 iconv_t ucs4_iconv;
11
12 // UCS-4 string
13 class widestring : public std::basic_string<unsigned>
14 {
15 public:
16         void operator= (const char *from)
17         {
18                 unsigned bytes = std::strlen(from);
19                 char *from_buf = strdup(from);
20                 unsigned *to_buf = new unsigned[bytes + 1];
21
22                 char *inptr = from_buf, *outptr = reinterpret_cast<char *> (to_buf);
23
24                 size_t in_left = bytes;
25                 size_t out_left = bytes * sizeof(unsigned);
26
27                 size_t ret = iconv(ucs4_iconv, NULL, NULL, &outptr, &out_left);
28                 if (ret == (size_t)(-1)) {
29                         throw std::runtime_error("Error in iconv during initialization");
30                 }
31
32                 ret = iconv(ucs4_iconv, &inptr, &in_left, &outptr, &out_left);
33                 if (ret == (size_t)(-1)) {
34                         perror("iconv");
35                         throw std::runtime_error("Error in iconv during conversion");
36                 }
37
38                 erase(begin(), end());
39                 std::copy(to_buf, reinterpret_cast<unsigned *> (outptr), std::back_inserter(*this));
40
41                 free(from_buf);
42                 delete[] to_buf;
43         }
44 };
45
46 template<>
47 void std::char_traits<unsigned>::assign(unsigned &to, unsigned const &from)
48 {
49         to = from;
50 }
51
52 template<>
53 unsigned *std::char_traits<unsigned>::copy(unsigned *to, unsigned const *from, unsigned n)
54 {
55         return static_cast<unsigned *>(memcpy(to, from, n * sizeof(unsigned)));
56 }
57
58 template<>
59 unsigned *std::char_traits<unsigned>::move(unsigned *to, unsigned const *from, unsigned n)
60 {
61         return static_cast<unsigned *>(memmove(to, from, n * sizeof(unsigned)));
62 }
63
64 template<>
65 unsigned *std::char_traits<unsigned>::assign(unsigned *to, size_t n, unsigned a)
66 {
67         for (unsigned i = 0; i < n; ++i)
68                 *to++ = a;
69         return to;
70 }
71
72
73 template<>
74 void pqxx::from_string<widestring>(const char *from, widestring &to)
75 {
76         to = from;
77 }
78
79 class Tournament {
80 public:
81         int id;
82         widestring name;
83 };
84
85 Tournament active_tournament;
86 FT_Face font;
87
88 /* A trigger that sets a flag whenever it's trigged. */
89 class FlagTrigger : pqxx::trigger {
90 private:
91         bool flag;
92         
93 public:
94         FlagTrigger(pqxx::connection_base &conn, const PGSTD::string &name)
95                 : pqxx::trigger(conn, name), flag(false) {}
96         virtual ~FlagTrigger() throw () {}
97         
98         virtual void operator() (int pid)
99         {
100                 flag = true;
101                 std::fprintf(stderr, "Received a flag trigger from pid %u\n", pid);
102         }
103
104         bool get_flag() const
105         {
106                 return flag;
107         }
108
109         void reset_flag()
110         {
111                 flag = false;
112         }
113 };
114
115 /* A transactor that fetches the current tournament and some information about it. */
116 class FetchCurrentTournament : public pqxx::transactor<> {
117 private:
118         Tournament *tourn;
119
120 public:
121         FetchCurrentTournament(Tournament *tourn) : tourn(tourn) {}
122         void operator() (pqxx::transaction<> &t)
123         {
124                 pqxx::result res( t.exec("SELECT * FROM bigscreen.active_tournament NATURAL JOIN tournaments") );
125                 try {
126                         pqxx::result::tuple tournament = res.at(0);
127
128                         tourn->id = tournament["tournament"].as(tourn->id);
129                         tourn->name = tournament["tournamentname"].as(tourn->name);
130                 } catch (PGSTD::out_of_range &e) {
131                         tourn->id = -1;
132                         tourn->name = "";
133                 }
134         }
135 };
136
137 void init(pqxx::connection &conn)
138 {
139         conn.perform(FetchCurrentTournament(&active_tournament));
140
141         if (active_tournament.id == -1) {
142                 std::fprintf(stderr, "No active tournament\n");
143         } else {
144                 std::fprintf(stderr, "Current tournament is %d (name: '%s')\n",
145                         active_tournament.id, active_tournament.name.c_str());
146         }
147 }
148
149 void main_loop(pqxx::connection &conn)
150 {
151         if (active_tournament.id == -1) {
152                 // No active tournament, sleep a second or so and exit
153                 sleep(1);
154                 return;
155         }
156         
157         pqxx::work t(conn, "trx");
158
159         // fetch all songs
160         pqxx::result res( t.exec("SELECT * FROM songs") );
161         for (pqxx::result::const_iterator i = res.begin(); i != res.end(); ++i) {
162                 std::fprintf(stderr, "%s\n", i["title"].c_str());
163         }
164         t.commit();
165         
166         sleep(1);
167 }
168
169 void init_freetype()
170 {
171         FT_Library library;
172         if (FT_Init_FreeType(&library))
173                 throw std::logic_error("FreeType init failed.");
174         if (FT_New_Face(library, "/usr/share/fonts/truetype/msttcorefonts/Georgia.ttf", 0, &font))
175                 throw std::logic_error("Face opening failed.");
176         if (FT_Set_Char_Size(font, 0, 12, 96, 96))
177                 throw std::logic_error("Size set failed.");
178 }
179
180 int main(int argc, char **argv)
181 {
182         ucs4_iconv = iconv_open("ucs-4", "utf-8");
183         
184         ptc_open("CCBS bigscreen", 800, 600);
185         
186         try {
187                 init_freetype();
188                 pqxx::connection conn("dbname=ccbs host=altersex.samfundet.no user=ccbs password=GeT|>>B_");
189                 FlagTrigger tournament_changed(conn, "active_tournament");
190                 
191                 // when active_tournament is changed, we destroy everything and start from scratch
192                 for ( ;; ) {
193                         tournament_changed.reset_flag();
194                         init(conn);
195                         do {
196                                 main_loop(conn);
197                                 conn.get_notifs();
198                         } while (!tournament_changed.get_flag());
199                         std::fprintf(stderr, "active_tournament changed, resetting...\n");
200                 }
201         } catch (const std::exception &e) {
202                 std::fprintf(stderr, "Exception: %s\n", e.what());
203                 exit(1);
204         }
205         
206         return 0;
207 }