mirror of
https://github.com/paxed/dgamelaunch.git
synced 2025-04-08 17:06:19 +02:00
Show the number of people watching each game in the watching-menu.
Also allow sorting by # of watchers. Requires dgamelaunch to be compiled with --enable-shmem git-svn-id: svn://katsu.triplehelix.org/dgamelaunch/trunk@536 db0b04b0-f4d1-0310-9a6d-de3e77497b0e
This commit is contained in:
parent
6245e81b59
commit
113fc564ef
4
TODO
4
TODO
@ -9,8 +9,6 @@
|
||||
will no longer work, because the cursor won't be moved to the previous
|
||||
line again
|
||||
|
||||
-change the watching-menu paging back to pre-1.5.0 behaviour
|
||||
(don't backtrack in the gamelist to keep the last page full)
|
||||
-when exiting from watching a player, move the cursor to the last line
|
||||
of the screen before enabling the ncurses mode; so when we exit dgl,
|
||||
the watched player's game is all visible and the menu prompt doesn't
|
||||
@ -118,8 +116,6 @@ or maybe add a new command '' set_charstrip "name" ''
|
||||
-public (no-password) accounts? (a per-user flag) what happens when someone
|
||||
is playing on the account and someone else logins and we start playing?
|
||||
-allow users to run recover themselves
|
||||
-make dgl show # of watchers. this would probably require adding a
|
||||
shared memory block to keep track of who is watching who...
|
||||
-configurable stuff: allowed chars in usernames,
|
||||
allow char stripping, ...
|
||||
|
||||
|
13
configure.ac
13
configure.ac
@ -144,6 +144,19 @@ if test "$enable_rlimit" = yes; then
|
||||
fi
|
||||
|
||||
|
||||
AC_ARG_ENABLE(shmem,
|
||||
[AC_HELP_STRING([--enable-shmem], [Use a shared memory block to show number of watchers.])],
|
||||
[enable_shmem=yes], [])
|
||||
|
||||
if test "$enable_shmem" = yes; then
|
||||
AC_CHECK_HEADERS([semaphore.h], [], [AC_MSG_ERROR([semaphore.h not found.])], [])
|
||||
AC_CHECK_HEADERS([sys/ipc.h], [], [AC_MSG_ERROR([sys/ipc.h not found.])], [])
|
||||
AC_CHECK_HEADERS([sys/shm.h], [], [AC_MSG_ERROR([sys/shm.h not found.])], [])
|
||||
AC_MSG_RESULT([Enabled showing number of watchers.])
|
||||
AC_DEFINE(USE_SHMEM,1,[Use shared memory block])
|
||||
LIBS="$LIBS -lrt"
|
||||
# or -pthread?
|
||||
fi
|
||||
|
||||
|
||||
AC_ARG_WITH(config-file,
|
||||
|
240
dgamelaunch.c
240
dgamelaunch.c
@ -53,6 +53,12 @@
|
||||
#ifdef USE_RLIMIT
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_SHMEM
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdlib.h>
|
||||
#include <curses.h>
|
||||
@ -408,18 +414,155 @@ drawbanner (struct dg_banner *ban, unsigned int start_line, unsigned int howmany
|
||||
mvaddstr (start_line + i, 1, ban->lines[i]);
|
||||
}
|
||||
|
||||
void
|
||||
shm_sem_wait(struct dg_shm *shm_dg_data)
|
||||
{
|
||||
#ifdef USE_SHMEM
|
||||
if (sem_wait(&(shm_dg_data->dg_sem)) == -1) {
|
||||
debug_write("sem_wait");
|
||||
graceful_exit(77);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
shm_sem_post(struct dg_shm *shm_dg_data)
|
||||
{
|
||||
#ifdef USE_SHMEM
|
||||
if (sem_post(&(shm_dg_data->dg_sem)) == -1) {
|
||||
debug_write("sem_post");
|
||||
graceful_exit(78);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
shm_update(struct dg_shm *shm_dg_data, struct dg_game **games, int len)
|
||||
{
|
||||
#ifdef USE_SHMEM
|
||||
int di, i;
|
||||
struct dg_shm_game *shm_dg_game = (struct dg_shm_game *)(shm_dg_data + sizeof(struct dg_shm));
|
||||
|
||||
shm_sem_wait(shm_dg_data);
|
||||
|
||||
for (di = 0; di < shm_dg_data->max_n_games; di++)
|
||||
if (shm_dg_game[di].in_use) {
|
||||
int delgame = 1;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!strcmp(games[i]->ttyrec_fn, shm_dg_game[di].ttyrec_fn)) {
|
||||
delgame = 0;
|
||||
games[i]->is_in_shm = 1;
|
||||
games[i]->shm_idx = di;
|
||||
games[i]->nwatchers = shm_dg_game[di].nwatchers;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (delgame) {
|
||||
shm_dg_game[di].in_use = 0;
|
||||
if (shm_dg_data->cur_n_games > 0) shm_dg_data->cur_n_games--;
|
||||
}
|
||||
}
|
||||
|
||||
if (shm_dg_data->cur_n_games < shm_dg_data->max_n_games) {
|
||||
for (i = 0; i < len; i++)
|
||||
if (!games[i]->is_in_shm) {
|
||||
for (di = 0; di < shm_dg_data->max_n_games; di++)
|
||||
if (!shm_dg_game[di].in_use) {
|
||||
shm_dg_game[di].in_use = 1;
|
||||
shm_dg_game[di].nwatchers = 0;
|
||||
games[i]->nwatchers = 0;
|
||||
games[i]->is_in_shm = 1;
|
||||
games[i]->shm_idx = di;
|
||||
shm_dg_data->cur_n_games++;
|
||||
strncpy(shm_dg_game[di].ttyrec_fn, games[i]->ttyrec_fn, 150);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shm_sem_post(shm_dg_data);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
shm_mk_keys(key_t *shm_key, key_t *shm_sem_key)
|
||||
{
|
||||
#ifdef USE_SHMEM
|
||||
if ((*shm_key = ftok("dgamelaunch", 'R')) == -1) {
|
||||
debug_write("ftok shm_key");
|
||||
graceful_exit(71);
|
||||
}
|
||||
if ((*shm_sem_key = ftok("dgamelaunch", 'S')) == -1) {
|
||||
debug_write("ftok shm_sem_key");
|
||||
graceful_exit(72);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
shm_init(struct dg_shm **shm_dg_data, struct dg_shm_game **shm_dg_game)
|
||||
{
|
||||
#ifdef USE_SHMEM
|
||||
key_t shm_key;
|
||||
key_t shm_sem_key;
|
||||
int shm_id;
|
||||
int shm_size;
|
||||
void *shm_data = NULL;
|
||||
int shm_data_existed = 0;
|
||||
|
||||
shm_mk_keys(&shm_key, &shm_sem_key);
|
||||
|
||||
/* max. shm_n_games simultaneous games recorded in the shared memory */
|
||||
shm_size = sizeof(struct dg_shm) + shm_n_games * sizeof(struct dg_shm_game);
|
||||
|
||||
/* connect to (and possibly create) the segment */
|
||||
if ((shm_id = shmget(shm_key, shm_size, 0644 | IPC_CREAT | IPC_EXCL)) == -1) {
|
||||
/* creation failed, so it already exists. attach to it */
|
||||
shm_data_existed = 1;
|
||||
if ((shm_id = shmget(shm_key, shm_size, 0644)) == -1) {
|
||||
debug_write("shmget");
|
||||
graceful_exit(73);
|
||||
}
|
||||
}
|
||||
|
||||
/* attach to the segment to get a pointer to it: */
|
||||
shm_data = shmat(shm_id, (void *)0, 0);
|
||||
if (shm_data == (char *)(-1)) {
|
||||
debug_write("shmat");
|
||||
graceful_exit(74);
|
||||
}
|
||||
if (!shm_data) {
|
||||
debug_write("shm_data == null");
|
||||
graceful_exit(75);
|
||||
}
|
||||
|
||||
(*shm_dg_data) = (struct dg_shm *)shm_data;
|
||||
(*shm_dg_game) = (struct dg_shm_game *)(shm_data + sizeof(struct dg_shm));
|
||||
|
||||
if (!shm_data_existed && shm_data) {
|
||||
memset(*shm_dg_game, 0, shm_n_games*sizeof(struct dg_shm_game));
|
||||
(*shm_dg_data)->max_n_games = shm_n_games;
|
||||
(*shm_dg_data)->cur_n_games = 0;
|
||||
if (sem_init(&((*shm_dg_data)->dg_sem), 1,1) == -1) {
|
||||
debug_write("sem_init");
|
||||
graceful_exit(76);
|
||||
}
|
||||
}
|
||||
#endif /* USE_SHMEM */
|
||||
}
|
||||
|
||||
void
|
||||
inprogressmenu (int gameid)
|
||||
{
|
||||
const char *selectorchars = "abcdefghijklmnoprstuvwxyzABCDEFGHIJKLMNOPRSTUVWXYZ";
|
||||
int i, menuchoice, len = 20, offset = 0;
|
||||
static dg_sortmode sortmode = NUM_SORTMODES;
|
||||
time_t ctime;
|
||||
struct dg_game **games = NULL;
|
||||
char ttyrecname[130], gametype[10];
|
||||
char ttyrecname[130], gametype[10], idletime[10];
|
||||
int *is_nhext;
|
||||
sigset_t oldmask, toblock;
|
||||
int idx = -1;
|
||||
int shm_idx = -1;
|
||||
int max_height = -1;
|
||||
int selected = -1;
|
||||
|
||||
@ -438,6 +581,11 @@ inprogressmenu (int gameid)
|
||||
|
||||
int require_enter = 0; /* TODO: make configurable */
|
||||
|
||||
int di;
|
||||
|
||||
struct dg_shm *shm_dg_data = NULL;
|
||||
struct dg_shm_game *shm_dg_game = NULL;
|
||||
|
||||
if (sortmode == NUM_SORTMODES)
|
||||
sortmode = globalconfig.sortmode;
|
||||
|
||||
@ -449,7 +597,10 @@ inprogressmenu (int gameid)
|
||||
graceful_exit(70);
|
||||
}
|
||||
|
||||
shm_init(&shm_dg_data, &shm_dg_game);
|
||||
|
||||
games = populate_games (gameid, &len, NULL); /* FIXME: should be 'me' instead of 'NULL' */
|
||||
shm_update(shm_dg_data, games, len);
|
||||
games = sort_games (games, len, sortmode);
|
||||
|
||||
while (1)
|
||||
@ -492,10 +643,15 @@ inprogressmenu (int gameid)
|
||||
dgl_sortprintw(SORTMODE_WINDOWSIZE, 29, "Size")
|
||||
dgl_sortprintw(SORTMODE_STARTTIME, 37, "Start date & time")
|
||||
dgl_sortprintw(SORTMODE_IDLETIME, 58, "Idle time")
|
||||
#ifdef USE_SHMEM
|
||||
dgl_sortprintw(SORTMODE_WATCHERS, 70, "Watchers")
|
||||
#endif
|
||||
|
||||
#undef dgl_sortprintw
|
||||
}
|
||||
|
||||
shm_sem_wait(shm_dg_data);
|
||||
|
||||
for (i = 0; i < max_height; i++)
|
||||
{
|
||||
if (i + offset >= len)
|
||||
@ -511,16 +667,40 @@ inprogressmenu (int gameid)
|
||||
snprintf (gametype, sizeof gametype, "%3dx%3d",
|
||||
games[i + offset]->ws_col, games[i + offset]->ws_row);
|
||||
|
||||
mvprintw (top_banner_hei + 1 + i, 1, "%c) %-15s %-5s %s %s %s %ldm %lds",
|
||||
#ifdef USE_SHMEM
|
||||
# define WATCH_LINE_FORMAT "%c) %-15s %-5s %s %s %s %-10s %i"
|
||||
#else
|
||||
# define WATCH_LINE_FORMAT "%c) %-15s %-5s %s %s %s %-10s"
|
||||
#endif
|
||||
{
|
||||
time_t ctime;
|
||||
(void) time(&ctime);
|
||||
long secs = (ctime - games[i + offset]->idle_time) % 60;
|
||||
long mins = (ctime - games[i + offset]->idle_time) / 60;
|
||||
long hours= (ctime - games[i + offset]->idle_time) / (60*60);
|
||||
if (hours)
|
||||
snprintf(idletime, 10, "%ldh %ldm", hours, mins);
|
||||
else
|
||||
snprintf(idletime, 10, "%ldm %lds", mins, secs);
|
||||
}
|
||||
|
||||
mvprintw (top_banner_hei + 1 + i, 1, WATCH_LINE_FORMAT,
|
||||
selectorchars[i], games[i + offset]->name, myconfig[games[i + offset]->gamenum]->shortname, gametype,
|
||||
games[i + offset]->date, games[i + offset]->time,
|
||||
(time (&ctime) - games[i + offset]->idle_time) / 60,
|
||||
(time (&ctime) - games[i + offset]->idle_time) % 60);
|
||||
idletime,
|
||||
#ifdef USE_SHMEM
|
||||
(games[i+offset]->is_in_shm ? shm_dg_game[games[i+offset]->shm_idx].nwatchers : -1)
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
);
|
||||
|
||||
if (i + offset == selected) attroff(selected_attr);
|
||||
|
||||
}
|
||||
|
||||
shm_sem_post(shm_dg_data);
|
||||
|
||||
btm = dgl_local_LINES-btm_banner_hei-top_banner_hei;
|
||||
if (btm > i) btm = i+1;
|
||||
if (len > 0) {
|
||||
@ -592,6 +772,9 @@ inprogressmenu (int gameid)
|
||||
case 'q': case 'Q':
|
||||
if (is_nhext) free(is_nhext);
|
||||
free_populated_games(games, len);
|
||||
#ifdef USE_SHMEM
|
||||
shmdt(shm_dg_data);
|
||||
#endif
|
||||
return;
|
||||
|
||||
case '.':
|
||||
@ -643,7 +826,16 @@ watchgame:
|
||||
clear ();
|
||||
refresh ();
|
||||
endwin ();
|
||||
|
||||
#ifdef USE_SHMEM
|
||||
if (games[idx]->is_in_shm) {
|
||||
shm_idx = games[idx]->shm_idx;
|
||||
shm_sem_wait(shm_dg_data);
|
||||
if (shm_dg_game[shm_idx].in_use &&
|
||||
!strcmp(shm_dg_game[shm_idx].ttyrec_fn, games[idx]->ttyrec_fn))
|
||||
shm_dg_game[shm_idx].nwatchers++;
|
||||
shm_sem_post(shm_dg_data);
|
||||
}
|
||||
#endif
|
||||
resizey = games[idx]->ws_row;
|
||||
resizex = games[idx]->ws_col;
|
||||
if (loggedin)
|
||||
@ -655,6 +847,16 @@ watchgame:
|
||||
setproctitle("%s", me->username);
|
||||
else
|
||||
setproctitle("<Anonymous>");
|
||||
#ifdef USE_SHMEM
|
||||
if (games[idx]->is_in_shm) {
|
||||
shm_sem_wait(shm_dg_data);
|
||||
if (shm_dg_game[shm_idx].in_use &&
|
||||
!strcmp(shm_dg_game[shm_idx].ttyrec_fn, games[idx]->ttyrec_fn) &&
|
||||
(shm_dg_game[shm_idx].nwatchers > 0))
|
||||
shm_dg_game[shm_idx].nwatchers--;
|
||||
shm_sem_post(shm_dg_data);
|
||||
}
|
||||
#endif
|
||||
initcurses ();
|
||||
}
|
||||
}
|
||||
@ -662,6 +864,7 @@ watchgame:
|
||||
if (selected >= 0 && selected < len)
|
||||
selectedgame = strdup(games[selected]->name);
|
||||
games = populate_games (gameid, &len, NULL); /* FIXME: should be 'me' instead of 'NULL' */
|
||||
shm_update(shm_dg_data, games, len);
|
||||
games = sort_games (games, len, sortmode);
|
||||
if (selectedgame) {
|
||||
selected = -1;
|
||||
@ -676,6 +879,9 @@ watchgame:
|
||||
}
|
||||
if (is_nhext) free(is_nhext);
|
||||
free_populated_games(games, len);
|
||||
#ifdef USE_SHMEM
|
||||
shmdt(shm_dg_data);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ************************************************************* */
|
||||
@ -2061,7 +2267,7 @@ main (int argc, char** argv)
|
||||
|
||||
__progname = basename(strdup(argv[0]));
|
||||
|
||||
while ((c = getopt(argc, argv, "qh:pf:aeW:")) != -1)
|
||||
while ((c = getopt(argc, argv, "qh:pf:aeW:S")) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
@ -2089,6 +2295,26 @@ main (int argc, char** argv)
|
||||
wall_email_str = strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'S': /* Free the shared memory block */
|
||||
{
|
||||
#ifdef USE_SHMEM
|
||||
key_t shm, sem;
|
||||
int shm_id;
|
||||
int shm_size = sizeof(struct dg_shm) + shm_n_games * sizeof(struct dg_shm_game);
|
||||
shm_mk_keys(&shm, &sem);
|
||||
if ((shm_id = shmget(shm, shm_size, 0644)) != -1) {
|
||||
shmctl(shm_id, IPC_RMID, NULL);
|
||||
if (!silent) fprintf(stderr, "shmem block freed.\n");
|
||||
} else {
|
||||
if (!silent) fprintf(stderr, "nonexistent shmem block.\n");
|
||||
}
|
||||
#else
|
||||
if (!silent) fprintf(stderr, "warning: dgamelaunch was compiled without shmem.\n");
|
||||
#endif
|
||||
graceful_exit(0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break; /*ignore */
|
||||
}
|
||||
|
@ -9,6 +9,10 @@
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef USE_SHMEM
|
||||
#include <semaphore.h>
|
||||
#endif
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
#endif
|
||||
@ -77,6 +81,22 @@ struct dg_menulist
|
||||
struct dg_menulist *next;
|
||||
};
|
||||
|
||||
struct dg_shm
|
||||
{
|
||||
#ifdef USE_SHMEM
|
||||
sem_t dg_sem;
|
||||
#endif
|
||||
int max_n_games;
|
||||
int cur_n_games;
|
||||
};
|
||||
|
||||
struct dg_shm_game
|
||||
{
|
||||
int in_use;
|
||||
int nwatchers;
|
||||
char ttyrec_fn[150];
|
||||
};
|
||||
|
||||
struct dg_game
|
||||
{
|
||||
char *ttyrec_fn;
|
||||
@ -86,6 +106,9 @@ struct dg_game
|
||||
time_t idle_time;
|
||||
int ws_row, ws_col; /* Window size */
|
||||
int gamenum;
|
||||
int is_in_shm;
|
||||
int shm_idx;
|
||||
int nwatchers;
|
||||
};
|
||||
|
||||
struct dg_config
|
||||
@ -157,6 +180,9 @@ typedef enum
|
||||
SORTMODE_WINDOWSIZE,
|
||||
SORTMODE_STARTTIME,
|
||||
SORTMODE_IDLETIME,
|
||||
#ifdef USE_SHMEM
|
||||
SORTMODE_WATCHERS,
|
||||
#endif
|
||||
NUM_SORTMODES
|
||||
} dg_sortmode;
|
||||
|
||||
@ -166,11 +192,16 @@ static const char *SORTMODE_NAME[NUM_SORTMODES] = {
|
||||
"Game",
|
||||
"Windowsize",
|
||||
"Starttime",
|
||||
"Idletime"
|
||||
"Idletime",
|
||||
#ifdef USE_SHMEM
|
||||
"Watchers",
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/* Global variables */
|
||||
extern int shm_n_games; /* TODO: make configurable */
|
||||
|
||||
extern char* config; /* file path */
|
||||
extern struct dg_config **myconfig;
|
||||
extern char *chosen_name;
|
||||
|
21
dgl-common.c
21
dgl-common.c
@ -55,6 +55,8 @@ int loggedin = 0;
|
||||
char *chosen_name;
|
||||
int num_games = 0;
|
||||
|
||||
int shm_n_games = 200;
|
||||
|
||||
int dgl_local_COLS = -1, dgl_local_LINES = -1;
|
||||
int curses_resize = 0;
|
||||
|
||||
@ -432,6 +434,19 @@ sort_game_starttime(const void *g1, const void *g2)
|
||||
return i;
|
||||
}
|
||||
|
||||
static int
|
||||
sort_game_watchers(const void *g1, const void *g2)
|
||||
{
|
||||
const struct dg_game *game1 = *(const struct dg_game **)g1;
|
||||
const struct dg_game *game2 = *(const struct dg_game **)g2;
|
||||
int i = dglsign(game1->nwatchers - game2->nwatchers);
|
||||
if (!i)
|
||||
i = strcmp(game1->time, game2->time);
|
||||
if (!i)
|
||||
return strcasecmp(game1->name, game2->name);
|
||||
return i;
|
||||
}
|
||||
|
||||
struct dg_game **
|
||||
sort_games (struct dg_game **games, int len, dg_sortmode sortmode)
|
||||
{
|
||||
@ -441,6 +456,9 @@ sort_games (struct dg_game **games, int len, dg_sortmode sortmode)
|
||||
case SORTMODE_WINDOWSIZE: qsort(games, len, sizeof(struct dg_game *), sort_game_windowsize); break;
|
||||
case SORTMODE_IDLETIME: qsort(games, len, sizeof(struct dg_game *), sort_game_idletime); break;
|
||||
case SORTMODE_STARTTIME: qsort(games, len, sizeof(struct dg_game *), sort_game_starttime); break;
|
||||
#ifdef USE_SHMEM
|
||||
case SORTMODE_WATCHERS: qsort(games, len, sizeof(struct dg_game *), sort_game_watchers); break;
|
||||
#endif
|
||||
default: ;
|
||||
}
|
||||
return games;
|
||||
@ -573,6 +591,9 @@ populate_games (int xgame, int *l, struct dg_user *me)
|
||||
games[len]->idle_time = pstat.st_mtime;
|
||||
|
||||
games[len]->gamenum = game;
|
||||
games[len]->is_in_shm = 0;
|
||||
games[len]->nwatchers = 0;
|
||||
games[len]->shm_idx = -1;
|
||||
|
||||
n = read(fd, pidws, sizeof(pidws) - 1);
|
||||
if (n > 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user