@@ -1,63 +1,63 @@ | |||
*.d | |||
*.o | |||
*.ko | |||
*.obj | |||
*.elf | |||
*.ilk | |||
*.map | |||
*.exp | |||
*.gch | |||
*.pch | |||
*.lib | |||
*.a | |||
*.la | |||
*.lo | |||
*.dll | |||
*.so | |||
*.so.* | |||
*.dylib | |||
*.exe | |||
*.out | |||
*.app | |||
*.i*86 | |||
*.x86_64 | |||
*.hex | |||
*.dSYM/ | |||
*.su | |||
*.idb | |||
*.pdb | |||
*.mod* | |||
*.cmd | |||
.tmp_versions/ | |||
modules.order | |||
Module.symvers | |||
Mkfile.old | |||
dkms.conf | |||
CMakeLists.txt.user | |||
CMakeCache.txt | |||
CMakeFiles | |||
CMakeScripts | |||
Testing | |||
Makefile | |||
cmake_install.cmake | |||
install_manifest.txt | |||
compile_commands.json | |||
CTestTestfile.cmake | |||
_deps | |||
Thumbs.db | |||
Thumbs.db:encryptable | |||
ehthumbs.db | |||
ehthumbs_vista.db | |||
*.stackdump | |||
[Dd]esktop.ini | |||
$RECYCLE.BIN/ | |||
*.cab | |||
*.msi | |||
*.msix | |||
*.msm | |||
*.msp | |||
*.lnk | |||
.idea/ | |||
cmake-build-debug/ | |||
dependencies/ | |||
assets/ | |||
*.d | |||
*.o | |||
*.ko | |||
*.obj | |||
*.elf | |||
*.ilk | |||
*.map | |||
*.exp | |||
*.gch | |||
*.pch | |||
*.lib | |||
*.a | |||
*.la | |||
*.lo | |||
*.dll | |||
*.so | |||
*.so.* | |||
*.dylib | |||
*.exe | |||
*.out | |||
*.global_app | |||
*.i*86 | |||
*.x86_64 | |||
*.hex | |||
*.dSYM/ | |||
*.su | |||
*.idb | |||
*.pdb | |||
*.mod* | |||
*.cmd | |||
.tmp_versions/ | |||
modules.order | |||
Module.symvers | |||
Mkfile.old | |||
dkms.conf | |||
CMakeLists.txt.user | |||
CMakeCache.txt | |||
CMakeFiles | |||
CMakeScripts | |||
Testing | |||
Makefile | |||
cmake_install.cmake | |||
install_manifest.txt | |||
compile_commands.json | |||
CTestTestfile.cmake | |||
_deps | |||
Thumbs.db | |||
Thumbs.db:encryptable | |||
ehthumbs.db | |||
ehthumbs_vista.db | |||
*.stackdump | |||
[Dd]esktop.ini | |||
$RECYCLE.BIN/ | |||
*.cab | |||
*.msi | |||
*.msix | |||
*.msm | |||
*.msp | |||
*.lnk | |||
.idea/ | |||
cmake-build-debug/ | |||
dependencies/ | |||
assets/ |
@@ -70,7 +70,15 @@ add_executable( | |||
src/packages/game/input/IZ_midi.h | |||
src/packages/game/data/IZ_list.c | |||
src/packages/game/data/IZ_list.h | |||
src/packages/game/network/IZ_wsclient.c src/packages/game/network/IZ_wsclient.h src/packages/game/log/IZ_log.c src/packages/game/log/IZ_log.h src/packages/game/network/IZ_network.h) | |||
src/packages/game/network/IZ_wsclient.c | |||
src/packages/game/network/IZ_wsclient.h | |||
src/packages/game/log/IZ_log.c | |||
src/packages/game/log/IZ_log.h | |||
src/packages/game/util/IZ_midi.c | |||
src/packages/game/util/IZ_midi.h | |||
src/packages/game/network/IZ_websocket.h | |||
src/packages/game/network/IZ_websocket.c | |||
) | |||
target_link_libraries( | |||
game | |||
@@ -121,6 +129,9 @@ add_executable( | |||
src/packages/game/input/IZ_midi.h | |||
src/packages/game/input/IZ_midi.c | |||
src/packages/game/util/IZ_midi.c | |||
src/packages/game/util/IZ_midi.h | |||
src/packages/game/input/input.test.c | |||
) | |||
@@ -173,8 +184,12 @@ add_executable( | |||
src/packages/server/log/IZ_log.h | |||
src/packages/server/log/IZ_log.c | |||
src/packages/server/main.c | |||
src/packages/server/network/IZ_wsserver.c src/packages/server/IZ_app.c src/packages/server/IZ_app.h src/packages/server/network/IZ_wsserver.h | |||
src/packages/server/network/IZ_network.h | |||
src/packages/server/IZ_app.c | |||
src/packages/server/IZ_app.h | |||
src/packages/server/network/IZ_wsserver.c | |||
src/packages/server/network/IZ_wsserver.h | |||
src/packages/server/network/IZ_websocket.h | |||
src/packages/server/network/IZ_websocket.c | |||
) | |||
target_link_libraries( | |||
@@ -1,31 +1,51 @@ | |||
#include "IZ_app.h" | |||
IZ_ProcedureResult IZ_AppWSClientCallback( | |||
struct lws* wsi, | |||
enum lws_callback_reasons reason, | |||
void* userraw, | |||
void* in, | |||
size_t len | |||
) { | |||
IZ_App* user = userraw; | |||
switch (reason) { | |||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: | |||
printf("Client Connection Error %llu\n", len); | |||
return 1; | |||
case LWS_CALLBACK_CLIENT_CLOSED: | |||
printf("Client Closed %llu\n", len); | |||
return 0; | |||
case LWS_CALLBACK_CLIENT_RECEIVE: | |||
printf("Client Receive %llu\n", len); | |||
break; | |||
case LWS_CALLBACK_CLIENT_ESTABLISHED: | |||
printf("Client Established %llu\n", len); | |||
IZ_ProcedureResult IZ_AppWSClientInitialize(IZ_App* app) { | |||
IZ_WSClientInitializeParams params = { | |||
.address = "localhost", | |||
.path = "/", | |||
.port = 42069, | |||
}; | |||
if (IZ_WSClientInitialize(&app->client, params)) { | |||
printf("error\n"); | |||
return -1; | |||
} | |||
return 0; | |||
} | |||
IZ_ProcedureResult IZ_AppConnect(void* app_raw) { | |||
IZ_App* app = app_raw; | |||
if (IZ_AppWSClientInitialize(app)) { | |||
return -1; | |||
} | |||
i32 result = 0; | |||
while (true) { | |||
if (IZ_WSClientHandle(&app->client)) { | |||
result = 1; | |||
break; | |||
default: | |||
} | |||
if (app->client.ws.interrupted) { | |||
break; | |||
} | |||
} | |||
return 0; | |||
IZ_WSClientTeardown(&app->client); | |||
return result; | |||
} | |||
void IZ_AppEstablishConnection(IZ_App* app) { | |||
app->client_thread = SDL_CreateThread(IZ_AppConnect, "networking", app); | |||
SDL_DetachThread(app->client_thread); | |||
} | |||
void IZ_AppCloseConnection(IZ_App* app) { | |||
if (!app->client.ws.context) { | |||
return; | |||
} | |||
IZ_WSClientCancelService(&app->client); | |||
} | |||
IZ_ProcedureResult IZ_AppInitialize(IZ_App* app, u8 argc, const char* argv[]) { | |||
@@ -50,16 +70,15 @@ IZ_ProcedureResult IZ_AppInitialize(IZ_App* app, u8 argc, const char* argv[]) { | |||
IZ_ConfigGetDefaultPath(config_path, 128); | |||
} | |||
if (IZ_VideoInitialize(&app->video_state, config_path)) { | |||
if (IZ_VideoInitialize(&app->video_state, config_path, argc, argv)) { | |||
return IZ_APP_RUN_VIDEO_INIT_ERROR; | |||
} | |||
if (IZ_InputInitialize(&app->input_state, config_path)) { | |||
if (IZ_InputInitialize(&app->input_state, config_path, argc, argv)) { | |||
return IZ_APP_RUN_INPUT_INIT_ERROR; | |||
} | |||
IZ_PoolInitialize(&app->pool, POOL_MAX_SIZE); | |||
IZ_WSClientInitialize(&app->client); | |||
// TODO put into its timer module | |||
app->ticks = 0; | |||
@@ -67,7 +86,7 @@ IZ_ProcedureResult IZ_AppInitialize(IZ_App* app, u8 argc, const char* argv[]) { | |||
} | |||
void IZ_AppTeardown(IZ_App* app) { | |||
IZ_WSClientDisconnect(&app->client); | |||
IZ_AppCloseConnection(app); | |||
IZ_PoolTeardown(&app->pool); | |||
IZ_InputTeardown(&app->input_state); | |||
IZ_VideoTeardown(&app->video_state); | |||
@@ -82,10 +101,10 @@ IZ_ProcedureResult IZ_AppHandleSDLEvents(IZ_App* app) { | |||
} | |||
if (e.type == SDL_KEYDOWN) { | |||
if (e.key.keysym.sym == SDLK_PAGEUP) { | |||
// TODO connect | |||
if (e.key.keysym.sym == SDLK_PAGEUP && !app->client.ws.context) { | |||
IZ_AppEstablishConnection(app); | |||
} else if (e.key.keysym.sym == SDLK_PAGEDOWN) { | |||
// TODO disconnect | |||
IZ_AppCloseConnection(app); | |||
} | |||
} | |||
@@ -167,7 +186,6 @@ IZ_ProcedureResult IZ_AppRun(IZ_App* app, u8 argc, const char* argv[]) { | |||
//} | |||
if (IZ_AppHandleEvents(app)) { | |||
// TODO refactor input handlers to have same function signature. | |||
break; | |||
} | |||
@@ -22,7 +22,7 @@ typedef struct { | |||
IZ_VideoState video_state; | |||
IZ_Pool pool; | |||
IZ_WSClient client; | |||
IZ_WSClientState client; | |||
SDL_Thread* client_thread; | |||
u64 ticks; | |||
} IZ_App; | |||
@@ -1,15 +1,15 @@ | |||
#include "IZ_input.h" | |||
void IZ_InputHandleSDLEvents(IZ_InputState* state, SDL_Event e) { | |||
IZ_JoystickHandleEvents(e, &state->joystick_state, &state->action); | |||
IZ_KeyboardHandleEvents(e, &state->keyboard_state, &state->action); | |||
IZ_JoystickHandleEvents(&state->joystick_state, &state->action, e); | |||
IZ_KeyboardHandleEvents(&state->keyboard_state, &state->action, e); | |||
} | |||
void IZ_InputHandlePortMIDIEvents(IZ_InputState* state, PmEvent e) { | |||
IZ_MIDIInputHandleEvents(e, &state->midi_input_state, &state->action); | |||
IZ_MIDIInputHandleEvents(&state->midi_input_state, &state->action, e); | |||
} | |||
IZ_ProcedureResult IZ_InputInitialize(IZ_InputState* state, const char* config_path) { | |||
IZ_ProcedureResult IZ_InputInitialize(IZ_InputState* state, const char* config_path, u8 argc, const char** argv) { | |||
*state = (IZ_InputState) { | |||
.action = {}, | |||
.joystick_state = {}, | |||
@@ -19,18 +19,15 @@ IZ_ProcedureResult IZ_InputInitialize(IZ_InputState* state, const char* config_p | |||
IZ_ProcedureResult result = 0; | |||
IZ_ProcedureResult joystick_result = IZ_JoystickInitialize(config_path, &state->joystick_state); | |||
if (joystick_result) { | |||
if (IZ_JoystickInitialize(&state->joystick_state, config_path, argc, argv)) { | |||
result |= 1; | |||
} | |||
IZ_ProcedureResult keyboard_result = IZ_KeyboardInitialize(config_path, &state->keyboard_state); | |||
if (keyboard_result) { | |||
if (IZ_KeyboardInitialize(&state->keyboard_state, config_path, argc, argv)) { | |||
result |= 2; | |||
} | |||
IZ_ProcedureResult midi_input_result = IZ_MIDIInputInitialize(config_path, &state->midi_input_state); | |||
if (midi_input_result) { | |||
if (IZ_MIDIInputInitialize(&state->midi_input_state, config_path, argc, argv)) { | |||
result |= 4; | |||
} | |||
@@ -39,7 +36,7 @@ IZ_ProcedureResult IZ_InputInitialize(IZ_InputState* state, const char* config_p | |||
state->action[player_index] = 0; | |||
} | |||
return result; | |||
return -result; | |||
} | |||
void IZ_InputTeardown(IZ_InputState* state) { | |||
@@ -17,7 +17,7 @@ void IZ_InputHandleSDLEvents(IZ_InputState*, SDL_Event); | |||
void IZ_InputHandlePortMIDIEvents(IZ_InputState*, PmEvent); | |||
IZ_ProcedureResult IZ_InputInitialize(IZ_InputState*, const char*); | |||
IZ_ProcedureResult IZ_InputInitialize(IZ_InputState*, const char*, u8, const char**); | |||
void IZ_InputTeardown(IZ_InputState*); | |||
@@ -1,6 +1,6 @@ | |||
#include "IZ_joystick.h" | |||
void IZ_JoystickHandleDeviceEvents(SDL_Event e, IZ_JoystickState* state) { | |||
void IZ_JoystickHandleDeviceEvents(IZ_JoystickState* state, SDL_Event e) { | |||
if (e.type == SDL_JOYDEVICEADDED) { | |||
if (SDL_NumJoysticks() <= PLAYERS && !state->device) { | |||
state->device = SDL_JoystickOpen(e.jdevice.which); | |||
@@ -18,7 +18,7 @@ void IZ_JoystickHandleDeviceEvents(SDL_Event e, IZ_JoystickState* state) { | |||
} | |||
} | |||
void IZ_JoystickHandleAxisEvents(SDL_Event e, IZ_JoystickState* state, IZ_Action* action) { | |||
void IZ_JoystickHandleAxisEvents(IZ_JoystickState* state, IZ_Action* action, SDL_Event e) { | |||
if (e.type == SDL_JOYAXISMOTION) { | |||
if ( | |||
e.jaxis.axis == IZ_JOY_AXIS_DIRECTION_HORIZONTAL1 | |||
@@ -52,7 +52,7 @@ void IZ_JoystickHandleAxisEvents(SDL_Event e, IZ_JoystickState* state, IZ_Action | |||
} | |||
} | |||
void IZ_JoystickHandleHatEvents(SDL_Event e, IZ_Action* action) { | |||
void IZ_JoystickHandleHatEvents(IZ_Action* action, SDL_Event e) { | |||
if (e.type == SDL_JOYHATMOTION) { | |||
*action &= ~(0x1 << IZ_ACTION_INDEX_UP); | |||
*action &= ~(0x1 << IZ_ACTION_INDEX_RIGHT); | |||
@@ -64,7 +64,7 @@ void IZ_JoystickHandleHatEvents(SDL_Event e, IZ_Action* action) { | |||
} | |||
} | |||
void IZ_JoystickHandleButtonEvents(SDL_Event e, IZ_JoystickState* state, IZ_Action* action) { | |||
void IZ_JoystickHandleButtonEvents(IZ_JoystickState* state, IZ_Action* action, SDL_Event e) { | |||
u8 control_index; | |||
for (control_index = 4; control_index < CONTROLS; control_index += 1) { | |||
if (e.jbutton.button == state->config.control_mapping[control_index]) { | |||
@@ -83,17 +83,17 @@ void IZ_JoystickHandleButtonEvents(SDL_Event e, IZ_JoystickState* state, IZ_Acti | |||
} | |||
} | |||
void IZ_JoystickHandleEvents(SDL_Event e, IZ_JoystickState(* state)[PLAYERS], IZ_Action(* action)[PLAYERS]) { | |||
void IZ_JoystickHandleEvents(IZ_JoystickState(* state)[PLAYERS], IZ_Action(* action)[PLAYERS], SDL_Event e) { | |||
u8 player_index; | |||
for (player_index = 0; player_index < PLAYERS; player_index += 1) { | |||
IZ_JoystickHandleDeviceEvents(e, &(*state)[player_index]); | |||
IZ_JoystickHandleAxisEvents(e, &(*state)[player_index], &(*action)[player_index]); | |||
IZ_JoystickHandleHatEvents(e, &(*action)[player_index]); | |||
IZ_JoystickHandleButtonEvents(e, &(*state)[player_index], &(*action)[player_index]); | |||
IZ_JoystickHandleDeviceEvents(&(*state)[player_index], e); | |||
IZ_JoystickHandleAxisEvents(&(*state)[player_index], &(*action)[player_index], e); | |||
IZ_JoystickHandleHatEvents(&(*action)[player_index], e); | |||
IZ_JoystickHandleButtonEvents(&(*state)[player_index], &(*action)[player_index], e); | |||
} | |||
} | |||
void IZ_JoystickLoadConfig(const char* config_path, IZ_JoystickState(* state)[PLAYERS]) { | |||
void IZ_JoystickLoadConfig(IZ_JoystickState(* state)[PLAYERS], const char* config_path) { | |||
char control_mapping_section_name[26]; | |||
char main_section_name[11]; | |||
@@ -117,7 +117,7 @@ void IZ_JoystickLoadConfig(const char* config_path, IZ_JoystickState(* state)[PL | |||
} | |||
} | |||
IZ_ProcedureResult IZ_JoystickSaveConfig(const char* config_path, IZ_JoystickState(* state)[PLAYERS]) { | |||
IZ_ProcedureResult IZ_JoystickSaveConfig(IZ_JoystickState(* state)[PLAYERS], const char* config_path) { | |||
u8 problem = 0; | |||
char control_mapping_section_name[26]; | |||
@@ -134,7 +134,7 @@ IZ_ProcedureResult IZ_JoystickSaveConfig(const char* config_path, IZ_JoystickSta | |||
(*state)[player_index].config.control_mapping[control_index], | |||
config_path | |||
)) { | |||
return 1; | |||
problem |= (1 << player_index); | |||
} | |||
} | |||
@@ -158,15 +158,15 @@ IZ_ProcedureResult IZ_JoystickSaveConfig(const char* config_path, IZ_JoystickSta | |||
} | |||
} | |||
return problem; | |||
return -problem; | |||
} | |||
IZ_ProcedureResult IZ_JoystickInitialize(const char* config_path, IZ_JoystickState(* state)[PLAYERS]) { | |||
IZ_ProcedureResult IZ_JoystickInitialize(IZ_JoystickState(* state)[PLAYERS], const char* config_path, u8 argc, const char* argv[]) { | |||
SDL_memcpy(state, &IZ_DEFAULT_JOYSTICK_STATE, sizeof(IZ_JoystickState)); | |||
IZ_JoystickLoadConfig(config_path, state); | |||
if (IZ_JoystickSaveConfig(config_path, state)) { | |||
return 1; | |||
IZ_JoystickLoadConfig(state, config_path); | |||
if (IZ_JoystickSaveConfig(state, config_path) < 0) { | |||
return -1; | |||
} | |||
u8 joysticks_count = SDL_NumJoysticks(); | |||
@@ -82,11 +82,11 @@ static const IZ_JoystickState IZ_DEFAULT_JOYSTICK_STATE[PLAYERS] = { | |||
}, | |||
}; | |||
IZ_ProcedureResult IZ_JoystickSaveConfig(const char*, IZ_JoystickState(*)[PLAYERS]); | |||
IZ_ProcedureResult IZ_JoystickSaveConfig(IZ_JoystickState(*)[PLAYERS], const char*); | |||
void IZ_JoystickHandleEvents(SDL_Event, IZ_JoystickState(*)[PLAYERS], IZ_Action(*)[PLAYERS]); | |||
void IZ_JoystickHandleEvents(IZ_JoystickState(*)[PLAYERS], IZ_Action(*)[PLAYERS], SDL_Event); | |||
IZ_ProcedureResult IZ_JoystickInitialize(const char*, IZ_JoystickState(*)[PLAYERS]); | |||
IZ_ProcedureResult IZ_JoystickInitialize(IZ_JoystickState(*)[PLAYERS], const char*, u8, const char**); | |||
void IZ_JoystickTeardown(IZ_JoystickState(*)[PLAYERS]); | |||
@@ -1,6 +1,6 @@ | |||
#include "IZ_keyboard.h" | |||
void IZ_KeyboardHandleKeyUpDownEvents(SDL_Event e, IZ_KeyboardState* state, IZ_Action* action) { | |||
void IZ_KeyboardHandleKeyUpDownEvents(IZ_KeyboardState* state, IZ_Action* action, SDL_Event e) { | |||
u8 control_index; | |||
for (control_index = 0; control_index < CONTROLS; control_index += 1) { | |||
if (e.key.keysym.sym == state->config.control_mapping[control_index]) { | |||
@@ -17,13 +17,13 @@ void IZ_KeyboardHandleKeyUpDownEvents(SDL_Event e, IZ_KeyboardState* state, IZ_A | |||
} | |||
} | |||
void IZ_KeyboardHandleEvents(SDL_Event e, IZ_KeyboardState(* state)[PLAYERS], IZ_Action(* action)[PLAYERS]) { | |||
void IZ_KeyboardHandleEvents(IZ_KeyboardState(* state)[PLAYERS], IZ_Action(* action)[PLAYERS], SDL_Event e) { | |||
for (u8 player_index = 0; player_index < PLAYERS; player_index += 1) { | |||
IZ_KeyboardHandleKeyUpDownEvents(e, &(*state)[player_index], &(*action)[player_index]); | |||
IZ_KeyboardHandleKeyUpDownEvents(&(*state)[player_index], &(*action)[player_index], e); | |||
} | |||
} | |||
IZ_ProcedureResult IZ_KeyboardSaveConfig(const char* config_path, IZ_KeyboardState(* state)[PLAYERS]) { | |||
IZ_ProcedureResult IZ_KeyboardSaveConfig(IZ_KeyboardState(* state)[PLAYERS], const char* config_path) { | |||
u8 problem = 0; | |||
char control_mapping_section_name[26]; | |||
@@ -46,7 +46,7 @@ IZ_ProcedureResult IZ_KeyboardSaveConfig(const char* config_path, IZ_KeyboardSta | |||
return problem; | |||
} | |||
void IZ_KeyboardLoadConfig(const char* config_path, IZ_KeyboardState(* state)[PLAYERS]) { | |||
void IZ_KeyboardLoadConfig(IZ_KeyboardState(* state)[PLAYERS], const char* config_path) { | |||
char buffer[128]; | |||
char keyboard_section_name[26]; | |||
@@ -69,8 +69,8 @@ void IZ_KeyboardLoadConfig(const char* config_path, IZ_KeyboardState(* state)[PL | |||
} | |||
} | |||
IZ_ProcedureResult IZ_KeyboardInitialize(const char* config_path, IZ_KeyboardState(* state)[PLAYERS]) { | |||
IZ_ProcedureResult IZ_KeyboardInitialize(IZ_KeyboardState(* state)[PLAYERS], const char* config_path, u8 argc, const char* argv[]) { | |||
SDL_memcpy(state, &IZ_DEFAULT_KEYBOARD_STATE, sizeof(IZ_KeyboardState)); | |||
IZ_KeyboardLoadConfig(config_path, state); | |||
return IZ_KeyboardSaveConfig(config_path, state); | |||
IZ_KeyboardLoadConfig(state, config_path); | |||
return IZ_KeyboardSaveConfig(state, config_path); | |||
} |
@@ -62,10 +62,10 @@ static const IZ_KeyboardState IZ_DEFAULT_KEYBOARD_STATE[PLAYERS] = { | |||
}, | |||
}; | |||
IZ_ProcedureResult IZ_KeyboardSaveConfig(const char*, IZ_KeyboardState(*)[PLAYERS]); | |||
IZ_ProcedureResult IZ_KeyboardSaveConfig(IZ_KeyboardState(*)[PLAYERS], const char*); | |||
void IZ_KeyboardHandleEvents(SDL_Event, IZ_KeyboardState(*)[PLAYERS], IZ_Action(*)[PLAYERS]); | |||
void IZ_KeyboardHandleEvents(IZ_KeyboardState(*)[PLAYERS], IZ_Action(*)[PLAYERS], SDL_Event); | |||
IZ_ProcedureResult IZ_KeyboardInitialize(const char*, IZ_KeyboardState(*)[PLAYERS]); | |||
IZ_ProcedureResult IZ_KeyboardInitialize(IZ_KeyboardState(*)[PLAYERS], const char*, u8, const char**); | |||
#endif |
@@ -1,67 +1,6 @@ | |||
#include "IZ_midi.h" | |||
char* IZ_MIDIGetNoteName(u8 midi_note) { | |||
static const char* pitch_names[] = { | |||
"C", | |||
"C#", | |||
"D", | |||
"D#", | |||
"E", | |||
"F", | |||
"F#", | |||
"G", | |||
"G#", | |||
"A", | |||
"A#", | |||
"B" | |||
}; | |||
const u8 pitch_class = midi_note % 12; | |||
const u8 octave = midi_note / 12; | |||
static char note_name[8]; | |||
sprintf_s(note_name, 8, "%s%u", pitch_names[pitch_class], octave); | |||
return note_name; | |||
} | |||
u8 IZ_MIDIGetNoteFromName(char* name) { | |||
char name_copy[8]; | |||
memcpy_s(name_copy, 8, name, 8); | |||
_strlwr_s(name_copy, 8); | |||
u8 octave; | |||
const char base_pitch_name[] = "c d ef g a b"; | |||
if (strlen(name_copy) == 2) { | |||
octave = name_copy[1] - '0'; | |||
u8 pitch_index; | |||
for (pitch_index = 0; pitch_index < 12; pitch_index += 1) { | |||
if (base_pitch_name[pitch_index] == name_copy[0]) { | |||
return (octave * 12) + pitch_index; | |||
} | |||
} | |||
return 255u; | |||
} | |||
u8 pitch_class; | |||
octave = name_copy[2] - '0'; | |||
if (strstr(name_copy, "c#") || strstr(name_copy, "db")) { | |||
pitch_class = 1; | |||
} else if (strstr(name_copy, "d#") || strstr(name_copy, "eb")) { | |||
pitch_class = 3; | |||
} else if (strstr(name_copy, "f#") || strstr(name_copy, "gb")) { | |||
pitch_class = 6; | |||
} else if (strstr(name_copy, "g#") || strstr(name_copy, "ab")) { | |||
pitch_class = 8; | |||
} else if (strstr(name_copy, "a#") || strstr(name_copy, "bb")) { | |||
pitch_class = 10; | |||
} else { | |||
return 255u; | |||
} | |||
return (octave * 12) + pitch_class; | |||
} | |||
void IZ_MIDIInputHandleNoteOnOffEvents(PmEvent e, IZ_MIDIInputState* state, IZ_Action* action) { | |||
void IZ_MIDIInputHandleNoteOnOffEvents(IZ_MIDIInputState* state, IZ_Action* action, PmEvent e) { | |||
u32 message = e.message; | |||
u8 status = message & 0xF0u; | |||
u8 channel = message & 0x0Fu; | |||
@@ -90,14 +29,14 @@ void IZ_MIDIInputHandleNoteOnOffEvents(PmEvent e, IZ_MIDIInputState* state, IZ_A | |||
} | |||
} | |||
void IZ_MIDIInputHandleEvents(PmEvent e, IZ_MIDIInputState(* state)[PLAYERS], IZ_Action(* action)[PLAYERS]) { | |||
void IZ_MIDIInputHandleEvents(IZ_MIDIInputState(* state)[PLAYERS], IZ_Action(* action)[PLAYERS], PmEvent e) { | |||
u8 player_index; | |||
for (player_index = 0; player_index < PLAYERS; player_index += 1) { | |||
IZ_MIDIInputHandleNoteOnOffEvents(e, &(*state)[player_index], &(*action)[player_index]); | |||
IZ_MIDIInputHandleNoteOnOffEvents(&(*state)[player_index], &(*action)[player_index], e); | |||
} | |||
} | |||
IZ_ProcedureResult IZ_MIDIInputSaveConfig(const char* config_path, IZ_MIDIInputState(* state)[PLAYERS]) { | |||
IZ_ProcedureResult IZ_MIDIInputSaveConfig(IZ_MIDIInputState(* state)[PLAYERS], const char* config_path) { | |||
u8 problem = 0; | |||
char control_mapping_section_name[27]; | |||
@@ -141,7 +80,7 @@ IZ_ProcedureResult IZ_MIDIInputSaveConfig(const char* config_path, IZ_MIDIInputS | |||
return problem; | |||
} | |||
void IZ_MIDIInputLoadConfig(const char* config_path, IZ_MIDIInputState(* state)[PLAYERS]) { | |||
void IZ_MIDIInputLoadConfig(IZ_MIDIInputState(* state)[PLAYERS], const char* config_path) { | |||
char buffer[128]; | |||
char control_mapping_section_name[27]; | |||
char main_section_name[12]; | |||
@@ -169,14 +108,14 @@ void IZ_MIDIInputLoadConfig(const char* config_path, IZ_MIDIInputState(* state)[ | |||
} | |||
} | |||
IZ_ProcedureResult IZ_MIDIInputInitialize(const char* config_path, IZ_MIDIInputState(* state)[PLAYERS]) { | |||
IZ_ProcedureResult IZ_MIDIInputInitialize(IZ_MIDIInputState(* state)[PLAYERS], const char* config_path, u8 argc, const char* argv[]) { | |||
if (Pm_Initialize()) { | |||
return 1; | |||
} | |||
SDL_memcpy(state, &IZ_DEFAULT_MIDI_INPUT_STATE, sizeof(IZ_MIDIInputState)); | |||
IZ_MIDIInputLoadConfig(config_path, state); | |||
if (IZ_MIDIInputSaveConfig(config_path, state)) { | |||
IZ_MIDIInputLoadConfig(state, config_path); | |||
if (IZ_MIDIInputSaveConfig(state, config_path)) { | |||
return 2; | |||
} | |||
@@ -11,6 +11,7 @@ | |||
#include <minIni.h> | |||
#include "IZ_action.h" | |||
#include "../util/IZ_midi.h" | |||
#define MIDI_EVENT_BUFFER_SIZE 1024 | |||
@@ -91,11 +92,11 @@ static const IZ_MIDIInputState IZ_DEFAULT_MIDI_INPUT_STATE[PLAYERS] = { | |||
}, | |||
}; | |||
IZ_ProcedureResult IZ_MIDIInputSaveConfig(const char *config_path, IZ_MIDIInputState(*)[PLAYERS]); | |||
IZ_ProcedureResult IZ_MIDIInputSaveConfig(IZ_MIDIInputState(*)[PLAYERS], const char*); | |||
void IZ_MIDIInputHandleEvents(PmEvent e, IZ_MIDIInputState(*)[PLAYERS], IZ_Action(*)[PLAYERS]); | |||
void IZ_MIDIInputHandleEvents(IZ_MIDIInputState(*)[PLAYERS], IZ_Action(*)[PLAYERS], PmEvent); | |||
IZ_ProcedureResult IZ_MIDIInputInitialize(const char *config_path, IZ_MIDIInputState(*)[PLAYERS]); | |||
IZ_ProcedureResult IZ_MIDIInputInitialize(IZ_MIDIInputState(*)[PLAYERS], const char*, u8, const char**); | |||
void IZ_MIDIInputTeardown(IZ_MIDIInputState(*)[PLAYERS]); | |||
@@ -41,7 +41,7 @@ spec("input") { | |||
} | |||
it("sets initial state") { | |||
IZ_JoystickInitialize("config.ini", &state); | |||
IZ_JoystickInitialize(&state, "config.ini", 0, NULL); | |||
check(mock_is_called(SDL_memcpy), "Initial state not loaded."); | |||
check(mock_is_called(SDL_NumJoysticks), "Connected joysticks not checked."); | |||
@@ -50,7 +50,7 @@ spec("input") { | |||
it("calls load method") { | |||
mock_set_expected_calls(ini_getl, ((CONTROLS - 4) + 2) * PLAYERS); | |||
IZ_JoystickInitialize("config.ini", &state); | |||
IZ_JoystickInitialize(&state, "config.ini", 0, NULL); | |||
check( | |||
mock_get_expected_calls(ini_getl) == mock_get_actual_calls(ini_getl), | |||
@@ -63,7 +63,7 @@ spec("input") { | |||
it("calls save method") { | |||
mock_set_expected_calls(ini_putl, ((CONTROLS - 4) + 2) * PLAYERS); | |||
IZ_JoystickInitialize("config.ini", &state); | |||
IZ_JoystickInitialize(&state, "config.ini", 0, NULL); | |||
check( | |||
mock_get_expected_calls(ini_putl) == mock_get_actual_calls(ini_putl), | |||
@@ -76,7 +76,7 @@ spec("input") { | |||
it("opens device handles") { | |||
mock_set_expected_calls(SDL_JoystickOpen, MOCK_OPEN_JOYSTICKS); | |||
IZ_JoystickInitialize("config.ini", &state); | |||
IZ_JoystickInitialize(&state, "config.ini", 0, NULL); | |||
check( | |||
mock_get_expected_calls(SDL_JoystickOpen) == mock_get_actual_calls(SDL_JoystickOpen), | |||
@@ -111,7 +111,7 @@ spec("input") { | |||
action[p] = 0; | |||
printf("(axis value: %d) ", e.jaxis.value); | |||
IZ_JoystickHandleEvents(e, &state, &action); | |||
IZ_JoystickHandleEvents(&state, &action, e); | |||
check( | |||
action[p] == (0x1 << IZ_ACTION_INDEX_RIGHT), | |||
"Action not set." | |||
@@ -123,7 +123,7 @@ spec("input") { | |||
action[p] = 0; | |||
printf("(axis value: %d) ", e.jaxis.value); | |||
IZ_JoystickHandleEvents(e, &state, &action); | |||
IZ_JoystickHandleEvents(&state, &action, e); | |||
check( | |||
action[p] == (0x1 << IZ_ACTION_INDEX_LEFT), | |||
"Action not set." | |||
@@ -135,7 +135,7 @@ spec("input") { | |||
action[p] = 0; | |||
printf("(axis value: %d) ", e.jaxis.value); | |||
IZ_JoystickHandleEvents(e, &state, &action); | |||
IZ_JoystickHandleEvents(&state, &action, e); | |||
check( | |||
action[p] == 0, | |||
"Action not set." | |||
@@ -153,7 +153,7 @@ spec("input") { | |||
action[p] = 0; | |||
printf("(axis value: %d) ", e.jaxis.value); | |||
IZ_JoystickHandleEvents(e, &state, &action); | |||
IZ_JoystickHandleEvents(&state, &action, e); | |||
check( | |||
action[p] == (0x1 << IZ_ACTION_INDEX_RIGHT), | |||
"Action not set." | |||
@@ -165,7 +165,7 @@ spec("input") { | |||
action[p] = 0; | |||
printf("(axis value: %d) ", e.jaxis.value); | |||
IZ_JoystickHandleEvents(e, &state, &action); | |||
IZ_JoystickHandleEvents(&state, &action, e); | |||
check( | |||
action[p] == (0x1 << IZ_ACTION_INDEX_LEFT), | |||
"Action not set." | |||
@@ -177,7 +177,7 @@ spec("input") { | |||
action[p] = 0; | |||
printf("(axis value: %d) ", e.jaxis.value); | |||
IZ_JoystickHandleEvents(e, &state, &action); | |||
IZ_JoystickHandleEvents(&state, &action, e); | |||
check( | |||
action[p] == 0, | |||
"Action not set." | |||
@@ -195,7 +195,7 @@ spec("input") { | |||
action[p] = 0; | |||
printf("(axis value: %d) ", e.jaxis.value); | |||
IZ_JoystickHandleEvents(e, &state, &action); | |||
IZ_JoystickHandleEvents(&state, &action, e); | |||
check( | |||
action[p] == (0x1 << IZ_ACTION_INDEX_DOWN), | |||
"Action not set." | |||
@@ -207,7 +207,7 @@ spec("input") { | |||
action[p] = 0; | |||
printf("(axis value: %d) ", e.jaxis.value); | |||
IZ_JoystickHandleEvents(e, &state, &action); | |||
IZ_JoystickHandleEvents(&state, &action, e); | |||
check( | |||
action[p] == (0x1 << IZ_ACTION_INDEX_UP), | |||
"Action not set." | |||
@@ -219,7 +219,7 @@ spec("input") { | |||
action[p] = 0; | |||
printf("(axis value: %d) ", e.jaxis.value); | |||
IZ_JoystickHandleEvents(e, &state, &action); | |||
IZ_JoystickHandleEvents(&state, &action, e); | |||
check( | |||
action[p] == 0, | |||
"Action not set." | |||
@@ -237,7 +237,7 @@ spec("input") { | |||
action[p] = 0; | |||
printf("(axis value: %d) ", e.jaxis.value); | |||
IZ_JoystickHandleEvents(e, &state, &action); | |||
IZ_JoystickHandleEvents(&state, &action, e); | |||
check( | |||
action[p] == (0x1 << IZ_ACTION_INDEX_DOWN), | |||
"Action not set." | |||
@@ -249,7 +249,7 @@ spec("input") { | |||
action[p] = 0; | |||
printf("(axis value: %d) ", e.jaxis.value); | |||
IZ_JoystickHandleEvents(e, &state, &action); | |||
IZ_JoystickHandleEvents(&state, &action, e); | |||
check( | |||
action[p] == (0x1 << IZ_ACTION_INDEX_UP), | |||
"Action not set." | |||
@@ -261,7 +261,7 @@ spec("input") { | |||
action[p] = 0; | |||
printf("(axis value: %d) ", e.jaxis.value); | |||
IZ_JoystickHandleEvents(e, &state, &action); | |||
IZ_JoystickHandleEvents(&state, &action, e); | |||
check( | |||
action[p] == 0, | |||
"Action not set." | |||
@@ -280,7 +280,7 @@ spec("input") { | |||
e.jhat.value = (0x1u << i); | |||
action[p] = 0; | |||
IZ_JoystickHandleEvents(e, &state, &action); | |||
IZ_JoystickHandleEvents(&state, &action, e); | |||
check( | |||
action[p] == (0x1u << i), | |||
"Action not set." | |||
@@ -291,7 +291,7 @@ spec("input") { | |||
e.jhat.value = 0; | |||
action[p] = ~0; | |||
IZ_JoystickHandleEvents(e, &state, &action); | |||
IZ_JoystickHandleEvents(&state, &action, e); | |||
check( | |||
!(action[p] & (0x1 << i)), | |||
"Action not unset." | |||
@@ -308,7 +308,7 @@ spec("input") { | |||
state[p].config.control_mapping[i] = IZ_DEFAULT_JOYSTICK_STATE[p].config.control_mapping[i]; | |||
action[p] = 0; | |||
IZ_JoystickHandleEvents(e, &state, &action); | |||
IZ_JoystickHandleEvents(&state, &action, e); | |||
check( | |||
action[p] == (0x1u << i), | |||
"Action not set." | |||
@@ -321,7 +321,7 @@ spec("input") { | |||
state[p].config.control_mapping[i] = IZ_DEFAULT_JOYSTICK_STATE[p].config.control_mapping[i]; | |||
action[p] = ~0; | |||
IZ_JoystickHandleEvents(e, &state, &action); | |||
IZ_JoystickHandleEvents(&state, &action, e); | |||
check( | |||
!(action[p] & (0x1 << i)), | |||
"Action not unset." | |||
@@ -351,7 +351,7 @@ spec("input") { | |||
it("calls save method") { | |||
mock_set_expected_calls(ini_putl, ((CONTROLS - 4) + 2) * PLAYERS); | |||
IZ_JoystickSaveConfig("config.ini", &state); | |||
IZ_JoystickSaveConfig(&state, "config.ini"); | |||
check( | |||
mock_get_expected_calls(ini_putl) == mock_get_actual_calls(ini_putl), | |||
@@ -416,7 +416,7 @@ spec("input") { | |||
} | |||
it("sets initial state") { | |||
IZ_KeyboardInitialize("config.ini", &state); | |||
IZ_KeyboardInitialize(&state, "config.ini", 0, NULL); | |||
check(mock_is_called(SDL_memcpy), "Initial state not loaded."); | |||
} | |||
@@ -424,7 +424,7 @@ spec("input") { | |||
it("calls load method") { | |||
mock_set_expected_calls(ini_gets, CONTROLS * PLAYERS); | |||
IZ_KeyboardInitialize("config.ini", &state); | |||
IZ_KeyboardInitialize(&state, "config.ini", 0, NULL); | |||
check( | |||
mock_get_expected_calls(ini_gets) == mock_get_actual_calls(ini_gets), | |||
@@ -437,7 +437,7 @@ spec("input") { | |||
it("calls save method") { | |||
mock_set_expected_calls(ini_puts, CONTROLS * PLAYERS); | |||
IZ_KeyboardInitialize("config.ini", &state); | |||
IZ_KeyboardInitialize(&state, "config.ini", 0, NULL); | |||
check( | |||
mock_get_expected_calls(ini_puts) == mock_get_actual_calls(ini_puts), | |||
@@ -462,7 +462,7 @@ spec("input") { | |||
state[p].config.control_mapping[i] = IZ_DEFAULT_KEYBOARD_STATE[p].config.control_mapping[i]; | |||
action[p] = 0; | |||
IZ_KeyboardHandleEvents(e, &state, &action); | |||
IZ_KeyboardHandleEvents(&state, &action, e); | |||
check( | |||
action[p] == (0x1 << i), | |||
"Action not set." | |||
@@ -475,7 +475,7 @@ spec("input") { | |||
state[p].config.control_mapping[i] = IZ_DEFAULT_KEYBOARD_STATE[p].config.control_mapping[i]; | |||
action[p] = ~0; | |||
IZ_KeyboardHandleEvents(e, &state, &action); | |||
IZ_KeyboardHandleEvents(&state, &action, e); | |||
check( | |||
!(action[p] & (0x1 << i)), | |||
"Action not unset." | |||
@@ -549,7 +549,7 @@ spec("input") { | |||
} | |||
it("sets initial state") { | |||
IZ_MIDIInputInitialize("config.ini", &state); | |||
IZ_MIDIInputInitialize(&state, "config.ini", 0, NULL); | |||
check(mock_is_called(SDL_memcpy), "Initial state not loaded."); | |||
check(mock_is_called(Pm_CountDevices), "Connected MIDI devices not checked."); | |||
@@ -559,7 +559,7 @@ spec("input") { | |||
mock_set_expected_calls(ini_gets, CONTROLS * PLAYERS); | |||
mock_set_expected_calls(ini_getl, 2 * PLAYERS); | |||
IZ_MIDIInputInitialize("config.ini", &state); | |||
IZ_MIDIInputInitialize(&state, "config.ini", 0, NULL); | |||
check( | |||
mock_get_expected_calls(ini_gets) == mock_get_actual_calls(ini_gets), | |||
@@ -580,7 +580,7 @@ spec("input") { | |||
mock_set_expected_calls(ini_puts, CONTROLS * PLAYERS); | |||
mock_set_expected_calls(ini_putl, 2 * PLAYERS); | |||
IZ_MIDIInputInitialize("config.ini", &state); | |||
IZ_MIDIInputInitialize(&state, "config.ini", 0, NULL); | |||
check( | |||
mock_get_expected_calls(ini_puts) == mock_get_actual_calls(ini_puts), | |||
@@ -600,7 +600,7 @@ spec("input") { | |||
it("opens device handles") { | |||
mock_set_expected_calls(Pm_OpenInput, MOCK_OPEN_JOYSTICKS); | |||
IZ_MIDIInputInitialize("config.ini", &state); | |||
IZ_MIDIInputInitialize(&state, "config.ini", 0, NULL); | |||
check( | |||
mock_get_expected_calls(Pm_OpenInput) == mock_get_actual_calls(Pm_OpenInput), | |||
@@ -657,7 +657,7 @@ spec("input") { | |||
state[p].config.control_mapping[i] = IZ_DEFAULT_MIDI_INPUT_STATE[p].config.control_mapping[i]; | |||
action[p] = 0; | |||
IZ_MIDIInputHandleEvents(e, &state, &action); | |||
IZ_MIDIInputHandleEvents(&state, &action, e); | |||
check( | |||
action[p] == (0x1 << i), | |||
"Action not set." | |||
@@ -669,7 +669,7 @@ spec("input") { | |||
state[p].config.control_mapping[i] = IZ_DEFAULT_MIDI_INPUT_STATE[p].config.control_mapping[i]; | |||
action[p] = ~0; | |||
IZ_MIDIInputHandleEvents(e, &state, &action); | |||
IZ_MIDIInputHandleEvents(&state, &action, e); | |||
check( | |||
!(action[p] & (0x1 << i)), | |||
"Action not unset." | |||
@@ -1,6 +0,0 @@ | |||
#ifndef IZ_NETWORK_H | |||
#define IZ_NETWORK_H | |||
#define NETWORK_PROTOCOL "izanagi-networking" | |||
#endif |
@@ -0,0 +1,28 @@ | |||
#include "IZ_websocket.h" | |||
void IZ_WebsocketInitialize(IZ_Websocket* ws) { | |||
ws->context = NULL; | |||
ws->interrupted = false; | |||
} | |||
IZ_ProcedureResult IZ_WebsocketHandle(IZ_Websocket* ws) { | |||
// FIXME: https://libwebsockets.org/git/libwebsockets/tree/minimal-examples-lowlevel/http-server/minimal-http-server-eventlib-foreign | |||
return lws_service(ws->context, 0); | |||
} | |||
void IZ_WebsocketCancelService(IZ_Websocket* ws) { | |||
ws->interrupted = true; | |||
lws_cancel_service(ws->context); | |||
} | |||
void IZ_WebsocketTeardown(IZ_Websocket* ws) { | |||
lws_context_destroy(ws->context); | |||
ws->context = NULL; | |||
} | |||
void IZ_WebsocketDestroyMessage(void* msg_raw) { | |||
IZ_WebsocketMessage* msg = msg_raw; | |||
free(msg->payload); | |||
msg->payload = NULL; | |||
msg->len = 0; | |||
} |
@@ -0,0 +1,34 @@ | |||
#ifndef IZ_WEBSOCKET_H | |||
#define IZ_WEBSOCKET_H | |||
#include <libwebsockets.h> | |||
#include "../IZ_common.h" | |||
#define NETWORK_PROTOCOL "izanagi-networking" | |||
#define RING_COUNT 32 | |||
/* one of these created for each message */ | |||
typedef struct { | |||
u8 binary: 1; | |||
void* payload; /* is malloc'd */ | |||
size_t len; | |||
u8 first: 1; | |||
u8 final: 1; | |||
} IZ_WebsocketMessage; | |||
typedef struct { | |||
struct lws_context* context; | |||
u8 interrupted: 1; | |||
} IZ_Websocket; | |||
void IZ_WebsocketInitialize(IZ_Websocket*); | |||
IZ_ProcedureResult IZ_WebsocketHandle(IZ_Websocket*); | |||
void IZ_WebsocketTeardown(IZ_Websocket*); | |||
void IZ_WebsocketDestroyMessage(void*); | |||
void IZ_WebsocketCancelService(IZ_Websocket*); | |||
#endif |
@@ -1,90 +1,303 @@ | |||
#include "IZ_wsclient.h" | |||
IZ_ProcedureResult IZ_WSClientCreateConnection(IZ_WSClient* client, IZ_WSClientConnectParams params) { | |||
static struct lws_client_connect_info info; | |||
memset(&info, 0, sizeof info); | |||
void IZ_WSClientAttemptConnect(struct lws_sorted_usec_list *sul) { | |||
IZ_WSClientVHostData* vhd = lws_container_of(sul, IZ_WSClientVHostData, sul); | |||
info.context = client->context; | |||
info.port = params.port; | |||
info.address = params.address; | |||
info.host = params.address; | |||
info.origin = params.address; | |||
info.protocol = params.protocol; | |||
info.path = params.path; | |||
info.userdata = params.userdata; | |||
// info.ssl_connection = ( | |||
// LCCSCF_ALLOW_SELFSIGNED | |||
// | LCCSCF_ALLOW_INSECURE | |||
// | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK | |||
// | LCCSCF_ALLOW_EXPIRED | |||
// ); | |||
client->connection = lws_client_connect_via_info(&info); | |||
if (!client->connection) { | |||
return 1; | |||
printf("%s %s %u", vhd->address, vhd->path, *vhd->port); | |||
vhd->i.context = vhd->context; | |||
vhd->i.port = *vhd->port; | |||
vhd->i.address = vhd->address; | |||
vhd->i.path = vhd->path; | |||
vhd->i.host = vhd->i.address; | |||
vhd->i.origin = vhd->i.address; | |||
vhd->i.ssl_connection = 0; | |||
vhd->i.protocol = NETWORK_PROTOCOL; | |||
vhd->i.pwsi = &vhd->client_wsi; | |||
if (lws_client_connect_via_info(&vhd->i)) { | |||
return; | |||
} | |||
lws_sul_schedule( | |||
vhd->context, | |||
0, | |||
&vhd->sul, | |||
IZ_WSClientAttemptConnect, | |||
10 * LWS_US_PER_SEC | |||
); | |||
} | |||
IZ_ProcedureResult IZ_WSClientProtocolInitialize(struct lws* wsi, void* in) { | |||
IZ_WSClientVHostData* vhd_instance = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get( | |||
lws_get_vhost(wsi), | |||
lws_get_protocol(wsi) | |||
); | |||
IZ_WSClientVHostData** vhd = &vhd_instance; | |||
*vhd = lws_protocol_vh_priv_zalloc( | |||
lws_get_vhost(wsi), | |||
lws_get_protocol(wsi), | |||
sizeof(IZ_WSClientVHostData) | |||
); | |||
(*vhd)->context = lws_get_context(wsi); | |||
(*vhd)->protocol = lws_get_protocol(wsi); | |||
(*vhd)->vhost = lws_get_vhost(wsi); | |||
(*vhd)->port = (u16*) lws_pvo_search( | |||
(const struct lws_protocol_vhost_options *)in, | |||
"port")->value; | |||
(*vhd)->address = lws_pvo_search( | |||
(const struct lws_protocol_vhost_options *)in, | |||
"address")->value; | |||
(*vhd)->path = lws_pvo_search( | |||
(const struct lws_protocol_vhost_options *)in, | |||
"path")->value; | |||
(*vhd)->ring = lws_ring_create( | |||
sizeof(IZ_WebsocketMessage), | |||
RING_COUNT, | |||
IZ_WebsocketDestroyMessage | |||
); | |||
if (!(*vhd)->ring) { | |||
return 1; | |||
} | |||
IZ_WSClientAttemptConnect(&(*vhd)->sul); | |||
return 0; | |||
} | |||
IZ_ProcedureResult IZ_WSClientCreateContext(IZ_WSClient* client, lws_callback_function* callback, void* userdata) { | |||
static struct lws_protocols protocols[] = { | |||
{ | |||
.name = "http", | |||
.callback = NULL, | |||
.per_session_data_size = 0, | |||
.rx_buffer_size = 0, | |||
.id = 0, | |||
.user = NULL, | |||
.tx_packet_size = 0, | |||
}, | |||
LWS_PROTOCOL_LIST_TERM, | |||
}; | |||
void IZ_WSClientProtocolTeardown(struct lws* wsi) { | |||
IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get( | |||
lws_get_vhost(wsi), | |||
lws_get_protocol(wsi) | |||
); | |||
protocols[0].callback = callback; | |||
protocols[0].user = userdata; | |||
static struct lws_context_creation_info info; | |||
memset(&info, 0, sizeof info); | |||
info.port = CONTEXT_PORT_NO_LISTEN, | |||
info.protocols = protocols, | |||
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT, | |||
vhd->finished = true; | |||
if (vhd->ring) { | |||
lws_ring_destroy(vhd->ring); | |||
} | |||
client->context = lws_create_context(&info); | |||
if (!client->context) { | |||
return 1; | |||
lws_sul_cancel(&vhd->sul); | |||
} | |||
void IZ_WSClientConnectionError(struct lws* wsi, void* in) { | |||
IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get( | |||
lws_get_vhost(wsi), | |||
lws_get_protocol(wsi) | |||
); | |||
lwsl_err("CLIENT_CONNECTION_ERROR: %s\n", in ? (char *)in : "(null)"); | |||
vhd->client_wsi = NULL; | |||
lws_sul_schedule( | |||
vhd->context, | |||
0, | |||
&vhd->sul, | |||
IZ_WSClientAttemptConnect, | |||
LWS_US_PER_SEC | |||
); | |||
} | |||
void IZ_WSClientOnOpen(struct lws* wsi) { | |||
IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get( | |||
lws_get_vhost(wsi), | |||
lws_get_protocol(wsi) | |||
); | |||
vhd->established = true; | |||
} | |||
IZ_ProcedureResult IZ_WSClientWritable(struct lws* wsi) { | |||
IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get( | |||
lws_get_vhost(wsi), | |||
lws_get_protocol(wsi) | |||
); | |||
const IZ_WebsocketMessage* pmsg = lws_ring_get_element(vhd->ring, &vhd->tail); | |||
if (!pmsg) { | |||
return 0; | |||
} | |||
/* notice we allowed for LWS_PRE in the payload already */ | |||
i32 m = lws_write( | |||
wsi, | |||
((unsigned char*) pmsg->payload) + LWS_PRE, | |||
pmsg->len, | |||
pmsg->binary ? LWS_WRITE_BINARY : LWS_WRITE_TEXT | |||
); | |||
if (m < (i32)pmsg->len) { | |||
lwsl_err("ERROR %d writing to ws socket\n", m); | |||
return -1; | |||
} | |||
lws_ring_consume_single_tail(vhd->ring, &vhd->tail, 1); | |||
/* more to do for us? */ | |||
if (lws_ring_get_element(vhd->ring, &vhd->tail)) { | |||
/* come back as soon as we can write more */ | |||
lws_callback_on_writable(wsi); | |||
} | |||
return 0; | |||
} | |||
void IZ_WSClientInitialize(IZ_WSClient* client) { | |||
// TODO delegate logs to SDL | |||
//lws_set_log_level(0, NULL); | |||
client->context = NULL; | |||
client->connection = NULL; | |||
void IZ_WSClientOnClose(struct lws* wsi) { | |||
IZ_WSClientVHostData* vhd = (IZ_WSClientVHostData*) lws_protocol_vh_priv_get( | |||
lws_get_vhost(wsi), | |||
lws_get_protocol(wsi) | |||
); | |||
vhd->client_wsi = NULL; | |||
vhd->established = false; | |||
lws_sul_schedule( | |||
vhd->context, | |||
0, | |||
&vhd->sul, | |||
IZ_WSClientAttemptConnect, | |||
LWS_US_PER_SEC | |||
); | |||
} | |||
IZ_ProcedureResult IZ_WSClientConnect(IZ_WSClient* client, IZ_WSClientConnectParams params) { | |||
if (IZ_WSClientCreateContext(client, params.callback, params.userdata)) { | |||
return 1; | |||
void IZ_WSClientOnReceive(struct lws* wsi, IZ_WSClientSessionData* pss, void* in, size_t len) { | |||
lwsl_user("LWS_CALLBACK_CLIENT_RECEIVE: %4d (rpp %5d, first %d, last %d, bin %d)\n", | |||
(int)len, (int)lws_remaining_packet_payload(wsi), | |||
lws_is_first_fragment(wsi), | |||
lws_is_final_fragment(wsi), | |||
lws_frame_is_binary(wsi)); | |||
// lwsl_hexdump_notice(in, len); | |||
IZ_WebsocketMessage amsg; | |||
amsg.first = (char)lws_is_first_fragment(wsi); | |||
amsg.final = (char)lws_is_final_fragment(wsi); | |||
amsg.binary = (char)lws_frame_is_binary(wsi); | |||
i32 n = (int)lws_ring_get_count_free_elements(pss->ring); | |||
if (!n) { | |||
lwsl_user("dropping!\n"); | |||
return; | |||
} | |||
if (IZ_WSClientCreateConnection(client, params)) { | |||
return 2; | |||
amsg.len = len; | |||
/* notice we over-allocate by LWS_PRE */ | |||
amsg.payload = malloc(LWS_PRE + len); | |||
if (!amsg.payload) { | |||
lwsl_user("OOM: dropping\n"); | |||
return; | |||
} | |||
return 0; | |||
memcpy((char *)amsg.payload + LWS_PRE, in, len); | |||
if (!lws_ring_insert(pss->ring, &amsg, 1)) { | |||
IZ_WebsocketDestroyMessage(&amsg); | |||
lwsl_user("dropping!\n"); | |||
return; | |||
} | |||
lws_callback_on_writable(wsi); | |||
if (!pss->flow_controlled && n < 3) { | |||
pss->flow_controlled = 1; | |||
lws_rx_flow_control(wsi, 0); | |||
} | |||
} | |||
IZ_ProcedureResult IZ_WSClientHandle(IZ_WSClient* client) { | |||
i32 response = lws_service(client->context, 0); | |||
if (response < 0) { | |||
return 1; | |||
IZ_ProcedureResult IZ_WSClientCallback( | |||
struct lws* wsi, | |||
enum lws_callback_reasons reason, | |||
void* user, | |||
void* in, | |||
size_t len | |||
) { | |||
switch (reason) { | |||
case LWS_CALLBACK_PROTOCOL_INIT: | |||
return IZ_WSClientProtocolInitialize(wsi, in); | |||
case LWS_CALLBACK_PROTOCOL_DESTROY: | |||
IZ_WSClientProtocolTeardown(wsi); | |||
break; | |||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: | |||
IZ_WSClientConnectionError(wsi, in); | |||
break; | |||
case LWS_CALLBACK_CLIENT_ESTABLISHED: | |||
IZ_WSClientOnOpen(wsi); | |||
break; | |||
case LWS_CALLBACK_CLIENT_CLOSED: | |||
IZ_WSClientOnClose(wsi); | |||
break; | |||
case LWS_CALLBACK_CLIENT_RECEIVE: | |||
IZ_WSClientOnReceive(wsi, user, in, len); | |||
break; | |||
case LWS_CALLBACK_CLIENT_WRITEABLE: | |||
return IZ_WSClientWritable(wsi); | |||
default: | |||
break; | |||
} | |||
return lws_callback_http_dummy(wsi, reason, user, in, len); | |||
} | |||
IZ_ProcedureResult IZ_WSClientInitialize(IZ_WSClientState* state, IZ_WSClientInitializeParams params) { | |||
struct lws_context_creation_info info; | |||
memset(&info, 0, sizeof info); | |||
info.port = CONTEXT_PORT_NO_LISTEN; | |||
static const struct lws_protocols protocols[] = { | |||
{ | |||
.name = NETWORK_PROTOCOL, | |||
.callback = IZ_WSClientCallback, | |||
.per_session_data_size = sizeof(IZ_WSClientSessionData), | |||
.rx_buffer_size = 1024, | |||
.id = 0, | |||
.user = NULL, | |||
.tx_packet_size = 0, | |||
}, | |||
LWS_PROTOCOL_LIST_TERM | |||
}; | |||
info.protocols = protocols; | |||
static struct lws_protocol_vhost_options pvo_address = { | |||
NULL, | |||
NULL, | |||
"address", /* pvo name */ | |||
"localhost" /* pvo value */ | |||
}; | |||
pvo_address.value = params.address; | |||
static struct lws_protocol_vhost_options pvo_path = { | |||
&pvo_address, | |||
NULL, | |||
"path", /* pvo name */ | |||
"/" /* pvo value */ | |||
}; | |||
pvo_path.value = params.path; | |||
static struct lws_protocol_vhost_options pvo_port = { | |||
&pvo_path, | |||
NULL, | |||
"port", /* pvo name */ | |||
NULL /* pvo value */ | |||
}; | |||
pvo_port.value = (void*) ¶ms.port; | |||
static const struct lws_protocol_vhost_options pvo = { | |||
NULL, /* "next" pvo linked-list */ | |||
&pvo_port, /* "child" pvo linked-list */ | |||
NETWORK_PROTOCOL, /* protocol name we belong to on this vhost */ | |||
"" /* ignored */ | |||
}; | |||
info.pvo = &pvo; | |||
info.fd_limit_per_thread = 1 + 1 + 1; | |||
IZ_WebsocketInitialize(&state->ws); | |||
state->ws.context = lws_create_context(&info); | |||
if (!state->ws.context) { | |||
return -1; | |||
} | |||
return 0; | |||
} | |||
void IZ_WSClientDisconnect(IZ_WSClient* client) { | |||
lws_context_destroy(client->context); | |||
IZ_ProcedureResult IZ_WSClientHandle(IZ_WSClientState* state) { | |||
return IZ_WebsocketHandle(&state->ws); | |||
} | |||
void IZ_WSClientTeardown(IZ_WSClientState* state) { | |||
IZ_WebsocketTeardown(&state->ws); | |||
} | |||
void IZ_WSClientCancelService(IZ_WSClientState* state) { | |||
IZ_WebsocketCancelService(&state->ws); | |||
} |
@@ -3,28 +3,52 @@ | |||
#include <libwebsockets.h> | |||
#include "../IZ_common.h" | |||
#include "IZ_network.h" | |||
#include "IZ_websocket.h" | |||
typedef struct { | |||
struct lws_context* context; | |||
struct lws* connection; | |||
} IZ_WSClient; | |||
struct lws_context *context; | |||
struct lws_vhost *vhost; | |||
const struct lws_protocols *protocol; | |||
lws_sorted_usec_list_t sul; | |||
struct lws_ring *ring; /* ringbuffer holding unsent messages */ | |||
u32 tail; | |||
struct lws_client_connect_info i; | |||
struct lws *client_wsi; | |||
u8 finished: 1; | |||
u8 established: 1; | |||
const char* address; | |||
const char* path; | |||
u16* port; | |||
} IZ_WSClientVHostData; | |||
typedef struct { | |||
struct lws_ring *ring; | |||
u32 tail; | |||
char flow_controlled; | |||
u8 completed: 1; | |||
u8 write_consume_pending: 1; | |||
} IZ_WSClientSessionData; | |||
typedef struct { | |||
u16 port; | |||
const char* address; | |||
const char* path; | |||
const char* protocol; | |||
void* userdata; | |||
lws_callback_function* callback; | |||
} IZ_WSClientConnectParams; | |||
u16 port; | |||
} IZ_WSClientInitializeParams; | |||
typedef struct { | |||
IZ_Websocket ws; | |||
} IZ_WSClientState; | |||
void IZ_WSClientInitialize(IZ_WSClient*); | |||
IZ_ProcedureResult IZ_WSClientInitialize(IZ_WSClientState*, IZ_WSClientInitializeParams); | |||
IZ_ProcedureResult IZ_WSClientConnect(IZ_WSClient*, IZ_WSClientConnectParams); | |||
IZ_ProcedureResult IZ_WSClientHandle(IZ_WSClientState*); | |||
IZ_ProcedureResult IZ_WSClientHandle(IZ_WSClient*); | |||
void IZ_WSClientTeardown(IZ_WSClientState*); | |||
void IZ_WSClientDisconnect(IZ_WSClient*); | |||
void IZ_WSClientCancelService(IZ_WSClientState*); | |||
#endif |
@@ -1,30 +1,30 @@ | |||
#include "IZ_video.h" | |||
IZ_ProcedureResult IZ_VideoSaveConfig(IZ_VideoConfig* config, const char* config_path) { | |||
if (!ini_putl("Video", "Width", config->width, config_path)) { | |||
return 1; | |||
IZ_ProcedureResult IZ_VideoSaveConfig(IZ_VideoState* state, const char* config_path) { | |||
if (!ini_putl("Video", "Width", state->config.width, config_path)) { | |||
return -1; | |||
} | |||
if (!ini_putl("Video", "Height", config->height, config_path)) { | |||
return 1; | |||
if (!ini_putl("Video", "Height", state->config.height, config_path)) { | |||
return -1; | |||
} | |||
if (!ini_putl("Video", "MaxFps", config->max_fps, config_path)) { | |||
return 1; | |||
if (!ini_putl("Video", "MaxFps", state->config.max_fps, config_path)) { | |||
return -1; | |||
} | |||
return 0; | |||
} | |||
void IZ_VideoLoadConfig(IZ_VideoConfig* config, const char* config_path) { | |||
config->width = ini_getl("Video", "Width", IZ_DEFAULT_VIDEO_STATE.config.width, config_path); | |||
config->height = ini_getl("Video", "Height", IZ_DEFAULT_VIDEO_STATE.config.height, config_path); | |||
config->max_fps = ini_getl("Video", "MaxFps", IZ_DEFAULT_VIDEO_STATE.config.max_fps, config_path); | |||
void IZ_VideoLoadConfig(IZ_VideoState* state, const char* config_path) { | |||
state->config.width = ini_getl("Video", "Width", IZ_DEFAULT_VIDEO_STATE.config.width, config_path); | |||
state->config.height = ini_getl("Video", "Height", IZ_DEFAULT_VIDEO_STATE.config.height, config_path); | |||
state->config.max_fps = ini_getl("Video", "MaxFps", IZ_DEFAULT_VIDEO_STATE.config.max_fps, config_path); | |||
} | |||
IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState* state, const char* config_path) { | |||
IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState* state, const char* config_path, u8 argc, const char* argv[]) { | |||
SDL_memcpy(state, &IZ_DEFAULT_VIDEO_STATE, sizeof(IZ_VideoState)); | |||
IZ_VideoLoadConfig(&state->config, config_path); | |||
if (IZ_VideoSaveConfig(&state->config, config_path)) { | |||
IZ_VideoLoadConfig(state, config_path); | |||
if (IZ_VideoSaveConfig(state, config_path)) { | |||
// fprintf_s(stderr, "Error committing video config.\n"); | |||
} | |||
state->last_update_at = 0u; | |||
@@ -40,9 +40,9 @@ static const IZ_VideoState IZ_DEFAULT_VIDEO_STATE = { | |||
.active_sprites = {}, | |||
}; | |||
IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState*, const char*); | |||
IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState*, const char*, u8, const char**); | |||
IZ_ProcedureResult IZ_VideoSaveConfig(IZ_VideoConfig*, const char*); | |||
IZ_ProcedureResult IZ_VideoSaveConfig(IZ_VideoState*, const char*); | |||
void IZ_VideoUpdate(IZ_VideoState*, u64, IZ_InputState*); | |||
@@ -21,7 +21,7 @@ spec("output") { | |||
it("calls save method") { | |||
mock_set_expected_calls(ini_putl, 3); | |||
IZ_VideoSaveConfig("config.ini", &config); | |||
IZ_VideoSaveConfig(&config, "config.ini"); | |||
check( | |||
mock_get_expected_calls(ini_putl) == mock_get_actual_calls(ini_putl), | |||
@@ -0,0 +1,62 @@ | |||
#include "IZ_midi.h" | |||
char* IZ_MIDIGetNoteName(u8 midi_note) { | |||
static const char* pitch_names[] = { | |||
"C", | |||
"C#", | |||
"D", | |||
"D#", | |||
"E", | |||
"F", | |||
"F#", | |||
"G", | |||
"G#", | |||
"A", | |||
"A#", | |||
"B" | |||
}; | |||
const u8 pitch_class = midi_note % 12; | |||
const u8 octave = midi_note / 12; | |||
static char note_name[8]; | |||
sprintf_s(note_name, 8, "%s%u", pitch_names[pitch_class], octave); | |||
return note_name; | |||
} | |||
u8 IZ_MIDIGetNoteFromName(char* name) { | |||
char name_copy[8]; | |||
memcpy_s(name_copy, 8, name, 8); | |||
_strlwr_s(name_copy, 8); | |||
u8 octave; | |||
const char base_pitch_name[] = "c d ef g a b"; | |||
if (strlen(name_copy) == 2) { | |||
octave = name_copy[1] - '0'; | |||
u8 pitch_index; | |||
for (pitch_index = 0; pitch_index < 12; pitch_index += 1) { | |||
if (base_pitch_name[pitch_index] == name_copy[0]) { | |||
return (octave * 12) + pitch_index; | |||
} | |||
} | |||
return 255u; | |||
} | |||
u8 pitch_class; | |||
octave = name_copy[2] - '0'; | |||
if (strstr(name_copy, "c#") || strstr(name_copy, "db")) { | |||
pitch_class = 1; | |||
} else if (strstr(name_copy, "d#") || strstr(name_copy, "eb")) { | |||
pitch_class = 3; | |||
} else if (strstr(name_copy, "f#") || strstr(name_copy, "gb")) { | |||
pitch_class = 6; | |||
} else if (strstr(name_copy, "g#") || strstr(name_copy, "ab")) { | |||
pitch_class = 8; | |||
} else if (strstr(name_copy, "a#") || strstr(name_copy, "bb")) { | |||
pitch_class = 10; | |||
} else { | |||
return 255u; | |||
} | |||
return (octave * 12) + pitch_class; | |||
} |
@@ -0,0 +1,11 @@ | |||
#ifndef IZ_UTIL_MIDI_H | |||
#define IZ_UTIL_MIDI_H | |||
#include <stdio.h> | |||
#include <string.h> | |||
#include "../IZ_common.h" | |||
char* IZ_MIDIGetNoteName(u8); | |||
u8 IZ_MIDIGetNoteFromName(char*); | |||
#endif |
@@ -1,7 +1,7 @@ | |||
#include "IZ_app.h" | |||
void IZ_AppHandleSignal(i32 _signal) { | |||
interrupted = true; | |||
IZ_WSServerCancelService(&global_app.server); | |||
} | |||
// TODO move to each subsystem | |||
@@ -20,19 +20,17 @@ void IZ_AppLoadConfig(IZ_App *app, u8 argc, const char **argv) { | |||
} | |||
IZ_ProcedureResult IZ_AppInitialize(IZ_App *app, u8 argc, const char **argv) { | |||
interrupted = false; | |||
signal(SIGINT, IZ_AppHandleSignal); | |||
//signal(SIGTERM, IZ_AppHandleSignal); | |||
IZ_AppLoadConfig(app, argc, argv); | |||
IZ_LogInterceptWSMessages(app->config.log_level); | |||
if (IZ_WSServerCreateContext(&app->context, (IZ_WSServerCreateContextParams) { | |||
if (IZ_WSServerInitialize(&app->server, (IZ_WSServerInitializeParams) { | |||
.protocol = NULL, | |||
.port = app->config.port, | |||
.default_filename = NULL, | |||
.origin = NULL, | |||
})) { | |||
return 1; | |||
return -1; | |||
} | |||
return 0; | |||
@@ -40,14 +38,26 @@ IZ_ProcedureResult IZ_AppInitialize(IZ_App *app, u8 argc, const char **argv) { | |||
IZ_ProcedureResult IZ_AppRun(IZ_App *app, u8 argc, const char **argv) { | |||
if (IZ_AppInitialize(app, argc, argv)) { | |||
return 1; | |||
return -1; | |||
} | |||
i32 n = 0; | |||
while (n >= 0 && !interrupted) { | |||
n = lws_service(app->context, 0); | |||
i32 result = 0; | |||
while (!app->server.ws.interrupted) { | |||
printf("A\n"); | |||
if (IZ_WSServerHandle(&app->server)) { | |||
printf("B\n"); | |||
result = -1; | |||
break; | |||
} | |||
if (app->server.ws.interrupted) { | |||
printf("C\n"); | |||
break; | |||
} | |||
printf("D\n"); | |||
} | |||
lws_context_destroy(app->context); | |||
return 0; | |||
IZ_WSServerTeardown(&app->server); | |||
printf("%u\n", result); | |||
return result; | |||
} |
@@ -7,8 +7,6 @@ | |||
#include "log/IZ_log.h" | |||
#include "IZ_common.h" | |||
static bool interrupted; | |||
typedef struct { | |||
i32 log_level; | |||
u16 port; | |||
@@ -16,7 +14,7 @@ typedef struct { | |||
typedef struct { | |||
IZ_AppConfig config; | |||
struct lws_context* context; | |||
IZ_WSServerState server; | |||
} IZ_App; | |||
static const IZ_App IZ_APP_DEFAULT_STATE = { | |||
@@ -24,9 +22,10 @@ static const IZ_App IZ_APP_DEFAULT_STATE = { | |||
.log_level = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE, | |||
.port = 42069, | |||
}, | |||
.context = NULL, | |||
}; | |||
static IZ_App global_app; | |||
IZ_ProcedureResult IZ_AppRun(IZ_App*, u8, const char**); | |||
#endif |
@@ -1,6 +1,5 @@ | |||
#include "IZ_app.h" | |||
IZ_ProcedureResult main(i32 argc, const char *argv[]) { | |||
IZ_App app; | |||
return IZ_AppRun(&app, argc, argv); | |||
return IZ_AppRun(&global_app, argc, argv); | |||
} |
@@ -1 +0,0 @@ | |||
E:/Projects/Games/izanagi/src/packages/game/network/IZ_network.h |
@@ -0,0 +1 @@ | |||
E:/Projects/Games/izanagi/src/packages/game/network/IZ_websocket.c |
@@ -0,0 +1 @@ | |||
E:/Projects/Games/izanagi/src/packages/game/network/IZ_websocket.h |
@@ -1,6 +1,6 @@ | |||
#include "IZ_wsserver.h" | |||
static void IZ_ProtocolCullLaggingClients(IZ_WSServerVHostData *vhd) { | |||
void IZ_ProtocolCullLaggingClients(IZ_WSServerVHostData *vhd) { | |||
u32 oldest_tail = lws_ring_get_oldest_tail(vhd->ring); | |||
IZ_WSServerSessionData *old_pss = NULL; | |||
i32 most = 0; | |||
@@ -93,15 +93,7 @@ static void IZ_ProtocolCullLaggingClients(IZ_WSServerVHostData *vhd) { | |||
/* destroys the message when everyone has had a copy of it */ | |||
void IZ_ProtocolDestroyMessage(void* msg_raw) { | |||
IZ_WSServerMessage *msg = msg_raw; | |||
free(msg->payload); | |||
msg->payload = NULL; | |||
msg->len = 0; | |||
} | |||
i32 IZ_WSServerInitialize(struct lws* wsi) { | |||
IZ_ProcedureResult IZ_WSServerProtocolInitialize(struct lws* wsi) { | |||
IZ_WSServerVHostData* vhd_instance = (IZ_WSServerVHostData*) lws_protocol_vh_priv_get( | |||
lws_get_vhost(wsi), | |||
lws_get_protocol(wsi) | |||
@@ -116,9 +108,9 @@ i32 IZ_WSServerInitialize(struct lws* wsi) { | |||
(*vhd)->protocol = lws_get_protocol(wsi); | |||
(*vhd)->vhost = lws_get_vhost(wsi); | |||
(*vhd)->ring = lws_ring_create( | |||
sizeof(IZ_WSServerMessage), | |||
sizeof(IZ_WebsocketMessage), | |||
RING_COUNT, | |||
IZ_ProtocolDestroyMessage | |||
IZ_WebsocketDestroyMessage | |||
); | |||
if (!(*vhd)->ring) { | |||
return 1; | |||
@@ -126,7 +118,7 @@ i32 IZ_WSServerInitialize(struct lws* wsi) { | |||
return 0; | |||
} | |||
void IZ_WSServerTeardown(struct lws* wsi) { | |||
void IZ_WSServerProtocolTeardown(struct lws* wsi) { | |||
IZ_WSServerVHostData* vhd = (IZ_WSServerVHostData*) lws_protocol_vh_priv_get( | |||
lws_get_vhost(wsi), | |||
lws_get_protocol(wsi) | |||
@@ -158,7 +150,7 @@ void IZ_WSServerOnClose(struct lws* wsi, IZ_WSServerSessionData* pss) { | |||
lws_ll_fwd_remove(IZ_WSServerSessionData, pss_list, pss, vhd->pss_list); | |||
} | |||
IZ_ProcedureResult IZ_WSServerOnSend(struct lws* wsi, IZ_WSServerSessionData* pss) { | |||
IZ_ProcedureResult IZ_WSServerWritable(struct lws* wsi, IZ_WSServerSessionData* pss) { | |||
IZ_WSServerVHostData* vhd = (IZ_WSServerVHostData*) lws_protocol_vh_priv_get( | |||
lws_get_vhost(wsi), | |||
lws_get_protocol(wsi) | |||
@@ -167,7 +159,7 @@ IZ_ProcedureResult IZ_WSServerOnSend(struct lws* wsi, IZ_WSServerSessionData* ps | |||
if (pss->culled) { | |||
return 0; | |||
} | |||
const IZ_WSServerMessage *pmsg = lws_ring_get_element(vhd->ring, &pss->tail); | |||
const IZ_WebsocketMessage* pmsg = lws_ring_get_element(vhd->ring, &pss->tail); | |||
if (!pmsg) { | |||
return 0; | |||
} | |||
@@ -175,7 +167,7 @@ IZ_ProcedureResult IZ_WSServerOnSend(struct lws* wsi, IZ_WSServerSessionData* ps | |||
/* notice we allowed for LWS_PRE in the payload already */ | |||
i32 m = lws_write( | |||
wsi, | |||
((unsigned char *) pmsg->payload) + LWS_PRE, | |||
((unsigned char*) pmsg->payload) + LWS_PRE, | |||
pmsg->len, | |||
pmsg->binary ? LWS_WRITE_BINARY : LWS_WRITE_TEXT | |||
); | |||
@@ -209,7 +201,7 @@ void IZ_WSServerOnReceive(struct lws* wsi, void* in, size_t len) { | |||
lws_get_vhost(wsi), | |||
lws_get_protocol(wsi) | |||
); | |||
IZ_WSServerMessage amsg; | |||
IZ_WebsocketMessage amsg; | |||
i32 n = (i32) lws_ring_get_count_free_elements(vhd->ring); | |||
if (!n) { | |||
/* forcibly make space */ | |||
@@ -235,7 +227,7 @@ void IZ_WSServerOnReceive(struct lws* wsi, void* in, size_t len) { | |||
/* ...and we copy the payload in at +LWS_PRE */ | |||
memcpy((char *) amsg.payload + LWS_PRE, in, len); | |||
if (!lws_ring_insert(vhd->ring, &amsg, 1)) { | |||
IZ_ProtocolDestroyMessage(&amsg); | |||
IZ_WebsocketDestroyMessage(&amsg); | |||
lwsl_user("dropping!\n"); | |||
return; | |||
} | |||
@@ -251,7 +243,7 @@ void IZ_WSServerOnReceive(struct lws* wsi, void* in, size_t len) { | |||
lws_end_foreach_llp(ppss, pss_list); | |||
} | |||
i32 IZ_WSServerCallback( | |||
IZ_ProcedureResult IZ_WSServerCallback( | |||
struct lws* wsi, | |||
enum lws_callback_reasons reason, | |||
void* user, | |||
@@ -260,9 +252,9 @@ i32 IZ_WSServerCallback( | |||
) { | |||
switch (reason) { | |||
case LWS_CALLBACK_PROTOCOL_INIT: | |||
return IZ_WSServerInitialize(wsi); | |||
return IZ_WSServerProtocolInitialize(wsi); | |||
case LWS_CALLBACK_PROTOCOL_DESTROY: | |||
IZ_WSServerTeardown(wsi); | |||
IZ_WSServerProtocolTeardown(wsi); | |||
break; | |||
case LWS_CALLBACK_ESTABLISHED: | |||
IZ_WSServerOnOpen(wsi, user); | |||
@@ -271,7 +263,7 @@ i32 IZ_WSServerCallback( | |||
IZ_WSServerOnClose(wsi, user); | |||
break; | |||
case LWS_CALLBACK_SERVER_WRITEABLE: | |||
return IZ_WSServerOnSend(wsi, user); | |||
return IZ_WSServerWritable(wsi, user); | |||
case LWS_CALLBACK_RECEIVE: | |||
IZ_WSServerOnReceive(wsi, in, len); | |||
break; | |||
@@ -282,7 +274,7 @@ i32 IZ_WSServerCallback( | |||
return 0; | |||
} | |||
IZ_ProcedureResult IZ_WSServerCreateContext(struct lws_context** context, IZ_WSServerCreateContextParams params) { | |||
IZ_ProcedureResult IZ_WSServerInitialize(IZ_WSServerState* state, IZ_WSServerInitializeParams params) { | |||
struct lws_context_creation_info info; | |||
memset(&info, 0, sizeof info); | |||
info.port = params.port; | |||
@@ -347,10 +339,23 @@ IZ_ProcedureResult IZ_WSServerCreateContext(struct lws_context** context, IZ_WSS | |||
| LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE | |||
); | |||
*context = lws_create_context(&info); | |||
if (!*context) { | |||
return 1; | |||
IZ_WebsocketInitialize(&state->ws); | |||
state->ws.context = lws_create_context(&info); | |||
if (!state->ws.context) { | |||
return -1; | |||
} | |||
return 0; | |||
} | |||
IZ_ProcedureResult IZ_WSServerHandle(IZ_WSServerState* state) { | |||
return IZ_WebsocketHandle(&state->ws); | |||
} | |||
void IZ_WSServerTeardown(IZ_WSServerState* state) { | |||
IZ_WebsocketTeardown(&state->ws); | |||
} | |||
void IZ_WSServerCancelService(IZ_WSServerState* state) { | |||
IZ_WebsocketCancelService(&state->ws); | |||
} |
@@ -4,16 +4,7 @@ | |||
#include "libwebsockets.h" | |||
#include <string.h> | |||
#include "../IZ_common.h" | |||
#include "IZ_network.h" | |||
#define RING_COUNT 32 | |||
/* one of these created for each message */ | |||
typedef struct { | |||
void* payload; /* is malloc'd */ | |||
size_t len; | |||
u8 binary: 1; | |||
} IZ_WSServerMessage; | |||
#include "IZ_websocket.h" | |||
/* one of these is created for each client connecting to us */ | |||
typedef struct IZ_WSServerSessionData { | |||
@@ -32,7 +23,7 @@ typedef struct { | |||
struct lws_ring *ring; /* ringbuffer holding unsent messages */ | |||
} IZ_WSServerVHostData; | |||
i32 IZ_WSServerCallback( | |||
IZ_ProcedureResult IZ_WSServerCallback( | |||
struct lws*, | |||
enum lws_callback_reasons, | |||
void*, | |||
@@ -45,8 +36,24 @@ typedef struct { | |||
const char* origin; | |||
const char* default_filename; | |||
const char* protocol; | |||
} IZ_WSServerCreateContextParams; | |||
} IZ_WSServerInitializeParams; | |||
typedef struct { | |||
i32 log_level; | |||
u16 port; | |||
} IZ_WSServerConfig; | |||
typedef struct { | |||
IZ_WSServerConfig config; | |||
IZ_Websocket ws; | |||
} IZ_WSServerState; | |||
IZ_ProcedureResult IZ_WSServerInitialize(IZ_WSServerState*, IZ_WSServerInitializeParams); | |||
IZ_ProcedureResult IZ_WSServerHandle(IZ_WSServerState*); | |||
void IZ_WSServerTeardown(IZ_WSServerState*); | |||
IZ_ProcedureResult IZ_WSServerCreateContext(struct lws_context**, IZ_WSServerCreateContextParams); | |||
void IZ_WSServerCancelService(IZ_WSServerState*); | |||
#endif |