int main (void) { // Prepare our context and sockets zctx_t *ctx = zctx_new (); void *publisher = zsocket_new (ctx, ZMQ_PUB); zsocket_bind (publisher, "tcp://*:5557"); int64_t sequence = 0; srandom ((unsigned) time (NULL)); // Start state manager and wait for synchronization signal void *updates = zthread_fork (ctx, state_manager, NULL); free (zstr_recv (updates)); while (!zctx_interrupted) { // Distribute as key-value message kvmsg_t *kvmsg = kvmsg_new (++sequence); kvmsg_fmt_key (kvmsg, "%d", randof (10000)); kvmsg_fmt_body (kvmsg, "%d", randof (1000000)); kvmsg_send (kvmsg, publisher); kvmsg_send (kvmsg, updates); kvmsg_destroy (&kvmsg); } printf (" Interrupted\n%d messages out\n", (int) sequence); zctx_destroy (&ctx); return 0; }
static int s_snapshots (zloop_t *loop, zmq_pollitem_t *poller, void *args) { clonesrv_t *self = (clonesrv_t *) args; zframe_t *identity = zframe_recv (poller->socket); if (identity) { // Request is in second frame of message char *request = zstr_recv (poller->socket); char *subtree = NULL; if (streq (request, "ICANHAZ?")) { free (request); subtree = zstr_recv (poller->socket); } else printf ("E: bad request, aborting\n"); if (subtree) { // Send state socket to client kvroute_t routing = { poller->socket, identity, subtree }; zhash_foreach (self->kvmap, s_send_single, &routing); // Now send END message with sequence number zclock_log ("I: sending shapshot=%d", (int) self->sequence); zframe_send (&identity, poller->socket, ZFRAME_MORE); kvmsg_t *kvmsg = kvmsg_new (self->sequence); kvmsg_set_key (kvmsg, "KTHXBAI"); kvmsg_set_body (kvmsg, (byte *) subtree, 0); kvmsg_send (kvmsg, poller->socket); kvmsg_destroy (&kvmsg); free (subtree); } } return 0; }
int main (void) { // Prepare our context and publisher socket zctx_t *ctx = zctx_new (); void *publisher = zsocket_new (ctx, ZMQ_PUB); zsocket_set_hwm (publisher, 0); zsocket_bind (publisher, "tcp://*:5556"); zclock_sleep (200); zhash_t *kvmap = zhash_new (); int64_t sequence = 0; srandom ((unsigned) time (NULL)); while (!zctx_interrupted) { // Distribute as key-value message kvmsg_t *kvmsg = kvmsg_new (++sequence); kvmsg_fmt_key (kvmsg, "%d", randof (10000)); kvmsg_fmt_body (kvmsg, "%d", randof (1000000)); kvmsg_send (kvmsg, publisher); kvmsg_store (&kvmsg, kvmap); } printf (" Interrupted\n%d messages out\n", (int) sequence); zhash_destroy (&kvmap); zctx_destroy (&ctx); return 0; }
static void state_manager (void *args, zctx_t *ctx, void *pipe) { zhash_t *kvmap = zhash_new (); zstr_send (pipe, "READY"); void *snapshot = zsocket_new (ctx, ZMQ_ROUTER); zsocket_bind (snapshot, "tcp://*:5556"); zmq_pollitem_t items [] = { { pipe, 0, ZMQ_POLLIN, 0 }, { snapshot, 0, ZMQ_POLLIN, 0 } }; int64_t sequence = 0; // Current snapshot version number while (!zctx_interrupted) { int rc = zmq_poll (items, 2, -1); if (rc == -1 && errno == ETERM) break; // Context has been shut down // Apply state update from main thread if (items [0].revents & ZMQ_POLLIN) { kvmsg_t *kvmsg = kvmsg_recv (pipe); if (!kvmsg) break; // Interrupted sequence = kvmsg_sequence (kvmsg); kvmsg_store (&kvmsg, kvmap); } // Execute state snapshot request if (items [1].revents & ZMQ_POLLIN) { zframe_t *identity = zframe_recv (snapshot); if (!identity) break; // Interrupted // Request is in second frame of message char *request = zstr_recv (snapshot); if (streq (request, "ICANHAZ?")) free (request); else { printf ("E: bad request, aborting\n"); break; } // Send state snapshot to client kvroute_t routing = { snapshot, identity }; // For each entry in kvmap, send kvmsg to client zhash_foreach (kvmap, s_send_single, &routing); // Now send END message with sequence number printf ("Sending state shapshot=%d\n", (int) sequence); zframe_send (&identity, snapshot, ZFRAME_MORE); kvmsg_t *kvmsg = kvmsg_new (sequence); kvmsg_set_key (kvmsg, "KTHXBAI"); kvmsg_set_body (kvmsg, (byte *) "", 0); kvmsg_send (kvmsg, snapshot); kvmsg_destroy (&kvmsg); } } zhash_destroy (&kvmap); }
static void collabclient_sendRedo_sfdfragment( cloneclient_t* cc, SplineFont* sf, SplineChar *sc, /* optional */ char* sfdfrag, /* SFD that makes sense for redo */ char* msgtype, /* will be MSG_TYPE_UNDO if set to zero */ int isLocalUndo ) { printf("collabclient_sendRedo_sfdfragment(top)\n"); if( !cc ) return; if( !msgtype ) msgtype = MSG_TYPE_UNDO; char pos[100]; char* uuid = sf->xuid; printf("uuid:%s\n", uuid ); int idx = 0; char* sfd = sfdfrag; printf("read undo sfd, data:%p\n", sfd ); if( DEBUG_SHOW_SFD_CHUNKS ) printf("SENDING: %s\n\n", sfd ); printf("timers1...\n" ); cc->roundTripTimerWaitingSeq = cc->publisher_sendseq; BackgroundTimer_touch( cc->roundTripTimer ); printf("timers2...\n" ); printf("sfd:%p...\n", sfd ); kvmsg_t *kvmsg = kvmsg_new(0); kvmsg_fmt_key (kvmsg, "%s%d", SUBTREE, cc->publisher_sendseq++); kvmsg_set_body (kvmsg, sfd, strlen(sfd) ); kvmsg_set_prop (kvmsg, "type", msgtype ); kvmsg_set_prop (kvmsg, "uuid", uuid ); if( sc ) { sprintf(pos, "%d", sc->orig_pos ); printf("pos:%s\n", pos ); printf("sc.name:%s\n", sc->name ); } size_t data_size = kvmsg_size (kvmsg); printf("data.size:%ld\n", data_size ); kvmsg_set_prop (kvmsg, "pos", pos ); if( sc ) kvmsg_set_prop (kvmsg, "name", sc->name ); sprintf(pos, "%d", isLocalUndo ); kvmsg_set_prop (kvmsg, "isLocalUndo", pos ); kvmsg_send (kvmsg, cc->publisher); kvmsg_destroy (&kvmsg); DEBUG("Sent a undo chunk of %zu bytes to the server\n",strlen(sfd)); free(sfd); }
static void collabclient_sendRedo_Internal( FontViewBase *fv, SplineChar *sc, Undoes *undo, int isLocalUndo ) { printf("collabclient_sendRedo_Internal()\n"); cloneclient_t* cc = fv->collabClient; if( !cc ) return; char* uuid = fv->sf->xuid; printf("uuid:%s\n", uuid ); printf("________________________ WRITE undo.layer: %d layer_sz:%d\n", undo->layer, sc->layer_cnt ); int idx = 0; char filename[PATH_MAX]; snprintf(filename, PATH_MAX, "%s/fontforge-collab-x.sfd", getTempDir() ); FILE* f = fopen( filename, "wb" ); SFDDumpUndo( f, sc, undo, "Undo", idx ); fclose(f); printf("wrote undo sfd... filename: %s\n", filename ); char* sfd = GFileReadAll( filename ); printf("read undo sfd, data:%p\n", sfd ); if( DEBUG_SHOW_SFD_CHUNKS ) printf("SENDING: %s\n\n", sfd ); printf("timers1...\n" ); cc->roundTripTimerWaitingSeq = cc->publisher_sendseq; BackgroundTimer_touch( cc->roundTripTimer ); printf("timers2...\n" ); printf("sfd:%p...\n", sfd ); kvmsg_t *kvmsg = kvmsg_new(0); kvmsg_fmt_key (kvmsg, "%s%d", SUBTREE, cc->publisher_sendseq++); kvmsg_set_body (kvmsg, sfd, strlen(sfd) ); kvmsg_set_prop (kvmsg, "type", MSG_TYPE_UNDO ); kvmsg_set_prop (kvmsg, "uuid", uuid ); char pos[100]; sprintf(pos, "%d", sc->orig_pos ); printf("pos:%s\n", pos ); printf("sc.name:%s\n", sc->name ); size_t data_size = kvmsg_size (kvmsg); printf("data.size:%ld\n", data_size ); kvmsg_set_prop (kvmsg, "pos", pos ); kvmsg_set_prop (kvmsg, "name", sc->name ); sprintf(pos, "%d", isLocalUndo ); kvmsg_set_prop (kvmsg, "isLocalUndo", pos ); kvmsg_send (kvmsg, cc->publisher); kvmsg_destroy (&kvmsg); DEBUG("Sent a undo chunk of %d bytes to the server\n",strlen(sfd)); free(sfd); }
static int s_send_hugz (zloop_t *loop, int timer_id, void *args) { clonesrv_t *self = (clonesrv_t *) args; kvmsg_t *kvmsg = kvmsg_new (self->sequence); kvmsg_set_key (kvmsg, "HUGZ"); kvmsg_set_body (kvmsg, (byte *) "", 0); kvmsg_send (kvmsg, self->publisher); kvmsg_destroy (&kvmsg); return 0; }
static void collabclient_sendSFD( void* ccvp, char* sfd, char* fontname ) { cloneclient_t* cc = (cloneclient_t*)ccvp; kvmsg_t *kvmsg = kvmsg_new(0); kvmsg_fmt_key (kvmsg, "%s%d", SUBTREE, cc->publisher_sendseq++); kvmsg_set_body (kvmsg, sfd, strlen(sfd)); kvmsg_set_prop (kvmsg, "type", MSG_TYPE_SFD ); kvmsg_set_prop (kvmsg, "fontname", fontname ); // kvmsg_set_prop (kvmsg, "ttl", "%d", randof (30)); kvmsg_send (kvmsg, cc->publisher); kvmsg_destroy (&kvmsg); DEBUG("Sent a SFD of %d bytes to the server\n",strlen(sfd)); free(sfd); }
int main (void) { // Prepare our context and subscriber zctx_t *ctx = zctx_new (); void *snapshot = zsocket_new (ctx, ZMQ_DEALER); zsocket_connect (snapshot, "tcp://localhost:5556"); void *subscriber = zsocket_new (ctx, ZMQ_SUB); zsockopt_set_subscribe (subscriber, ""); zsocket_connect (subscriber, "tcp://localhost:5557"); void *publisher = zsocket_new (ctx, ZMQ_PUSH); zsocket_connect (publisher, "tcp://localhost:5558"); zhash_t *kvmap = zhash_new (); srandom ((unsigned) time (NULL)); // Get state snapshot int64_t sequence = 0; zstr_send (snapshot, "ICANHAZ?"); while (TRUE) { kvmsg_t *kvmsg = kvmsg_recv (snapshot); if (!kvmsg) break; // Interrupted if (streq (kvmsg_key (kvmsg), "KTHXBAI")) { sequence = kvmsg_sequence (kvmsg); printf ("I: received snapshot=%d\n", (int) sequence); kvmsg_destroy (&kvmsg); break; // Done } kvmsg_store (&kvmsg, kvmap); } int64_t alarm = zclock_time () + 1000; while (!zctx_interrupted) { zmq_pollitem_t items [] = { { subscriber, 0, ZMQ_POLLIN, 0 } }; int tickless = (int) ((alarm - zclock_time ())); if (tickless < 0) tickless = 0; int rc = zmq_poll (items, 1, tickless * ZMQ_POLL_MSEC); if (rc == -1) break; // Context has been shut down if (items [0].revents & ZMQ_POLLIN) { kvmsg_t *kvmsg = kvmsg_recv (subscriber); if (!kvmsg) break; // Interrupted // Discard out-of-sequence kvmsgs, incl. heartbeats if (kvmsg_sequence (kvmsg) > sequence) { sequence = kvmsg_sequence (kvmsg); kvmsg_store (&kvmsg, kvmap); printf ("I: received update=%d\n", (int) sequence); } else kvmsg_destroy (&kvmsg); } // If we timed-out, generate a random kvmsg if (zclock_time () >= alarm) { kvmsg_t *kvmsg = kvmsg_new (0); kvmsg_fmt_key (kvmsg, "%d", randof (10000)); kvmsg_fmt_body (kvmsg, "%d", randof (1000000)); kvmsg_send (kvmsg, publisher); kvmsg_destroy (&kvmsg); alarm = zclock_time () + 1000; } } printf (" Interrupted\n%d messages in\n", (int) sequence); zhash_destroy (&kvmap); zctx_destroy (&ctx); return 0; }
int main (void) { // Prepare our context and subscriber void *context = zmq_init (1); void *subscriber = zmq_socket (context, ZMQ_SUB); zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE, "", 0); zmq_connect (subscriber, "tcp://localhost:5556"); void *snapshot = zmq_socket (context, ZMQ_XREQ); zmq_connect (snapshot, "tcp://localhost:5557"); void *updates = zmq_socket (context, ZMQ_PUSH); zmq_connect (updates, "tcp://localhost:5558"); s_catch_signals (); zhash_t *kvmap = zhash_new (); srandom ((unsigned) time (NULL)); // Get state snapshot int64_t sequence = 0; s_send (snapshot, "I can haz state?"); while (!s_interrupted) { kvmsg_t *kvmsg = kvmsg_recv (snapshot); if (!kvmsg) break; // Interrupted if (streq (kvmsg_key (kvmsg), "KTHXBAI")) { sequence = kvmsg_sequence (kvmsg); kvmsg_destroy (&kvmsg); break; // Done } kvmsg_store (&kvmsg, kvmap); } printf ("I: received snapshot=%" PRId64 "\n", sequence); int zero = 0; zmq_setsockopt (snapshot, ZMQ_LINGER, &zero, sizeof (zero)); zmq_close (snapshot); int64_t alarm = s_clock () + 1000; while (!s_interrupted) { zmq_pollitem_t items [] = { { subscriber, 0, ZMQ_POLLIN, 0 } }; int tickless = (int) ((alarm - s_clock ())); if (tickless < 0) tickless = 0; int rc = zmq_poll (items, 1, tickless * 1000); if (rc == -1) break; // Context has been shut down if (items [0].revents & ZMQ_POLLIN) { kvmsg_t *kvmsg = kvmsg_recv (subscriber); if (!kvmsg) break; // Interrupted // Discard out-of-sequence kvmsgs, incl. heartbeats if (kvmsg_sequence (kvmsg) > sequence) { sequence = kvmsg_sequence (kvmsg); kvmsg_store (&kvmsg, kvmap); printf ("I: received update=%" PRId64 "\n", sequence); } else kvmsg_destroy (&kvmsg); } // If we timed-out, generate a random kvmsg if (s_clock () >= alarm) { kvmsg_t *kvmsg = kvmsg_new (0); kvmsg_fmt_key (kvmsg, "%d", randof (10000)); kvmsg_fmt_body (kvmsg, "%d", randof (1000000)); kvmsg_send (kvmsg, updates); kvmsg_destroy (&kvmsg); alarm = s_clock () + 1000; } } zhash_destroy (&kvmap); printf (" Interrupted\n%" PRId64 " messages in\n", sequence); zmq_setsockopt (updates, ZMQ_LINGER, &zero, sizeof (zero)); zmq_close (updates); zmq_close (subscriber); zmq_term (context); return 0; }
int main (void) { // Prepare our context and sockets zctx_t *ctx = zctx_new (); void *snapshot = zsocket_new (ctx, ZMQ_ROUTER); zsocket_bind (snapshot, "tcp://*:5556"); void *publisher = zsocket_new (ctx, ZMQ_PUB); zsocket_bind (publisher, "tcp://*:5557"); void *collector = zsocket_new (ctx, ZMQ_PULL); zsocket_bind (collector, "tcp://*:5558"); // .split body of main task // The body of the main task collects updates from clients and // publishes them back out to clients: int64_t sequence = 0; zhash_t *kvmap = zhash_new (); zmq_pollitem_t items [] = { { collector, 0, ZMQ_POLLIN, 0 }, { snapshot, 0, ZMQ_POLLIN, 0 } }; while (!zctx_interrupted) { int rc = zmq_poll (items, 2, 1000 * ZMQ_POLL_MSEC); // Apply state update sent from client if (items [0].revents & ZMQ_POLLIN) { kvmsg_t *kvmsg = kvmsg_recv (collector); if (!kvmsg) break; // Interrupted kvmsg_set_sequence (kvmsg, ++sequence); kvmsg_send (kvmsg, publisher); kvmsg_store (&kvmsg, kvmap); printf ("I: publishing update %5d\n", (int) sequence); } // Execute state snapshot request if (items [1].revents & ZMQ_POLLIN) { zframe_t *identity = zframe_recv (snapshot); if (!identity) break; // Interrupted // Request is in second frame of message char *request = zstr_recv (snapshot); if (streq (request, "ICANHAZ?")) free (request); else { printf ("E: bad request, aborting\n"); break; } // Send state snapshot to client kvroute_t routing = { snapshot, identity }; // For each entry in kvmap, send kvmsg to client zhash_foreach (kvmap, s_send_single, &routing); // Now send END message with sequence number printf ("I: sending shapshot=%d\n", (int) sequence); zframe_send (&identity, snapshot, ZFRAME_MORE); kvmsg_t *kvmsg = kvmsg_new (sequence); kvmsg_set_key (kvmsg, "KTHXBAI"); kvmsg_set_body (kvmsg, (byte *) "", 0); kvmsg_send (kvmsg, snapshot); kvmsg_destroy (&kvmsg); } } printf (" Interrupted\n%d messages handled\n", (int) sequence); zhash_destroy (&kvmap); zctx_destroy (&ctx); return 0; }