static void server_message (client_t *self) { if (self->reply) fmq_msg_destroy (&self->reply); self->reply = fmq_msg_recv (self->dealer); if (!self->reply) return; // Interrupted; do nothing if (fmq_msg_id (self->reply) == FMQ_MSG_SRSLY) client_execute (self, srsly_event); else if (fmq_msg_id (self->reply) == FMQ_MSG_RTFM) client_execute (self, rtfm_event); else if (fmq_msg_id (self->reply) == FMQ_MSG_ORLY) client_execute (self, orly_event); else if (fmq_msg_id (self->reply) == FMQ_MSG_OHAI_OK) client_execute (self, ohai_ok_event); else if (fmq_msg_id (self->reply) == FMQ_MSG_CHEEZBURGER) client_execute (self, cheezburger_event); else if (fmq_msg_id (self->reply) == FMQ_MSG_HUGZ) client_execute (self, hugz_event); else if (fmq_msg_id (self->reply) == FMQ_MSG_ICANHAZ_OK) client_execute (self, icanhaz_ok_event); // Any input from server counts as activity self->expires_at = zclock_time () + self->heartbeat * 2; }
// Client hash function that checks if client is alive static int client_ping (const char *key, void *client, void *socket) { client_t *self = (client_t *) client; if (zclock_time () >= self->heartbeat_at) { client_execute (self, heartbeat_event); self->heartbeat_at = zclock_time () + self->heartbeat; } return 0; }
static void agent_client_message (agent_t *self) { zmsg_t *msg = zmsg_recv (self->router); if (!msg) return; // Interrupted; do nothing puts ("Received message from client"); zmsg_dump (msg); // Frame 0 is address client that sent message zframe_t *address = zmsg_pop (msg); char *hashkey = zframe_strhex (address); client_t *client = zhash_lookup (self->clients, hashkey); if (client == NULL) { client = client_new (self->router, hashkey, address); zhash_insert (self->clients, hashkey, client); zhash_freefn (self->clients, hashkey, client_free); } else { free (hashkey); zframe_destroy (&address); } // Frame 1 is the command char *command = zmsg_popstr (msg); client_set_request (client, msg); if (command) { if (streq (command, "OHAI")) client_execute (client, ohai_event); else if (streq (command, "ICANHAZ")) client_execute (client, icanhaz_event); else if (streq (command, "HUGZ")) client_execute (client, hugz_event); free (command); } }
static void client_restart (client_t *self, char *endpoint) { // Reconnect to new endpoint if specified if (endpoint) { if (self->dealer) zsocket_destroy (self->ctx, self->dealer); self->dealer = zsocket_new (self->ctx, ZMQ_DEALER); zmq_connect (self->dealer, endpoint); } // Clear out any previous request data fmq_msg_destroy (&self->request); self->request = fmq_msg_new (0); // Restart dialog state machine from zero self->state = start_state; self->expires_at = 0; // Application hook to reinitialize dialog // Provides us with an event to kick things off initialize_the_client (self); client_execute (self, self->next_event); }
mvcp_error_code client_transport( client demo ) { mvcp_error_code error = mvcp_ok; int refresh = 1; int terminated = 0; mvcp_status_t status; mvcp_notifier notifier = mvcp_get_notifier( demo->dv ); while ( !terminated ) { if ( refresh ) { printf( " +----+ +------+ +----+ +------+ +---+ +-----+ +------+ +-----+ +---+ \n" ); printf( " |1=-5| |2=-2.5| |3=-1| |4=-0.5| |5=1| |6=0.5| |7=1.25| |8=2.5| |9=5| \n" ); printf( " +----+ +------+ +----+ +------+ +---+ +-----+ +------+ +-----+ +---+ \n" ); printf( "\n" ); printf( "+----------------------------------------------------------------------+\n" ); printf( "| 0 = quit, x = eXecute, 'space' = pause |\n" ); printf( "| g = goto a frame, q = queue maintenance |\n" ); printf( "| h = step -1, j = end of clip, k = start of clip, l = step 1 |\n" ); printf( "| eof handling: p = pause, r = repeat, t = terminate |\n" ); printf( "| i = set in point, o = set out point, c = clear in/out |\n" ); printf( "| u = use point settings, d = don't use point settings |\n" ); printf( "+----------------------------------------------------------------------+\n" ); printf( "\n" ); term_init( ); refresh = 0; } client_change_status( demo, 1 ); switch( term_read( ) ) { case '0': terminated = 1; break; case -1: break; case ' ': error = mvcp_unit_pause( demo->dv, demo->selected_unit ); break; case '1': error = mvcp_unit_play_at_speed( demo->dv, demo->selected_unit, -5000 ); break; case '2': error = mvcp_unit_play_at_speed( demo->dv, demo->selected_unit, -2500 ); break; case '3': error = mvcp_unit_play_at_speed( demo->dv, demo->selected_unit, -1000 ); break; case '4': error = mvcp_unit_play_at_speed( demo->dv, demo->selected_unit, -500 ); break; case '5': error = mvcp_unit_play( demo->dv, demo->selected_unit ); break; case '6': error = mvcp_unit_play_at_speed( demo->dv, demo->selected_unit, 500 ); break; case '7': error = mvcp_unit_play_at_speed( demo->dv, demo->selected_unit, 1250 ); break; case '8': error = mvcp_unit_play_at_speed( demo->dv, demo->selected_unit, 2500 ); break; case '9': error = mvcp_unit_play_at_speed( demo->dv, demo->selected_unit, 5000 ); break; case 's': error = mvcp_unit_goto( demo->dv, demo->selected_unit, 0 ); break; case 'h': error = mvcp_unit_step( demo->dv, demo->selected_unit, -1 ); break; case 'j': mvcp_notifier_get( notifier, &status, demo->selected_unit ); error = mvcp_unit_goto( demo->dv, demo->selected_unit, status.tail_out ); break; case 'k': mvcp_notifier_get( notifier, &status, demo->selected_unit ); error = mvcp_unit_goto( demo->dv, demo->selected_unit, status.in ); break; case 'l': error = mvcp_unit_step( demo->dv, demo->selected_unit, 1 ); break; case 'p': error = mvcp_unit_set( demo->dv, demo->selected_unit, "eof", "pause" ); break; case 'r': error = mvcp_unit_set( demo->dv, demo->selected_unit, "eof", "loop" ); break; case 't': error = mvcp_unit_set( demo->dv, demo->selected_unit, "eof", "stop" ); break; case 'i': error = client_set_in( demo ); break; case 'o': error = client_set_out( demo ); break; case 'g': client_change_status( demo, 0 ); term_exit( ); error = client_goto( demo ); refresh = 1; break; case 'c': error = client_clear_in_out( demo ); break; case 'u': error = mvcp_unit_set( demo->dv, demo->selected_unit, "points", "use" ); break; case 'd': error = mvcp_unit_set( demo->dv, demo->selected_unit, "points", "ignore" ); break; case 'x': client_change_status( demo, 0 ); term_exit( ); client_execute( demo ); refresh = 1; break; case 'q': client_change_status( demo, 0 ); term_exit( ); client_queue_maintenance( demo, &demo->queues[ demo->selected_unit ] ); refresh = 1; break; } client_change_status( demo, 0 ); } term_exit( ); return error; }
mvcp_error_code client_load( client demo ) { mvcp_error_code error = mvcp_ok; int terminated = 0; int refresh = 1; int start = 0; strcpy( demo->current_directory, demo->last_directory ); term_init( ); while ( !terminated ) { mvcp_dir dir = mvcp_dir_init( demo->dv, demo->current_directory ); if ( mvcp_dir_count( dir ) == -1 ) { printf( "Invalid directory - retrying %s\n", demo->last_directory ); mvcp_dir_close( dir ); dir = mvcp_dir_init( demo->dv, demo->last_directory ); if ( mvcp_dir_count( dir ) == -1 ) { printf( "Invalid directory - going back to /\n" ); mvcp_dir_close( dir ); dir = mvcp_dir_init( demo->dv, "/" ); strcpy( demo->current_directory, "/" ); } else { strcpy( demo->current_directory, demo->last_directory ); } } terminated = mvcp_dir_count( dir ) == -1; if ( !terminated ) { int index = 0; int selected = 0; int max = 9; int end = 0; end = mvcp_dir_count( dir ); strcpy( demo->last_directory, demo->current_directory ); while ( !selected && !terminated ) { mvcp_dir_entry_t entry; int pressed; if ( refresh ) { const char *action = "Load & Play"; if ( demo->queues[ demo->selected_unit ].mode ) action = "Queue"; printf( "%s from %s\n\n", action, demo->current_directory ); if ( strcmp( demo->current_directory, "/" ) ) printf( "-: Parent directory\n" ); for ( index = start; index < end && ( index - start ) < max; index ++ ) { mvcp_dir_get( dir, index, &entry ); printf( "%d: %s\n", index - start + 1, entry.name ); } while ( ( index ++ % 9 ) != 0 ) printf( "\n" ); printf( "\n" ); if ( start + max < end ) printf( "space = more files" ); else if ( end > max ) printf( "space = return to start of list" ); if ( start > 0 ) printf( ", b = previous files" ); printf( "\n" ); printf( "0 = abort, t = transport, x = execute command, q = queue maintenance\n\n" ); refresh = 0; } client_change_status( demo, 1 ); pressed = term_read( ); switch( pressed ) { case -1: break; case '0': terminated = 1; break; case 'b': refresh = start - max >= 0; if ( refresh ) start = start - max; break; case ' ': refresh = start + max < end; if ( refresh ) { start = start + max; } else if ( end > max ) { start = 0; refresh = 1; } break; case '-': if ( strcmp( demo->current_directory, "/" ) ) { selected = 1; ( *strrchr( demo->current_directory, '/' ) ) = '\0'; ( *( strrchr( demo->current_directory, '/' ) + 1 ) ) = '\0'; } break; case 't': client_change_status( demo, 0 ); term_exit( ); client_transport( demo ); term_init( ); selected = 1; break; case 'x': client_change_status( demo, 0 ); term_exit( ); client_execute( demo ); term_init( ); selected = 1; break; case 'q': client_change_status( demo, 0 ); term_exit( ); client_queue_maintenance( demo, &demo->queues[ demo->selected_unit ] ); term_init( ); selected = 1; break; default: if ( pressed >= '1' && pressed <= '9' ) { if ( ( start + pressed - '1' ) < end ) { mvcp_dir_get( dir, start + pressed - '1', &entry ); selected = 1; strcat( demo->current_directory, entry.name ); } } break; } client_change_status( demo, 0 ); } mvcp_dir_close( dir ); } if ( !terminated && demo->current_directory[ strlen( demo->current_directory ) - 1 ] != '/' ) { if ( demo->queues[ demo->selected_unit ].mode == 0 ) { error = mvcp_unit_load( demo->dv, demo->selected_unit, demo->current_directory ); mvcp_unit_play( demo->dv, demo->selected_unit ); } else { client_queue_add( demo, &demo->queues[ demo->selected_unit ], demo->current_directory ); printf( "File %s added to queue.\n", demo->current_directory ); } strcpy( demo->current_directory, demo->last_directory ); refresh = 0; } else { refresh = 1; start = 0; } } term_exit( ); return error; }
static void control_message (client_t *self) { zmsg_t *msg = zmsg_recv (self->pipe); char *method = zmsg_popstr (msg); if (streq (method, "SUBSCRIBE")) { char *path = zmsg_popstr (msg); // Store subscription along with any previous ones // Check we don't already have a subscription for this path sub_t *sub = (sub_t *) zlist_first (self->subs); while (sub) { if (streq (path, sub->path)) return; sub = (sub_t *) zlist_next (self->subs); } // Subscription path must start with '/' // We'll do better error handling later assert (*path == '/'); // New subscription, so store it for later replay sub = sub_new (self, path); zlist_append (self->subs, sub); // If we're connected, then also send to server if (self->connected) { fmq_msg_path_set (self->request, path); self->next_event = subscribe_event; } free (path); } else if (streq (method, "CONNECT")) { char *endpoint = zmsg_popstr (msg); client_restart (self, endpoint); free (endpoint); } else if (streq (method, "CONFIG")) { char *config_file = zmsg_popstr (msg); fmq_config_destroy (&self->config); self->config = fmq_config_load (config_file); if (self->config) client_apply_config (self); else { printf ("E: cannot load config file '%s'\n", config_file); self->config = fmq_config_new ("root", NULL); } free (config_file); } else if (streq (method, "SETOPTION")) { char *path = zmsg_popstr (msg); char *value = zmsg_popstr (msg); fmq_config_path_set (self->config, path, value); free (path); free (value); } else if (streq (method, "STOP")) { zstr_send (self->pipe, "OK"); self->stopped = true; } free (method); zmsg_destroy (&msg); if (self->next_event) client_execute (self, self->next_event); }