Created
July 27, 2018 18:38
-
-
Save NaomiAmethyst/5920f4a1028d27fd870adf5d1b0128a8 to your computer and use it in GitHub Desktop.
v1x1 WASM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define WASM_EXPORT __attribute__((visibility("default"))) | |
/* v1x1.h: https://raw.githubusercontent.com/TableflippersAnonymous/v1x1/master/v1x1-modules/v1x1-modules-channel/v1x1-modules-channel-wasm/src/main/resources/v1x1.h */ | |
#ifndef _V1X1_H | |
#define _V1X1_H 1 | |
#ifdef __cplusplus | |
extern "C" { | |
#endif | |
#include <stdint.h> | |
#define EVENT_MESSAGE 0 | |
#define EVENT_SCHEDULER_NOTIFY 1 | |
#define EVENT_DISCORD_VOICE_STATE 2 | |
#define EVENT_HTTP_RESPONSE 3 | |
#define PLATFORM_TWITCH 1 | |
#define PLATFORM_DISCORD 2 | |
#define PLATFORM_SLACK 3 | |
#define PLATFORM_MIXER 4 | |
#define PLATFORM_YOUTUBE 5 | |
#define PLATFORM_CURSE 6 | |
#define PLATFORM_API 7 | |
#define HTTP_GET 0 | |
#define HTTP_POST 1 | |
#define HTTP_PUT 2 | |
#define HTTP_DELETE 3 | |
#define DISPLAYNAME_USER 0 | |
#define DISPLAYNAME_CHANNEL 1 | |
/* A standard UUID */ | |
struct v1x1_uuid { | |
uint64_t high; | |
uint64_t low; | |
} __attribute__((__packed__)); | |
/* A buffer. Used for strings and the like. */ | |
struct v1x1_buffer { | |
int32_t length; | |
void *buf; | |
} __attribute__((__packed__)); | |
/* A tenant is a grouping of channel_groups */ | |
struct v1x1_tenant { | |
struct v1x1_uuid id; | |
struct v1x1_buffer display_name; | |
} __attribute__((__packed__)); | |
/* A channel_group is a grouping of channels on a given platform */ | |
struct v1x1_channel_group { | |
struct v1x1_buffer id; | |
struct v1x1_buffer display_name; | |
uint8_t platform; | |
struct v1x1_tenant tenant; | |
} __attribute__((__packed__)); | |
/* A channel is a named location where messages are broadcast and received */ | |
struct v1x1_channel { | |
struct v1x1_buffer id; | |
struct v1x1_buffer display_name; | |
struct v1x1_channel_group channel_group; | |
} __attribute__((__packed__)); | |
/* A global_user is a grouping of users that belong to the same person */ | |
struct v1x1_global_user { | |
struct v1x1_uuid id; | |
} __attribute__((__packed__)); | |
/* A user is an actor on a given platform */ | |
struct v1x1_user { | |
struct v1x1_buffer id; | |
struct v1x1_buffer display_name; | |
uint8_t platform; | |
struct v1x1_global_user global_user; | |
} __attribute__((__packed__)); | |
/* A permission is a string that represents a privilege granted */ | |
struct v1x1_permission { | |
struct v1x1_buffer node; | |
} __attribute__((__packed__)); | |
/* A permission_set is a list of permissions granted to a user on a channel */ | |
struct v1x1_permission_set { | |
int32_t length; | |
struct v1x1_permission *permissions; | |
} __attribute__((__packed__)); | |
/* A message is a byte sequence sent from a user to a channel */ | |
struct v1x1_message { | |
struct v1x1_channel channel; | |
struct v1x1_user sender; | |
struct v1x1_buffer text; | |
struct v1x1_permission_set permissions; | |
} __attribute__((__packed__)); | |
/* An event_message is an event that is fired when a message is received */ | |
struct v1x1_event_message { | |
struct v1x1_message message; | |
} __attribute__((__packed__)); | |
/* An event_scheduler_notify is an event that is triggered by v1x1_schedule_once */ | |
struct v1x1_event_scheduler_notify { | |
struct v1x1_buffer payload; | |
} __attribute__((__packed__)); | |
/* A discord_voice_state is the state of a user's voice connection on the discord platform */ | |
struct v1x1_discord_voice_state { | |
struct v1x1_buffer guild_id; | |
struct v1x1_buffer channel_id; | |
struct v1x1_buffer user_id; | |
struct v1x1_buffer session_id; | |
uint8_t deaf; | |
uint8_t mute; | |
uint8_t self_deaf; | |
uint8_t self_mute; | |
uint8_t suppress; | |
} __attribute__((__packed__)); | |
/* An event_discord_voice_state is an event sent when a user's discord_voice_state changes */ | |
struct v1x1_event_discord_voice_state { | |
struct v1x1_discord_voice_state old_voice_state; | |
struct v1x1_discord_voice_state new_voice_state; | |
} __attribute__((__packed__)); | |
/* An http_header is a struct describing a single HTTP header */ | |
struct v1x1_http_header { | |
struct v1x1_buffer name; | |
struct v1x1_buffer value; | |
} __attribute__((__packed__)); | |
/* An event_http_response is an event sent when an http request completes */ | |
struct v1x1_event_http_response { | |
int32_t response_code; | |
int32_t header_count; | |
struct v1x1_http_header *headers; | |
struct v1x1_buffer body; | |
struct v1x1_buffer event_payload; | |
} __attribute__((__packed__)); | |
/* An event is a struct describing the properties of a given change that is observed by v1x1 */ | |
struct v1x1_event { | |
uint8_t event_type; | |
union { | |
struct v1x1_event_message message_event; | |
struct v1x1_event_scheduler_notify scheduler_notify_event; | |
struct v1x1_event_discord_voice_state discord_voice_state_event; | |
struct v1x1_event_http_response http_response_event; | |
} data; | |
} __attribute__((__packed__)); | |
/* A channel_group_spec is a struct describing the channels that belong to a channel_group */ | |
struct v1x1_channel_group_spec { | |
struct v1x1_channel_group channel_group; | |
int32_t channel_count; | |
struct v1x1_channel *channels; | |
} __attribute__((__packed__)); | |
/* A tenant_spec is a struct describing the channel_groups that belong to a tenant */ | |
struct v1x1_tenant_spec { | |
struct v1x1_tenant tenant; | |
int32_t channel_group_count; | |
struct v1x1_channel_group_spec *channel_groups; | |
} __attribute__((__packed__)); | |
/* An http_request is a struct describing an HTTP request */ | |
struct v1x1_http_request { | |
int32_t verb; | |
struct v1x1_buffer uri; | |
int32_t header_count; | |
struct v1x1_http_header *headers; | |
struct v1x1_buffer body; | |
struct v1x1_buffer event_payload; | |
} __attribute__((__packed__)); | |
/** | |
* Get the size of the current event (in bytes) | |
* @return size of the current event | |
*/ | |
extern int32_t v1x1_event_size(void); | |
/** | |
* Read the current event into memory. | |
* @param ptr Location to read the current event into. | |
* @param len Max length of event to read | |
* @return non-zero on success | |
*/ | |
extern int32_t v1x1_read_event(void *ptr, int len); | |
/** | |
* Sends a chat message | |
* @param channel Channel to send message to | |
* @param message Text of message to send | |
* @return non-zero on success | |
*/ | |
extern int32_t v1x1_send_message(struct v1x1_channel *channel, struct v1x1_buffer *message); | |
/** | |
* Clear a user's messages from a channel | |
* @param channel Channel to clear messages from | |
* @param user User whose messages we should clear | |
* @param amount Number of messages to clear (if the platform supports it) | |
* @param reason Reason for clearing messages | |
* @return non-zero on success | |
*/ | |
extern int32_t v1x1_purge(struct v1x1_channel *channel, struct v1x1_user *user, int32_t amount, struct v1x1_buffer *reason); | |
/** | |
* Makes a user be quiet | |
* @param channel Channel where user is not being quiet | |
* @param user User to make quiet | |
* @param length Duration (in seconds) to make user quiet for | |
* @param reason Reason for making user quiet | |
* @return non-zero on success | |
*/ | |
extern int32_t v1x1_timeout(struct v1x1_channel *channel, struct v1x1_user *user, int32_t length, struct v1x1_buffer *reason); | |
/** | |
* Stop making a user be quiet | |
* @param channel Channel where the user has been made to be quiet | |
* @param user User who has been made to be quiet | |
* @return non-zero on success | |
*/ | |
extern int32_t v1x1_untimeout(struct v1x1_channel *channel, struct v1x1_user *user); | |
/** | |
* Temporarily remove a user from a channel | |
* @param channel Channel from which to remove the user | |
* @param user User to be removed | |
* @param reason Reason for removing the user | |
* @return non-zero on success | |
*/ | |
extern int32_t v1x1_kick(struct v1x1_channel *channel, struct v1x1_user *user, struct v1x1_buffer *reason); | |
/** | |
* Less temporarily remove a user from a channel | |
* @param channel Channel from which to remove the user | |
* @param user User to be removed | |
* @param length Duration (in seconds) before the user can come back, 0 for indefinite (if supported) | |
* @param reason Reason for removing the user | |
* @return non-zero on success | |
*/ | |
extern int32_t v1x1_ban(struct v1x1_channel *channel, struct v1x1_user *user, int32_t length, struct v1x1_buffer *reason); | |
/** | |
* Punish user in the minimal way supported by the platform | |
* @param channel Channel where the user should be punished | |
* @param user User to be punished | |
* @param length Duration (in seconds) to punish the user for (if supported) | |
* @param reason Reason for punishing the user | |
* @return non-zero on success | |
*/ | |
extern int32_t v1x1_punish(struct v1x1_channel *channel, struct v1x1_user *user, int32_t length, struct v1x1_buffer *reason); | |
/** | |
* Generates a SCHEDULER_NOTIFY event after a given duration | |
* @param minutes Duration (in minutes) to wait before delivering the SCHEDULER_NOTIFY event | |
* @param payload Payload to send in the SCHEDULER_NOTIFY event | |
* @return non-zero on success | |
*/ | |
extern int32_t v1x1_schedule_once(int32_t minutes, struct v1x1_buffer *payload); | |
/** | |
* Writes a value to the key-value store | |
* @param key Location to write the value | |
* @param val Value to write | |
* @return non-zero on success | |
*/ | |
extern int32_t v1x1_kvstore_write(struct v1x1_buffer *key, struct v1x1_buffer *val); | |
/** | |
* Checks if a value exists in the key-value store at a given key | |
* @param key Location to look for value | |
* @return non-zero if key has a value | |
*/ | |
extern int32_t v1x1_kvstore_has_key(struct v1x1_buffer *key); | |
/** | |
* Get the length of a value at a given key in the key-value store | |
* @param key Location to look for value | |
* @return Length of value, -1 if key does have a value | |
*/ | |
extern int32_t v1x1_kvstore_length(struct v1x1_buffer *key); | |
/** | |
* Reads a value from the key-value store | |
* @param key Location to read the value | |
* @param val Buffer to write the value to | |
* @return non-zero on success | |
*/ | |
extern int32_t v1x1_kvstore_read(struct v1x1_buffer *key, struct v1x1_buffer *val); | |
/** | |
* Deletes a value from the key-value store | |
* @param key Location to delete | |
* @return non-zero on success | |
*/ | |
extern int32_t v1x1_kvstore_delete(struct v1x1_buffer *key); | |
/** | |
* Logs a message | |
* @param message Message to be logged | |
* @return non-zero on success | |
*/ | |
extern int32_t v1x1_log(struct v1x1_buffer *message); | |
/** | |
* Gets the size of the current tenant spec (in bytes) | |
* @return size of tenant spec | |
*/ | |
extern int32_t v1x1_tenant_spec_size(void); | |
/** | |
* Gets the current tenant spec struct | |
* @param tenant_spec Struct to be filled | |
* @param len Length of allocated struct | |
* @return non-zero on success | |
*/ | |
extern int32_t v1x1_get_tenant_spec(struct v1x1_tenant_spec *tenant_spec, int32_t len); | |
/** | |
* Makes an HTTP request. Data will be returned via event | |
* to a random instance of your WebAssembly script. | |
* @param request Struct containing request data | |
* @return non-zero on success | |
*/ | |
extern int32_t v1x1_http(struct v1x1_http_request *request); | |
/** | |
* Gets a display_name for an entity | |
* @param display_name_type Type of entity | |
* @param platform Platform of entity | |
* @param id Buffer containing ID of entity | |
* @param display_name Buffer containing room to write display_name | |
* @return non-zero on success | |
*/ | |
extern int32_t v1x1_get_display_name(int32_t display_name_type, int32_t platform, struct v1x1_buffer *id, struct v1x1_buffer *display_name); | |
#ifdef __cplusplus | |
} | |
#endif | |
#endif | |
/* main.c: https://webassembly.studio/?f=me039czlxxs */ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdarg.h> | |
#include <string.h> | |
#include <errno.h> | |
struct v1x1_buffer mkbuffer(int32_t length, char *data) { | |
struct v1x1_buffer buffer = { | |
length, data | |
}; | |
return buffer; | |
} | |
struct v1x1_buffer mkstrbuffer(char *str) { | |
return mkbuffer(strlen(str), str); | |
} | |
void send_message(struct v1x1_channel *channel, char *message) { | |
struct v1x1_buffer buffer = mkstrbuffer(message); | |
v1x1_send_message(channel, &buffer); | |
} | |
void send_messagef(struct v1x1_channel *channel, char *format, ...) { | |
char buf[4096]; | |
va_list args; | |
va_start(args, format); | |
vsnprintf(buf, 4096, format, args); | |
send_message(channel, buf); | |
va_end(args); | |
} | |
WASM_EXPORT | |
void main(void) { | |
/* no initialize */ | |
} | |
WASM_EXPORT | |
void event_handler(void) { | |
int event_size = v1x1_event_size(); | |
if(event_size < 0) | |
return; | |
struct v1x1_event *evt = malloc(event_size); | |
v1x1_read_event(evt, event_size); | |
if(evt->event_type == EVENT_MESSAGE) { | |
struct v1x1_message *msg = &evt->data.message_event.message; | |
if(!strcmp(msg->text.buf, "!hellowasm")) { | |
send_messagef(&msg->channel, "Hi, %s!", msg->sender.display_name.buf); | |
} | |
} else if(evt->event_type == EVENT_DISCORD_VOICE_STATE) { | |
struct v1x1_discord_voice_state *old_voice_state = &evt->data.discord_voice_state_event.old_voice_state; | |
struct v1x1_discord_voice_state *new_voice_state = &evt->data.discord_voice_state_event.new_voice_state; | |
if(strcmp(old_voice_state->channel_id.buf, new_voice_state->channel_id.buf)) { | |
struct v1x1_channel channel = { | |
.id = mkstrbuffer("151174332582854656"), | |
.channel_group = { | |
.platform = PLATFORM_DISCORD, | |
.id = mkstrbuffer("97624850574622720") | |
} | |
}; | |
char channel_src[128]; | |
char channel_dst[128]; | |
char user[128]; | |
struct v1x1_buffer channel_src_buf = mkbuffer(127, channel_src); | |
struct v1x1_buffer channel_dst_buf = mkbuffer(127, channel_dst); | |
struct v1x1_buffer user_buf = mkbuffer(127, user); | |
if(old_voice_state->channel_id.length == 0) { | |
v1x1_get_display_name(DISPLAYNAME_USER, PLATFORM_DISCORD, &new_voice_state->user_id, &user_buf); | |
v1x1_get_display_name(DISPLAYNAME_CHANNEL, PLATFORM_DISCORD, &new_voice_state->channel_id, &channel_dst_buf); | |
send_messagef(&channel, "%s joined %s", user_buf.buf, channel_dst_buf.buf); | |
} else if(new_voice_state->channel_id.length == 0) { | |
v1x1_get_display_name(DISPLAYNAME_USER, PLATFORM_DISCORD, &old_voice_state->user_id, &user_buf); | |
v1x1_get_display_name(DISPLAYNAME_CHANNEL, PLATFORM_DISCORD, &old_voice_state->channel_id, &channel_src_buf); | |
send_messagef(&channel, "%s left %s", user_buf.buf, channel_src_buf.buf); | |
} else { | |
v1x1_get_display_name(DISPLAYNAME_USER, PLATFORM_DISCORD, &old_voice_state->user_id, &user_buf); | |
v1x1_get_display_name(DISPLAYNAME_CHANNEL, PLATFORM_DISCORD, &old_voice_state->channel_id, &channel_src_buf); | |
v1x1_get_display_name(DISPLAYNAME_CHANNEL, PLATFORM_DISCORD, &new_voice_state->channel_id, &channel_dst_buf); | |
send_messagef(&channel, "%s moved from %s to %s", user_buf.buf, channel_src_buf.buf, channel_dst_buf.buf); | |
} | |
} | |
} | |
free(evt); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment