CWindows CWindows CFreeRTOSmbedPosix CWindows C Storage & Playback Tutorial for Realtime Apps

Requires that the Storage and Playback add-on is enabled for your key. How do I enable add-on features for my keys? - see http://www.pubnub.com/knowledge-base/discussion/644/how-do-i-enable-add-on-features-for-my-keys
PubNub's Storage and Playback feature enables developers to store messages as they are published, and retrieve them at a later time. Before using this feature it must be enabled in the PubNub Admin Console.
Being able to pull an archive of messages from storage has many applications:
  • Populate chat, collaboration and machine configuration on app load.
  • Store message streams with real-time data management.
  • Retrieve historical data streams for reporting, auditing and compliance (HIPAA, SOX, Data Protection Directive, and more).
  • Replay live events with delivery of real-time data during rebroadcasting.
As needed, specific messages can be marked "do not archive" when published to prevent archiving on a per-message basis, and storage retention time can range from 1 day to forever.
These code samples build off code defined in the Pub & Sub tutorial, so before proceeding, be sure you have completed the Pub & Sub tutorial first.
To begin, lets populate a new channel with some test publishes that we'll pull from storage using the pubnub_history() method.

We'll define a callback for response handing that is applicable for both pubnub_publish() and pubnub_history() methods.
//Only for Callback, not required for Sync

struct UserData {
  CRITICAL_SECTION mutw;
  HANDLE condw;
  pubnub_t *pn;
};

struct UserData user_data;

static void InitUserData(struct UserData *pUserData, pubnub_t *pn) {
  InitializeCriticalSection(&pUserData->mutw);
  pUserData->condw = CreateEvent(NULL, TRUE, FALSE, NULL);
  pUserData->pn = pn;
}

void sample_callback(pubnub_t *pn, enum pubnub_trans trans, enum pubnub_res result, void *user_data)
{
  struct UserData *pUserData = (struct UserData*)user_data;

  SetEvent(pUserData->condw);
}

static enum pubnub_res await(struct UserData *pUserData)
{
  ResetEvent(pUserData->condw);
  WaitForSingleObject(pUserData->condw, INFINITE);

  return pubnub_last_result(pUserData->pn);
}

int main() {
  pubnub_t *pn = pubnub_alloc();
  if (NULL == pn) {
    printf("Failed to allocate Pubnub context!\n");
    return -1;
  }

  InitUserData(&user_data, pn);

  pubnub_init(pn, "demo", "demo");
  pubnub_register_callback(pn, sample_callback, &user_data);

  // ...

  pubnub_free(pn);
  return 0;
}
Before we can pull history for a channel, that channel must first have had messages published on it. We'll do just that by publishing some messages onto a channel to "seed" it for a history call.
//Sync Example

#define BUFFER_SIZE 14

const char *channel = "history_channel";
const char *message_tmp = "\"message#%d\"";
char buffer[BUFFER_SIZE];
enum pubnub_res res;
int i;

for (i = 0; i < 500; i++) {
  snprintf(buffer, BUFFER_SIZE, message_tmp, i);
  pubnub_publish(pn, channel, buffer);
  res = pubnub_await(pn);

  if (PNR_OK != res) {
    printf("Publishing #%d failed with code: %d\n", i, res);
    break;
  }
}


// Callback Example
#define BUFFER_SIZE 14

void publish_500_messages(pubnub_t *pn) {
  const char *channel = "history_channel";
  const char *message_tmp = "\"message#%d\"";
  char buffer[BUFFER_SIZE];
  enum pubnub_res res;
  int i;

  pubnub_register_callback(pn, sample_callback);

  for (i = 0; i < 500; i++) {
    snprintf(buffer, BUFFER_SIZE, message_tmp, i);
    pubnub_publish(pn, channel, buffer);
    printf("Publishing #%d...", i);

    await();

    res = pubnub_last_result(pn);
    if (PNR_OK != res) {
      printf(" Publishing #%d failed with code: %d\n", i, res);
      break;
    }

    printf(" OK\n");
  }
}
In the above example, we publish a barrage of test messages to history_channel.
Now that we've populated the channel (and thus the backend storage system), we can pull from storage using the pubnub_history() method call:
// Sync
enum pubnub_res res;
const char *msg;

pubnub_history(pn, "history_channel", 10, false);
res = pubnub_await(pn);

if (PNR_OK == res) {
  puts("Got history! Messages:");
  for (;;) {
    msg = pubnub_get(pn);
    if (NULL == msg) {
      break;
    }
    puts(msg);
  }
} else {
  printf("Getting history failed with code: %d\n", res);
}


// Callback
void get_last_10_messages(pubnub_t *pn) {
  enum pubnub_res res;
  const char *msg;

  pubnub_register_callback(pn, sample_callback);

  pubnub_history(pn, "history_channel", 10, false);
  await();
  res = pubnub_last_result(pn);

  if (PNR_OK == res) {
    puts("Got history! Messages:");
    for (;;) {
      msg = pubnub_get(pn);
      if (NULL == msg) {
        break;
      }
      puts(msg);
    }
  } else {
    printf("Getting history failed with code: %d\n", res);
  }
}
The response format is

[
	["message1", "message2", "message3",... ],
	"Start Time Token",
	"End Time Token"
]
In general, Pubnub SDKs have a default of 100 messages for the count argument of the history transaction. Current version of C-core doesn't provide a way to not specify the count, as it is a regular parameter of pubnub_history and there are no optional parameters in C. So, you always have to set the count. But, in case you have no idea what to use, use 100.
The timetoken response value is a string, representing 17-digit precision unix time (UTC). To convert PubNub's timetoken to Unix timestamp (seconds), divide the timetoken number by 10,000,000 (10^7).