3

I am watching a Drive resource. Setting up the watch (using the googleapis 0.2.13-alpha client with node.js and drive.file.watch):

exports.subscribeDriveCallbacksCmd = function( user, fileId ){
  var userId = user.id;
  var baseUrl = exports.BASE_URL;
  var subscribeUrl = baseUrl+"/incoming/file";
  var watchId = 'id-'+fileId+'-'+(new Date()).getTime();
  var subscription = {
    id: watchId,
    token: userId+':'+fileId,
    type: 'web_hook',
    address: subscribeUrl,
    params:{
      ttl: 600
    }
  };
  var params = {
    fileId: fileId
  };

//var cmd = client.drive.files.watch( params, subscription );

// FIXME - Hack around bug in RPC implememntation var hack = {channel:subscription}; for( var key in params ){ hack[key] = params[key]; } var cmd = client.drive.files.watch( hack );

return cmd; };

var cmd = exports.subscribeDriveCallbacksCmd( user, '0ZZuoVaqdWGhpUk9PZZ' ); var batch = client.newBatchRequest(); batch.add(cmd); batch.withAuthClient(user.auth).execute(cb);

After this, I'm getting a response of

{ kind: 'api#channel',
    id: 'id-0ZZuoVaqdWGhpUk9PZZ-1374536746592',
    resourceId: 'WT6g4bx-4or2kPWsL53z7YxZZZZ',
    resourceUri: 'https://www.googleapis.com/drive/v2/files/0AHuoVaqdWGhpUkZZZZ?updateViewedDate=false&alt=json',
    token: '101852559274654726533:0ZZuoVaqdWGhpUk9PZZ',
    expiration: '1374537347934' }
and a sync callback with the following headers
  'x-goog-channel-id': 'id-0ZZuoVaqdWGhpUk9PZZ-1374536746592',
  'x-goog-channel-expiration': 'Mon, 22 Jul 2013 23:55:47 GMT',
  'x-goog-resource-state': 'sync',
  'x-goog-message-number': '1',
  'x-goog-resource-id': 'WT6g4bx-4or2kPWsL53z7YxZZZZ',
  'x-goog-resource-uri': 'https://www.googleapis.com/drive/v2/files/0AHuoVaqdWGhpUkZZZZ?updateViewedDate=false&alt=json',
  'x-goog-channel-token': '101852559274654726533:0ZZuoVaqdWGhpUk9PZZ',
  'user-agent': 'APIs-Google; (+http://code.google.com/apis)

There are several problems with this, however:

  • The resource-id returned by both of these do not match the fileId passed when I subscribed to the watch. It does match the ID given in the resource-uri
  • Trying to use either the resourceID returned here, or the fileId passed when I subscribed, returns an error when I try to stop the channel.

The error given for drive.channel.stop varies depending on how I do the call. If I use the API Explorer at the bottom of the Channel: Stop page, providing either the resourceId or the fileId for the resourceId parameter, I get


404 Not Found

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "notFound",
    "message": "Channel not found"
   }
  ],
  "code": 404,
  "message": "Channel not found"
 }
}

If I use the node.js library with this code:

exports.cancelDriveCallbacksCmd = function( watchId, fileId, resourceId ){
  var body = {
    id: watchId,
    resourceId: resourceId
  };
  var cmd = client.drive.channels.stop( body );
  return cmd;
};
var cmd = exports.cancelDriveCallbacksCmd( 'id-0ZZuoVaqdWGhpUk9PZZ-1374536746592', '0ZZuoVaqdWGhpUk9PZZ', 'WT6g4bx-4or2kPWsL53z7YxZZZZ' );
var batch = client.newBatchRequest();
batch.add(cmd);
batch.withAuthClient(user.auth).execute(cb);

I get the error

{ code: 500,
  message: 'Internal Error',
  data: 
   [ { domain: 'global',
       reason: 'internalError',
       message: 'Internal Error' } ] }
which I suspected was related to Bug 59 which has a workaround (which was the hack code I was using above) but should have the fix in place sometime this week, I understand.

So I changed it to this code, which worked around the bug for files.watch:


exports.cancelDriveCallbacksCmd = function( watchId, fileId, resourceId ){
  var params = {};
  var body = {
    id: watchId,
    resourceId: resourceId,
    fileId: fileId
  };

  //var cmd = client.drive.channels.stop( params, body );

  // FIXME - hack around bug in RPC implementation
  var hack = {channel:body};
  for( var key in params ){
    hack[key] = params[key];
  }
  var cmd = client.drive.channels.stop( hack );
  console.log( 'cancelDriveCallbacksCmd', hack );

  return cmd;
};

But I get the same 500 error.

Any thoughts about what I might be doing wrong or how to even go about debugging where I might be going wrong with it?

Prisoner
  • 49,922
  • 7
  • 53
  • 105
  • Answer for first question: resourceId has nothing to do with fileId and just use 1. resourceId returned from Google and 2. channel's id you provided to unsubscribe. – JunYoung Gwak Jul 23 '13 at 01:12
  • FYI, channel resource is bound to user. If you created channel regarding resource of user A, you should unsubscribe with user A's credential or you will get 404. – JunYoung Gwak Jul 23 '13 at 01:17
  • Updated with additional code. If the resourceId has nothing to do with the fileId, why does the resourceUrl include the fileId as part of it? And why are the confirmations coming back without saying what file they're watching? But I was passing the channel ID (that I assigned) and the resourceID (that it returned) and was getting the errors in question. Both operations are being done by the same user, although via two different access_tokens generated from two different apps. – Prisoner Jul 23 '13 at 03:58

1 Answers1

6
  1. Push notification is designed to watch any api resource, although it only supports Changes and Files for now. Thus, it needs unique resourceId for all resource type. That is the reason why they have resourceId that is not equal to fileId.

  2. Confirmations do come back with info about which file it is watching. Check header of your response. Also, you can make use of token to save channel specific information if you want.

  3. If you are using API explorer, you cannot unsubscribe from the channel because as you know, push notification requires additional verification of url through apis console and apis explorer is not authenticated to access your notification. It is working as intended by security reason. I will report about this issue to stop people from getting confused with this.

  4. fileId doesn't go to request body. It should be one of the parameters. Also, you should make request to Channels.stop() to unsubscribe. Something like this:

Code to subscribe:

var channel= {
  'id': 'yourchannelid',
  'type': 'web_hook',
  'address': 'https://notification.endpoint'
};
var request = client.drive.files.watch({'fileId': fileId, 'channel':channel});

Code to unsubscribe

var request = client.drive.channels.stop({'id': channelId, 'resourceId':resourceId});
Ali Afshar
  • 40,967
  • 12
  • 95
  • 109
JunYoung Gwak
  • 2,967
  • 3
  • 21
  • 35
  • Re: item 2) As illustrated above, I've made use of the token, since there doesn't appear to be any header that comes back with the file-id being watched, and I didn't think parsing the resource-uri header would be reliable in the long term. – Prisoner Jul 23 '13 at 13:20
  • Re: item 4) You found one of the problems with the code! I had cut/paste the Bug 59 hack-around incorrectly and was calling files.watch instead of channels.stop. I updated the question above to reflect two of the ways I've tried calling channels.stop, and both are generating a 500 error. – Prisoner Jul 23 '13 at 13:32
  • Re: items 1 and 3) Thanks for clarifying these points! Both make sense, although since I frequently use the API Explorer to test things out based on my code, it did confuse things. I appreciate the explanations and the help. – Prisoner Jul 23 '13 at 13:35
  • 4) Did you try the code I posted? That bug is a known issue and the code I posted is a tested workaround. – JunYoung Gwak Jul 23 '13 at 15:54
  • 2) In the header, I just tested that I receive `X-Goog-Resource-Uri` which contains fileId in this format: `https://www.googleapis.com/drive/v2/files/0Bw_2Lr1vw5_nnnhVOF8zczZ4Ync?updateViewedDate=false&alt=json` Do you see fileId in resource Uri? Resource Uri represents which resource the push notification is watching on which does contain fileId. – JunYoung Gwak Jul 23 '13 at 15:56
  • 3) I will report api explorer issue. Thank you! – JunYoung Gwak Jul 23 '13 at 16:11
  • 2) Ok, so we can assume that the format of x-goog-resource-uri won't change and can parse that out? Good. Thank you. – Prisoner Jul 23 '13 at 21:25
  • 4) Yes, I tried a cut and paste of your unsubscribe code. if the channelId variable is the same as 'yourchannelid' given your above example. It gives me the 500 error. – Prisoner Jul 23 '13 at 21:27
  • 4) This code is tested from Javascript client. I thought node.js client works almost the same way as javascript client does but it seems like that is not the case. I'll ask node.js expert for help. – JunYoung Gwak Jul 23 '13 at 22:46
  • 1
    It seems like this is a bug. Will be fixed soon. – JunYoung Gwak Jul 24 '13 at 16:38