Search code examples
phpgoogle-glassgoogle-mirror-api

How do I batch insert timeline items using PHP and the Google Glass Mirror API?


Currently, in a PHP code base I work on, several timeline items and a bundle cover are inserted in 4 calls like this:

insert_timeline_item($mirror_service, $new_timeline_item_1, null, null);  
insert_timeline_item($mirror_service, $new_timeline_item_2, null, null);  
insert_timeline_item($mirror_service, $new_timeline_item_3, null, null);  
insert_timeline_item($mirror_service, $new_timeline_item_bundle_cover, null, null);  

I'm aware of the Java and Python ways to send these all in a single batch HTTP call to the Mirror API. How do I do that in PHP?

Right now the cards arrive on the Glass relatively slowly and a user will often try to scroll and see there is nothing to scroll before the other results arrive, for example. Anything that could help the results all arrive at once would help a lot. We already mitigate as much as possible by only making a notification sound on the last card, but it isn't enough for a good user experience.


Solution

  • A batch request to insert timeline items is not guaranteed to arrive all at once or in any particular order. The documentation on batch operations has a footnote that points this out (see the note at the end of the section titled "Response to a batch request" at https://developers.google.com/glass/batch). The only way to ensure that your cards arrive in order is to instead wait for each return response on insert, than fire the last card to create the bundle with your notification chime.

    EDIT: There is a convenience method (Google_Http_Batch()) that you can use when you setup your client by setting the client to setUseBatch(true). See: https://developers.google.com/api-client-library/php/guide/batch

    In terms of just the batch request in PHP, to my knowledge there is not an existing convenience method. You have to build your own request, setup your context via stream_context_create() and then send it via fopen() or file_get_contents().

    I haven't tested the following code, but this is the basic concept:

    // Our batch url endpoint
    $endpoint = "/batch";
    
    // Boundary for our multiple requests
    $boundary = "===============SOMETHINGTHATDOESNOTMATCHCONTENT==\n";
    
    //
    // Build a series of timeline cards to insert
    // probably spin this off into it's own method for simplicty sake
    //
    $timeline_items .= "--" . $boundary;
    $timeline_items .= "Content-Type: application/http\n";
    $timeline_items .= "Content-Transfer-Encoding: binary\n";
    $timeline_items .= "POST /mirror/v1/timeline HTTP/1.1\n";
    $timeline_items .= "Content-Type: application/json\n";
    
    // You'd need the specific ouath2 bearer token for your user here
    //
    // Note, if you were simply sending a single batch to always one user,
    // you could reasonably move this header to the outer /batch params
    // as it will flow down to all child requests as per the documentation
    //
    // see "Format of a batch request" section at https://developers.google.com/glass/batch
    //
    $timeline_items .= "authorization: Bearer " . $user_bearer_token . "\n";
    
    $timeline_items .= "accept: application/json\n";
    $timeline_items .= "content-length: " . strlen($timeline_card_json) . "\n\n";
    $timeline_items .= $timeline_card_json . "\n";
    $timeline_items .= "--" . $boundary;
    
    //
    // Add some other timeline items into your $timeline_items batch
    //
    
    // Setup our params for our context
    $params = array(
        'http' => array( 
            'method' => 'POST', 
            'header' => 'Content-Type: multipart/mixed; boundary="' . $boundary . '"',
            'accept-encoding' => 'gzip, deflate',     
            'content' => $timeline_items
        )
    );
    
    // Create context
    $context = stream_context_create($params); 
    
    // Fire off request
    $batch_result = file_get_contents($endpoint, false, $context);