initial commit
This commit is contained in:
commit
8c8158ad5b
7 changed files with 724 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
prezzyd
|
||||||
|
prezzyc
|
||||||
|
*.o
|
25
Makefile
Normal file
25
Makefile
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
CC = cc
|
||||||
|
CFLAGS = -std=c99 -O2 -pedantic -Wall -Wextra
|
||||||
|
LDFLAGS = -ldiscord-rpc
|
||||||
|
OBJS = prezzyipc.o
|
||||||
|
|
||||||
|
all: prezzyd prezzyc
|
||||||
|
|
||||||
|
prezzyd: prezzyd.o ${OBJS}
|
||||||
|
cc ${CFLAGS} -o $@ prezzyd.o ${OBJS} ${LDFLAGS}
|
||||||
|
prezzyc: prezzyc.o ${OBJS}
|
||||||
|
cc ${CFLAGS} -o $@ prezzyc.o ${OBJS} ${LDFLAGS}
|
||||||
|
|
||||||
|
.SUFFIXES: .c .o
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
${CC} ${CFLAGS} -DBUILD_DATE=\"$$(date -I)\" -c $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f prezzyd prezzyc prezzyd.o prezzyc.o ${OBJS}
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
|
|
||||||
|
prezzyd.o: prezzyd.c prezzyipc.h discord_rpc.h
|
||||||
|
prezzyc.o: prezzyc.c prezzyipc.h
|
||||||
|
prezzyipc.o: prezzyipc.c prezzyipc.h
|
87
discord_rpc.h
Normal file
87
discord_rpc.h
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#if defined(DISCORD_DYNAMIC_LIB)
|
||||||
|
# if defined(_WIN32)
|
||||||
|
# if defined(DISCORD_BUILDING_SDK)
|
||||||
|
# define DISCORD_EXPORT __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define DISCORD_EXPORT __declspec(dllimport)
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# define DISCORD_EXPORT __attribute__((visibility("default")))
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define DISCORD_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct DiscordRichPresence {
|
||||||
|
const char* state; /* max 128 bytes */
|
||||||
|
const char* details; /* max 128 bytes */
|
||||||
|
int64_t startTimestamp;
|
||||||
|
int64_t endTimestamp;
|
||||||
|
const char* largeImageKey; /* max 32 bytes */
|
||||||
|
const char* largeImageText; /* max 128 bytes */
|
||||||
|
const char* smallImageKey; /* max 32 bytes */
|
||||||
|
const char* smallImageText; /* max 128 bytes */
|
||||||
|
const char* partyId; /* max 128 bytes */
|
||||||
|
int partySize;
|
||||||
|
int partyMax;
|
||||||
|
const char* matchSecret; /* max 128 bytes */
|
||||||
|
const char* joinSecret; /* max 128 bytes */
|
||||||
|
const char* spectateSecret; /* max 128 bytes */
|
||||||
|
int8_t instance;
|
||||||
|
} DiscordRichPresence;
|
||||||
|
|
||||||
|
typedef struct DiscordUser {
|
||||||
|
const char* userId;
|
||||||
|
const char* username;
|
||||||
|
const char* discriminator;
|
||||||
|
const char* avatar;
|
||||||
|
} DiscordUser;
|
||||||
|
|
||||||
|
typedef struct DiscordEventHandlers {
|
||||||
|
void (*ready)(const DiscordUser* request);
|
||||||
|
void (*disconnected)(int errorCode, const char* message);
|
||||||
|
void (*errored)(int errorCode, const char* message);
|
||||||
|
void (*joinGame)(const char* joinSecret);
|
||||||
|
void (*spectateGame)(const char* spectateSecret);
|
||||||
|
void (*joinRequest)(const DiscordUser* request);
|
||||||
|
} DiscordEventHandlers;
|
||||||
|
|
||||||
|
#define DISCORD_REPLY_NO 0
|
||||||
|
#define DISCORD_REPLY_YES 1
|
||||||
|
#define DISCORD_REPLY_IGNORE 2
|
||||||
|
|
||||||
|
DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
|
||||||
|
DiscordEventHandlers* handlers,
|
||||||
|
int autoRegister,
|
||||||
|
const char* optionalSteamId);
|
||||||
|
DISCORD_EXPORT void Discord_Shutdown(void);
|
||||||
|
|
||||||
|
/* checks for incoming messages, dispatches callbacks */
|
||||||
|
DISCORD_EXPORT void Discord_RunCallbacks(void);
|
||||||
|
|
||||||
|
/* If you disable the lib starting its own io thread, you'll need to call this from your own */
|
||||||
|
#ifdef DISCORD_DISABLE_IO_THREAD
|
||||||
|
DISCORD_EXPORT void Discord_UpdateConnection(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence);
|
||||||
|
DISCORD_EXPORT void Discord_ClearPresence(void);
|
||||||
|
|
||||||
|
DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply);
|
||||||
|
|
||||||
|
DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* handlers);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
146
prezzyc.c
Normal file
146
prezzyc.c
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
/*
|
||||||
|
* prezzyc
|
||||||
|
* Copyright (c) 2024 Jeremy Baxter.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _PREZZYC_C_
|
||||||
|
#define _DEFAULT_SOURCE
|
||||||
|
|
||||||
|
#ifndef BUILD_DATE
|
||||||
|
#define BUILD_DATE "1970-01-01"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "prezzyipc.h"
|
||||||
|
#include "discord_rpc.h"
|
||||||
|
|
||||||
|
static PrezzyIpcPacket **packets;
|
||||||
|
static int packetCount;
|
||||||
|
|
||||||
|
void
|
||||||
|
addPacket(PrezzyProperty property, PrezzyPayloadType type,
|
||||||
|
char *pString, int64_t pInteger)
|
||||||
|
{
|
||||||
|
PrezzyIpcPacket *p;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
p = malloc(sizeof(PrezzyIpcPacket));
|
||||||
|
p->property = property;
|
||||||
|
p->type = type;
|
||||||
|
if (type == PLT_STRING) {
|
||||||
|
len = strlen(pString) + 1;
|
||||||
|
p->pString = malloc(len * sizeof(char));
|
||||||
|
strbcpy(p->pString, pString, len);
|
||||||
|
} else
|
||||||
|
p->pInteger = pInteger;
|
||||||
|
|
||||||
|
packetCount++;
|
||||||
|
packets = realloc(packets,
|
||||||
|
packetCount * sizeof(PrezzyIpcPacket *));
|
||||||
|
packets[packetCount - 1] = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
getServer(const char *socketPath)
|
||||||
|
{
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
memset(&addr, 0, sizeof(struct sockaddr_un));
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strbcpy(addr.sun_path, socketPath, sizeof(addr.sun_path) - 1);
|
||||||
|
|
||||||
|
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
||||||
|
err(1, "failed to create IPC client socket");
|
||||||
|
if (connect(fd, (struct sockaddr *)&addr,
|
||||||
|
sizeof(struct sockaddr_un)) == -1)
|
||||||
|
err(1, "failed to establish connection to IPC daemon");
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fputs(
|
||||||
|
"usage: prezzyc [-aV] [-d details] [-I icon] [-i tooltip]\n"
|
||||||
|
" [-L large-image] [-l tooltip] [-s state]\n"
|
||||||
|
" [-P limit] [-p size] [-T end] [-t start]\n",
|
||||||
|
stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *buffer;
|
||||||
|
ssize_t sz;
|
||||||
|
int ch, i;
|
||||||
|
int server;
|
||||||
|
|
||||||
|
if (argc < 2) { /* no options? */
|
||||||
|
usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, "ad:I:i:L:l:P:p:s:T:t:V")) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'a': addPacket(PREZZY_TIMESTAMP_START, PLT_INT64, NULL, time(NULL)); break;
|
||||||
|
case 'd': addPacket(PREZZY_DETAILS, PLT_STRING, optarg, 0); break;
|
||||||
|
case 'I': addPacket(PREZZY_ICON, PLT_STRING, optarg, 0); break;
|
||||||
|
case 'i': addPacket(PREZZY_ICON_TOOLTIP, PLT_STRING, optarg, 0); break;
|
||||||
|
case 'L': addPacket(PREZZY_LARGE_IMAGE, PLT_STRING, optarg, 0); break;
|
||||||
|
case 'l': addPacket(PREZZY_LARGE_TOOLTIP, PLT_STRING, optarg, 0); break;
|
||||||
|
case 's': addPacket(PREZZY_STATE, PLT_STRING, optarg, 0); break;
|
||||||
|
case 'P': addPacket(PREZZY_PARTY_LIMIT, PLT_INT, NULL,
|
||||||
|
squashLong(strtol(optarg, NULL, 10))); break;
|
||||||
|
case 'p': addPacket(PREZZY_PARTY_SIZE, PLT_INT, NULL,
|
||||||
|
squashLong(strtol(optarg, NULL, 10))); break;
|
||||||
|
case 'T': addPacket(PREZZY_TIMESTAMP_END, PLT_INT64, NULL,
|
||||||
|
strtol(optarg, NULL, 10)); break;
|
||||||
|
case 't': addPacket(PREZZY_TIMESTAMP_START, PLT_INT64, NULL,
|
||||||
|
strtol(optarg, NULL, 10)); break;
|
||||||
|
case 'V':
|
||||||
|
printf("prezzyc version 0.1 built on " BUILD_DATE "\n");
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc - optind > 0) { /* extra arguments? */
|
||||||
|
usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
server = getServer(PREZZY_SOCK);
|
||||||
|
|
||||||
|
for (i = 0; i < packetCount; i++) {
|
||||||
|
buffer = fromIpcPacket(*packets[i]);
|
||||||
|
write(server, buffer, strlen(buffer));
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
write(server, "\0", 1);
|
||||||
|
|
||||||
|
buffer = malloc(PREZZY_PACKET_MAX * sizeof(char));
|
||||||
|
memset(buffer, 0, PREZZY_PACKET_MAX);
|
||||||
|
while ((sz = read(server, buffer, PREZZY_PACKET_MAX - 1)) > 0) {
|
||||||
|
if (buffer[0] != 0)
|
||||||
|
errx(1, "IPC error %d: %s", buffer[0], buffer + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sz == -1)
|
||||||
|
err(1, "failed to read from IPC server");
|
||||||
|
|
||||||
|
for (i = 0; i < packetCount; i++) {
|
||||||
|
if (packets[i]->type == PLT_STRING)
|
||||||
|
free(packets[i]->pString);
|
||||||
|
free(packets[i]);
|
||||||
|
}
|
||||||
|
free(packets);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
258
prezzyd.c
Normal file
258
prezzyd.c
Normal file
|
@ -0,0 +1,258 @@
|
||||||
|
/*
|
||||||
|
* prezzyd
|
||||||
|
* Copyright (c) 2024 Jeremy Baxter.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _PREZZYD_C_
|
||||||
|
#define _DEFAULT_SOURCE
|
||||||
|
|
||||||
|
#ifndef BUILD_DATE
|
||||||
|
#define BUILD_DATE "1970-01-01"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <err.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "prezzyipc.h"
|
||||||
|
#include "discord_rpc.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
connectHandler(const DiscordUser *user)
|
||||||
|
{
|
||||||
|
warnx("established connection to Discord (%s/%s)",
|
||||||
|
user->username, user->userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
disconnectHandler(int code, const char *message)
|
||||||
|
{
|
||||||
|
warnx("disconnected from client (%d: %s)", code, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
errorHandler(int code, const char *message)
|
||||||
|
{
|
||||||
|
errx(1, "rpc error %d: %s", code, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
canReadFrom(int fd)
|
||||||
|
{
|
||||||
|
struct pollfd *p;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
p = malloc(sizeof(struct pollfd));
|
||||||
|
p->fd = fd;
|
||||||
|
p->events = POLLIN;
|
||||||
|
|
||||||
|
if (poll(p, 1, 5000) == -1)
|
||||||
|
err(1, "failed to poll client");
|
||||||
|
|
||||||
|
ret = p->revents & POLLIN;
|
||||||
|
free(p);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ipcClose(int fd, byte code, const char *message)
|
||||||
|
{
|
||||||
|
write(fd, (char []){code}, 1);
|
||||||
|
write(fd, message, strlen(message));
|
||||||
|
if (close(fd) == -1)
|
||||||
|
err(1, "failed to close IPC connection");
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ipcSucceed(int fd)
|
||||||
|
{
|
||||||
|
ipcClose(fd, 0, "OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
makeIpcServer(const char *bindPath, int backlog)
|
||||||
|
{
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
||||||
|
err(1, "failed to create IPC socket");
|
||||||
|
|
||||||
|
if (remove(bindPath) == -1) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
err(1, "could not remove %s", bindPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&addr, 0, sizeof(struct sockaddr_un));
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strbcpy(addr.sun_path, bindPath, sizeof(addr.sun_path) - 1);
|
||||||
|
|
||||||
|
if (bind(fd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) == -1)
|
||||||
|
err(1, "failed to bind to %s", bindPath);
|
||||||
|
if (listen(fd, backlog) == -1)
|
||||||
|
err(1, "failed to listen on IPC socket %s", bindPath);
|
||||||
|
|
||||||
|
if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) == -1)
|
||||||
|
err(1, "failed to create non-blocking IPC socket");
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
void *propertyMapping[PREZZY_PROPERTY_MAX];
|
||||||
|
DiscordRichPresence presence;
|
||||||
|
DiscordEventHandlers handlers;
|
||||||
|
const char *clientId;
|
||||||
|
int ch, sd;
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, "V")) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'V':
|
||||||
|
printf("prezzyd version 0.1 built on " BUILD_DATE "\n");
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc - optind != 1) {
|
||||||
|
fputs("usage: prezzyd [-V] client-id\n", stderr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
clientId = argv[optind];
|
||||||
|
|
||||||
|
memset(&presence, 0, sizeof(DiscordRichPresence));
|
||||||
|
memset(&handlers, 0, sizeof(DiscordEventHandlers));
|
||||||
|
handlers.ready = connectHandler;
|
||||||
|
handlers.disconnected = disconnectHandler;
|
||||||
|
handlers.errored = errorHandler;
|
||||||
|
|
||||||
|
Discord_Initialize(clientId, &handlers, 1, NULL);
|
||||||
|
|
||||||
|
propertyMapping[PREZZY_STATE] = &presence.state;
|
||||||
|
propertyMapping[PREZZY_DETAILS] = &presence.details;
|
||||||
|
propertyMapping[PREZZY_LARGE_IMAGE] = &presence.largeImageKey;
|
||||||
|
propertyMapping[PREZZY_LARGE_TOOLTIP] = &presence.largeImageText;
|
||||||
|
propertyMapping[PREZZY_ICON] = &presence.smallImageKey;
|
||||||
|
propertyMapping[PREZZY_ICON_TOOLTIP] = &presence.smallImageText;
|
||||||
|
propertyMapping[PREZZY_PARTY_SIZE] = &presence.partySize;
|
||||||
|
propertyMapping[PREZZY_PARTY_LIMIT] = &presence.partyMax;
|
||||||
|
propertyMapping[PREZZY_TIMESTAMP_START] = &presence.startTimestamp;
|
||||||
|
propertyMapping[PREZZY_TIMESTAMP_END] = &presence.endTimestamp;
|
||||||
|
|
||||||
|
/* start ipc server */
|
||||||
|
sd = makeIpcServer(PREZZY_SOCK, 8);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
PrezzyIpcPacket **packets;
|
||||||
|
char buffer[PREZZY_PACKET_MAX];
|
||||||
|
ssize_t sz;
|
||||||
|
int client, i, packetCount;
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
packets = NULL;
|
||||||
|
packetCount = 0;
|
||||||
|
client = accept(sd, NULL, NULL);
|
||||||
|
|
||||||
|
if (client == -1) {
|
||||||
|
switch (errno) {
|
||||||
|
case EWOULDBLOCK:
|
||||||
|
goto update;
|
||||||
|
default:
|
||||||
|
err(1, "failed to accept incoming IPC connection");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IPC error codes:
|
||||||
|
* 1: error during initial read
|
||||||
|
* 2: bad request format
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!canReadFrom(client))
|
||||||
|
ipcClose(client, 1, "Timed out");
|
||||||
|
|
||||||
|
for (i = 0; (sz = read(client, &ch, 1)) > 0; i++) {
|
||||||
|
if (i == PREZZY_PACKET_MAX) {
|
||||||
|
ipcClose(client, 0, "OK (truncated)");
|
||||||
|
buffer[i - 1] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ch) {
|
||||||
|
case '\n':
|
||||||
|
case '\0':
|
||||||
|
/* end current packet */
|
||||||
|
if (i + 1 < 2 && /* are we before the payload? */
|
||||||
|
/* accept null bytes after newlines */
|
||||||
|
!(ch == '\0' && i == 0)) {
|
||||||
|
ipcClose(client, 2, "Request missing payload");
|
||||||
|
goto update;
|
||||||
|
}
|
||||||
|
if (buffer[0] < 0 || buffer[0] >= PREZZY_PROPERTY_MAX) {
|
||||||
|
ipcClose(client, 2, "Invalid property byte");
|
||||||
|
goto update;
|
||||||
|
}
|
||||||
|
buffer[i] = '\0';
|
||||||
|
|
||||||
|
packetCount++;
|
||||||
|
packets = realloc(packets, packetCount *
|
||||||
|
sizeof(PrezzyIpcPacket *));
|
||||||
|
packets[packetCount - 1] = makeIpcPacket(buffer);
|
||||||
|
|
||||||
|
if (ch == '\0') {
|
||||||
|
ipcSucceed(client);
|
||||||
|
goto process;
|
||||||
|
}
|
||||||
|
/* '\n'; more requests later */
|
||||||
|
i = -1;
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
buffer[i] = ch;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sz == -1)
|
||||||
|
err(1, "failed to read from IPC client");
|
||||||
|
|
||||||
|
process:
|
||||||
|
for (i = 0; i < packetCount; i++) {
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (packets[i]->type == PLT_STRING) {
|
||||||
|
len = strlen(packets[i]->pString) + 1;
|
||||||
|
*(char **)propertyMapping[packets[i]->property] =
|
||||||
|
malloc(len * sizeof(char));
|
||||||
|
strlcpy(*(char **)propertyMapping[packets[i]->property],
|
||||||
|
packets[i]->pString, len);
|
||||||
|
} else {
|
||||||
|
if (packets[i]->type == PLT_INT64) {
|
||||||
|
*(int64_t *)propertyMapping[packets[i]->property] =
|
||||||
|
packets[i]->pInteger;
|
||||||
|
} else {
|
||||||
|
*(int *)propertyMapping[packets[i]->property] =
|
||||||
|
squashLong(packets[i]->pInteger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update:
|
||||||
|
Discord_UpdatePresence(&presence);
|
||||||
|
Discord_RunCallbacks();
|
||||||
|
usleep(64000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Discord_Shutdown();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
132
prezzyipc.c
Normal file
132
prezzyipc.c
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* prezzyipc.c
|
||||||
|
* Copyright (c) 2024 Jeremy Baxter.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _PREZZYIPC_C_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "prezzyipc.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
dumpPacket(PrezzyIpcPacket p)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"[packet]\n"
|
||||||
|
"property = %d\n"
|
||||||
|
"type = %d\n"
|
||||||
|
"payload = ",
|
||||||
|
p.property, p.type);
|
||||||
|
if (p.type == PLT_STRING)
|
||||||
|
fprintf(stderr, "%s\n", p.pString);
|
||||||
|
else
|
||||||
|
fprintf(stderr, "%ld\n", p.pInteger);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
fromIpcPacket(PrezzyIpcPacket p)
|
||||||
|
{
|
||||||
|
char *buffer;
|
||||||
|
|
||||||
|
buffer = malloc(PREZZY_PACKET_MAX * sizeof(char));
|
||||||
|
|
||||||
|
if (p.type == PLT_STRING) {
|
||||||
|
snprintf(buffer, PREZZY_PACKET_MAX, "%c%s\n",
|
||||||
|
p.property, p.pString);
|
||||||
|
} else {
|
||||||
|
snprintf(buffer, PREZZY_PACKET_MAX, "%c%ld\n",
|
||||||
|
p.property, p.pInteger);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrezzyIpcPacket *
|
||||||
|
makeIpcPacket(const char *buffer)
|
||||||
|
{
|
||||||
|
PrezzyIpcPacket *m;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
m = malloc(sizeof(PrezzyIpcPacket));
|
||||||
|
|
||||||
|
/* extract property */
|
||||||
|
m->property = buffer[0];
|
||||||
|
if (m->property < 0 || m->property >= PREZZY_PROPERTY_MAX)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* determine payload type */
|
||||||
|
m->type = payloadTypeMapping[m->property];
|
||||||
|
|
||||||
|
switch (m->type) {
|
||||||
|
case PLT_STRING:
|
||||||
|
m->pString = NULL;
|
||||||
|
for (i = 1; buffer[i] != '\n' && buffer[i] != '\0'
|
||||||
|
&& i < PREZZY_PACKET_MAX; i++) {
|
||||||
|
m->pString = realloc(m->pString, (i + 1) * sizeof(char));
|
||||||
|
m->pString[i - 1] = buffer[i];
|
||||||
|
m->pString[i] = '\0';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PLT_INT64:
|
||||||
|
m->pInteger = strtol(buffer + 1, NULL, 10);
|
||||||
|
break;
|
||||||
|
case PLT_INT:
|
||||||
|
m->pInteger = squashLong(strtol(buffer + 1, NULL, 10));
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
squashLong(long l)
|
||||||
|
{
|
||||||
|
return (l >= INT_MIN && l <= INT_MAX) ? l : INT_MAX ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy string src to buffer dst of size dsize. At most dsize-1
|
||||||
|
* chars will be copied. Always NUL terminates (unless dsize == 0).
|
||||||
|
* Returns strlen(src); if retval >= dsize, truncation occurred.
|
||||||
|
*/
|
||||||
|
size_t
|
||||||
|
strbcpy(char *dst, const char *src, size_t dsize)
|
||||||
|
{
|
||||||
|
const char *osrc = src;
|
||||||
|
size_t nleft = dsize;
|
||||||
|
|
||||||
|
/* Copy as many bytes as will fit. */
|
||||||
|
if (nleft != 0) {
|
||||||
|
while (--nleft != 0) {
|
||||||
|
if ((*dst++ = *src++) == '\0')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Not enough room in dst, add NUL and traverse rest of src. */
|
||||||
|
if (nleft == 0) {
|
||||||
|
if (dsize != 0)
|
||||||
|
*dst = '\0'; /* NUL-terminate dst */
|
||||||
|
while (*src++)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (src - osrc - 1); /* count does not include NUL */
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
stringFrom(const char *reference)
|
||||||
|
{
|
||||||
|
char *buffer;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
len = strlen(reference) + 1;
|
||||||
|
buffer = malloc(len * sizeof(char));
|
||||||
|
strbcpy(buffer, reference, len);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
73
prezzyipc.h
Normal file
73
prezzyipc.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* prezzyipc.h
|
||||||
|
* Copyright (c) 2024 Jeremy Baxter.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PREZZYIPC_H_
|
||||||
|
#define _PREZZYIPC_H_
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define PREZZY_PACKET_MAX 1024
|
||||||
|
#define PREZZY_SOCK "/tmp/prezzyd.sock"
|
||||||
|
|
||||||
|
typedef char byte;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PREZZY_STATE = 1,
|
||||||
|
PREZZY_DETAILS = 2,
|
||||||
|
PREZZY_LARGE_IMAGE = 3,
|
||||||
|
PREZZY_LARGE_TOOLTIP = 4,
|
||||||
|
PREZZY_ICON = 5,
|
||||||
|
PREZZY_ICON_TOOLTIP = 6,
|
||||||
|
PREZZY_PARTY_SIZE = 7,
|
||||||
|
PREZZY_PARTY_LIMIT = 8,
|
||||||
|
PREZZY_TIMESTAMP_START = 9,
|
||||||
|
PREZZY_TIMESTAMP_END = 10,
|
||||||
|
PREZZY_PROPERTY_MAX = 11
|
||||||
|
} PrezzyProperty;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PLT_STRING = 1,
|
||||||
|
PLT_INT64 = 2,
|
||||||
|
PLT_INT = 3,
|
||||||
|
PLT_MAX = 4
|
||||||
|
} PrezzyPayloadType;
|
||||||
|
|
||||||
|
#ifdef _PREZZYIPC_C_
|
||||||
|
PrezzyPayloadType payloadTypeMapping[PREZZY_PROPERTY_MAX] = {
|
||||||
|
[PREZZY_STATE] = PLT_STRING,
|
||||||
|
[PREZZY_DETAILS] = PLT_STRING,
|
||||||
|
[PREZZY_LARGE_IMAGE] = PLT_STRING,
|
||||||
|
[PREZZY_LARGE_TOOLTIP] = PLT_STRING,
|
||||||
|
[PREZZY_ICON] = PLT_STRING,
|
||||||
|
[PREZZY_ICON_TOOLTIP] = PLT_STRING,
|
||||||
|
[PREZZY_PARTY_SIZE] = PLT_INT,
|
||||||
|
[PREZZY_PARTY_LIMIT] = PLT_INT,
|
||||||
|
[PREZZY_TIMESTAMP_START] = PLT_INT64,
|
||||||
|
[PREZZY_TIMESTAMP_END] = PLT_INT64
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
extern PrezzyPayloadType payloadTypeMapping[PREZZY_PROPERTY_MAX];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PrezzyProperty property;
|
||||||
|
PrezzyPayloadType type;
|
||||||
|
char *pString;
|
||||||
|
int64_t pInteger;
|
||||||
|
} PrezzyIpcPacket;
|
||||||
|
|
||||||
|
void dumpPacket(PrezzyIpcPacket);
|
||||||
|
char *fromIpcPacket(PrezzyIpcPacket);
|
||||||
|
PrezzyIpcPacket *makeIpcPacket(const char *);
|
||||||
|
int squashLong(long);
|
||||||
|
size_t strbcpy(char *, const char *, size_t);
|
||||||
|
char *stringFrom(const char *);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Add a link
Reference in a new issue