Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
23b25d52bd | |||
7d0d5fa06b | |||
19e3093f3b | |||
461a8587ad | |||
23e07c376a | |||
bf18c0a9cc | |||
0ec0045301 | |||
540bd616a8 | |||
3496759430 | |||
4c6310343d | |||
|
7bf2881145 | ||
|
3850cf3032 | ||
|
832e4b97a9 | ||
|
336352a335 | ||
|
f09c05fd1a | ||
|
7bfa64ca81 | ||
|
41e6be61e7 | ||
|
2c01baef1b | ||
|
7b2120d122 |
8
Makefile
8
Makefile
@ -3,6 +3,12 @@ BIN=cts
|
|||||||
|
|
||||||
all: main
|
all: main
|
||||||
|
|
||||||
|
staticgen: colors.o src/dbquery.c
|
||||||
|
echo "\nCompiling executable as static page generator\n"
|
||||||
|
gcc -c src/dbquery.c $(CFLAGS) -DSTATICGEN
|
||||||
|
gcc -c src/main.c $(CFLAGS) -DSTATICGEN
|
||||||
|
gcc colors.o dbquery.o main.o -lsqlite3 -o $(BIN)
|
||||||
|
|
||||||
main: main.o
|
main: main.o
|
||||||
gcc colors.o dbquery.o main.o -lsqlite3 -o $(BIN)
|
gcc colors.o dbquery.o main.o -lsqlite3 -o $(BIN)
|
||||||
|
|
||||||
@ -19,4 +25,4 @@ testcolor: src/colors.c src/tcolor.c
|
|||||||
gcc src/colors.c src/tcolor.c -o tcolor -I"includes" -g
|
gcc src/colors.c src/tcolor.c -o tcolor -I"includes" -g
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm *.o *.log $(BIN)
|
rm *.o
|
||||||
|
33
README.md
33
README.md
@ -1,11 +1,20 @@
|
|||||||
C CGI Xonotic DeFrag
|
# xdfcgi
|
||||||
-----------------
|
|
||||||
A CGI program written in C to display data related to Race CTS leaderboards of Xonotic servers.
|
A common gateway inferface (CGI) program written in C to display Race CTS leaderboards of Xonotic servers. It can also be a static page generator.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
* SQLite3
|
sqlite-devel python3 python-sqlite
|
||||||
|
|
||||||
|
The first is only needed for compilation of the C program. The latter two are only for the auxiliary script `allmaps.py`.
|
||||||
|
|
||||||
|
## Compiling
|
||||||
|
`make` makes a CGI program.
|
||||||
|
|
||||||
|
`make staticgen` makes a static page generator.
|
||||||
|
|
||||||
|
## Usage: CGI Query Strings
|
||||||
|
The program queries the database `db/cts.db` (`./src/dbquery.c`, function `static bool executequery`)
|
||||||
|
|
||||||
## Web Server Queries
|
|
||||||
* `(none)`
|
* `(none)`
|
||||||
- Query file: `queries/mranks.sql`
|
- Query file: `queries/mranks.sql`
|
||||||
- Requests the map list of the server and related data.
|
- Requests the map list of the server and related data.
|
||||||
@ -18,11 +27,25 @@ A CGI program written in C to display data related to Race CTS leaderboards of X
|
|||||||
- Query file: `queries/rplayers.sql`
|
- Query file: `queries/rplayers.sql`
|
||||||
- Requests a player's ranks for all maps leaderboards s/he is present on.
|
- Requests a player's ranks for all maps leaderboards s/he is present on.
|
||||||
|
|
||||||
|
## Usage: Static Page Generation
|
||||||
|
|
||||||
|
python scripts/allmaps.py
|
||||||
|
|
||||||
|
The CGI program is still invoked in static generation. The files `allmaps.py`, `output/leaderboard.css`, `overview.html`, `map.html` produce the output.
|
||||||
|
|
||||||
|
Before executing `allmaps.py`, copy and modify the templates.
|
||||||
|
|
||||||
|
cp templates/overview.html .
|
||||||
|
cp templates/map.html .
|
||||||
|
|
||||||
|
`allmaps.py` outputs an html file for all distinct maps in the database. The leaderboards for each map (equivalent to `?map=[map name]`) are in `output/maps/`.
|
||||||
|
|
||||||
## Game Versions Used Under:
|
## Game Versions Used Under:
|
||||||
* Xonotic 0.8.1
|
* Xonotic 0.8.1
|
||||||
* Xonotic 0.8.2
|
* Xonotic 0.8.2
|
||||||
|
|
||||||
## Compilers
|
## Compilers
|
||||||
|
* gcc (GCC) 10.2.1
|
||||||
* MinGW, GCC 4.7.1
|
* MinGW, GCC 4.7.1
|
||||||
|
|
||||||
__________________
|
__________________
|
||||||
|
17
output/leaderboard.css
Normal file
17
output/leaderboard.css
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
footer {
|
||||||
|
text-align:center;
|
||||||
|
}
|
||||||
|
table, th, td {
|
||||||
|
border: 1px solid grey;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
th, td {
|
||||||
|
width:auto;
|
||||||
|
text-align:center;
|
||||||
|
word-wrap: break-word;
|
||||||
|
margin: 1em 1em 1em 1em;
|
||||||
|
}
|
||||||
|
|
@ -5,4 +5,4 @@ where Cts_ranks.mapid = Cts_times.mapid
|
|||||||
and cryptokey = idvalue
|
and cryptokey = idvalue
|
||||||
and idrank = 1
|
and idrank = 1
|
||||||
group by Cts_ranks.mapid
|
group by Cts_ranks.mapid
|
||||||
order by max(trank);
|
order by count(trank) DESC;
|
||||||
|
67
scripts/allmaps.py
Normal file
67
scripts/allmaps.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import sqlite3 as sql
|
||||||
|
import subprocess, traceback
|
||||||
|
|
||||||
|
# get all maps in database
|
||||||
|
def getmaps(database):
|
||||||
|
output = []
|
||||||
|
con = sql.connect(database)
|
||||||
|
with con:
|
||||||
|
cursor = con.cursor()
|
||||||
|
try:
|
||||||
|
cursor.execute("select distinct mapid from Cts_times;")
|
||||||
|
output = cursor.fetchall()
|
||||||
|
except sql.Error:
|
||||||
|
print("Shit is fucked.")
|
||||||
|
return output
|
||||||
|
|
||||||
|
# if there is no query then it outputs the index file.
|
||||||
|
def getcontent(query=None):
|
||||||
|
cmd = [("./cts")]
|
||||||
|
proc = subprocess.Popen(cmd, env=query, stdout=subprocess.PIPE, shell=True)
|
||||||
|
# communicate returns 'bytes' class with function 'decode'
|
||||||
|
return proc.communicate()[0].decode('utf-8')
|
||||||
|
|
||||||
|
def renderindex(template):
|
||||||
|
# no env variable
|
||||||
|
table = getcontent()
|
||||||
|
filename = "./output/index.html"
|
||||||
|
with open(filename, 'w+') as fout:
|
||||||
|
fout.write(template % (table))
|
||||||
|
fout.close
|
||||||
|
pass
|
||||||
|
|
||||||
|
def main():
|
||||||
|
template = ""
|
||||||
|
with open("overview.html", 'r') as fin:
|
||||||
|
template = fin.read()
|
||||||
|
renderindex(template)
|
||||||
|
maps = getmaps("db/cts.db")
|
||||||
|
with open("map.html", 'r') as fin:
|
||||||
|
template = fin.read()
|
||||||
|
# for each map generate an html file.
|
||||||
|
for game_map in maps:
|
||||||
|
# game_map is a tuple obj.
|
||||||
|
map_name = game_map[0]
|
||||||
|
query = {"QUERY_STRING" : ("map=%s" % map_name)}
|
||||||
|
table = getcontent(query)
|
||||||
|
filename = ("./output/maps/%s.html" % map_name)
|
||||||
|
with open(filename, 'w+') as fout:
|
||||||
|
title = map_name
|
||||||
|
fout.write(template.format(
|
||||||
|
title=title,
|
||||||
|
map_name=map_name,
|
||||||
|
table=table)
|
||||||
|
)
|
||||||
|
# fout.write(template % (title, map_name, table))
|
||||||
|
return True
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
success = False
|
||||||
|
try:
|
||||||
|
success = main()
|
||||||
|
except FileNotFoundError:
|
||||||
|
traceback.print_exc()
|
||||||
|
print("\n\t The script probably didn't find the page templates needed to generate a page. You can copy minimal working examples from the repository at templates/.")
|
||||||
|
if success:
|
||||||
|
print("allmaps.py - Generated pages for all maps.")
|
||||||
|
pass
|
@ -31,7 +31,7 @@ static inline void print_tblheader(const char *c) {
|
|||||||
char *labels;
|
char *labels;
|
||||||
switch (*c) {
|
switch (*c) {
|
||||||
default:
|
default:
|
||||||
labels = "<TABLE class='center'>\
|
labels = "<TABLE class='leaderboard'>\
|
||||||
<TH class='tablename' COLSPAN='4'> <H3><BR>Map List</H3> </TH>\
|
<TH class='tablename' COLSPAN='4'> <H3><BR>Map List</H3> </TH>\
|
||||||
<TR>\
|
<TR>\
|
||||||
<TH class='columnname'>Name</TH>\
|
<TH class='columnname'>Name</TH>\
|
||||||
@ -41,7 +41,7 @@ static inline void print_tblheader(const char *c) {
|
|||||||
</TR>";
|
</TR>";
|
||||||
break;
|
break;
|
||||||
case QMLEADERBOARD:
|
case QMLEADERBOARD:
|
||||||
labels = "<TABLE class='center'>\
|
labels = "<TABLE class='leaderboard'>\
|
||||||
<TH class='tablename' COLSPAN='3'><H3><BR>Leaderboard</H3></TH>\
|
<TH class='tablename' COLSPAN='3'><H3><BR>Leaderboard</H3></TH>\
|
||||||
<TR>\
|
<TR>\
|
||||||
<TH class='columnname'>Rank</TH>\
|
<TH class='columnname'>Rank</TH>\
|
||||||
@ -50,7 +50,7 @@ static inline void print_tblheader(const char *c) {
|
|||||||
</TR>";
|
</TR>";
|
||||||
break;
|
break;
|
||||||
case QRPLAYER:
|
case QRPLAYER:
|
||||||
labels = "<TABLE class='center'>\
|
labels = "<TABLE class='leaderboard'>\
|
||||||
<TH class='tablename' COLSPAN='3'> <H3><BR>Ranks</H3> </TH>\
|
<TH class='tablename' COLSPAN='3'> <H3><BR>Ranks</H3> </TH>\
|
||||||
<TR>\
|
<TR>\
|
||||||
<TH class='columnname'>Name</TH>\
|
<TH class='columnname'>Name</TH>\
|
||||||
@ -98,7 +98,11 @@ static void qresult(sqlite3_stmt * const sp, const char *c) {
|
|||||||
if (ISPLAYERNAME(c, i)) {
|
if (ISPLAYERNAME(c, i)) {
|
||||||
print_plname(field);
|
print_plname(field);
|
||||||
} else if (ISMAPNAME(c, i)) {
|
} else if (ISMAPNAME(c, i)) {
|
||||||
|
#ifdef STATICGEN
|
||||||
|
printf("<TD><a href='./maps/%s.html'>%s</a></TD>", field, field);
|
||||||
|
#else
|
||||||
printf("<TD><a href='/cgi/cts?map=%s'>%s</a></TD>", field, field);
|
printf("<TD><a href='/cgi/cts?map=%s'>%s</a></TD>", field, field);
|
||||||
|
#endif
|
||||||
} else if (i == 2 && (*c == QMLEADERBOARD || *c == QOVERVIEW)) {
|
} else if (i == 2 && (*c == QMLEADERBOARD || *c == QOVERVIEW)) {
|
||||||
print_time(field);
|
print_time(field);
|
||||||
} else {
|
} else {
|
||||||
|
16
src/main.c
16
src/main.c
@ -8,10 +8,7 @@ void html(void) {
|
|||||||
<link rel=\"stylesheet\" type=\"text/css\" href=\"page.css\">\
|
<link rel=\"stylesheet\" type=\"text/css\" href=\"page.css\">\
|
||||||
<title>/v/ - Xonotic</title>\
|
<title>/v/ - Xonotic</title>\
|
||||||
<p class='hidden'>:-) / nice one<br></p>";
|
<p class='hidden'>:-) / nice one<br></p>";
|
||||||
const char *html_bot = "<br><br><p classname='footer'>Pages under construction.<br>\
|
const char *html_bot = "<br><br>\
|
||||||
Service may sporadically become unavailable.<br>\
|
|
||||||
In-game database is not directly synced with this web server.\
|
|
||||||
</p>\
|
|
||||||
</body></html>";
|
</body></html>";
|
||||||
const char *html_mid = "<br>\
|
const char *html_mid = "<br>\
|
||||||
<H2>hi / good luck and have fun.<br><br>Available Pages</H2>\
|
<H2>hi / good luck and have fun.<br><br>Available Pages</H2>\
|
||||||
@ -29,7 +26,18 @@ void html(void) {
|
|||||||
printf("%s", html_bot);
|
printf("%s", html_bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// use with template
|
||||||
|
void templated(void) {
|
||||||
|
const char *qstr = getenv("QUERY_STRING");
|
||||||
|
getquery(qstr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
#ifdef STATICGEN
|
||||||
|
templated();
|
||||||
|
#else
|
||||||
html();
|
html();
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
22
templates/map.html
Normal file
22
templates/map.html
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{title} - Leaderboards - Minimal Working Example</title>
|
||||||
|
<link href="/style.css" rel="stylesheet" type="text/css" media="all">
|
||||||
|
<link href="../leaderboard.css" rel="stylesheet" type="text/css" media="all">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<!-- map name -->
|
||||||
|
<h1>{map_name}</h1>
|
||||||
|
|
||||||
|
<!-- code generated table goes here -->
|
||||||
|
{table}
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>Page generated using <a href="https://notabug.org/scuti/xdfcgi">xdfcgi</a> by <a href="https://scuti.neocities.org/">scuti</a></p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
19
templates/overview.html
Normal file
19
templates/overview.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>CTS Leaderboards - Minimal Working Example</title>
|
||||||
|
<link href="/style.css" rel="stylesheet" type="text/css" media="all">
|
||||||
|
<link href="./leaderboard.css" rel="stylesheet" type="text/css" media="all">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<!-- code generated table goes here -->
|
||||||
|
%s
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<p>Page generated using <a href="https://notabug.org/scuti/xdfcgi">xdfcgi</a> by <a href="https://scuti.neocities.org/">scuti</a></p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user