问题
I have subscribed my app to listen to Google push notifications. Channel details was persisted. I can receive notifications from google to my endpoint.
@PostMapping("/google/calendars/")
public void watch(HttpServletRequest request,
@RequestHeader(value = "X-Goog-Channel-ID", required = false) String googleChannelId,
@RequestHeader(value = "X-Goog-Channel-Token", required = false) String googleChannelToken,
@RequestHeader(value = "X-Goog-Channel-Expiration", required = false) String googleChannelExpiration,
@RequestHeader(value = "X-Goog-Resource-ID", required = false) String googleResourceId,
@RequestHeader(value = "X-Goog-Resource-URI", required = false) String googleResourceUri,
@RequestHeader(value = "X-Goog-Resource-State", required = false) String googleResourceState,
@RequestHeader(value = "X-Goog-Message-Number", required = false) String googleMessageNumber,
Using information was received I can open client
to google service. But I do not know how to get changes.
googleChannelId=354a78aa-0cc0-4b5b-96c5-e54e03a51e68
googleChannelToken=<null>
googleChannelExpiration=Sat, 18 Mar 2017 17:01:56 GMT
googleResourceId=eVHbdUeaWhfQPpvJPU7VZRxYzUs
googleResourceUri=https://www.googleapis.com/calendar/v3/calendars/sergii_vlasiuk@ukr.net/events?maxResults=250&alt=json
googleResourceState=exists
googleMessageNumber=403802722
exists
means googleResourceId
was changed.
Using googleChannelId
I load my channel details and open client.
- How to use
googleResourceId
in my pull change request (request example maybe)? - Is it correct understanding:
not_exists
means resource was deleted;exists
means resource was created or edited?
Add details
I've tried
client.events().get(originalCalendarId, googleResourceId).execute()
Where:
client
iscom.google.api.services.calendar.Calendar
object with correct tokens.ginalCalendarId
- is good known google calendar Id, one was used in subscription.googleResourceId
- is from header messageX-Goog-Resource-ID
value. ->404 Not Found { "code" : 404, "errors" : [ { "domain" : "global", "message" : "Not Found", "reason" : "notFound" } ], "message" : "Not Found" }
回答1:
If Google doesn't have a convenient approach to distinguish which exactly entities have been updated, I suppose we should think about a workaround. In my opinion, getting all the events and updating your database state by traversing and rewriting all the data will lead you to some performance issues.
To address that, I would choose using "etag" value that each event has. Every time an event is updated, the ETag changes(works in CalDav protocol)
http://cdn.nsoftware.com/help/IP9/cs/CalDAV_p_ETag.htm
If you save etag to your database with your event, then once you get the list of events from Google, you can just check etag value and update only the elements that were really changed. That must optimize the part when you update your entries.
Google supports etag. You can find it here:
https://developers.google.com/google-apps/calendar/v3/reference/events/list
{
"kind": "calendar#events",
"etag": etag,
"summary": string,
"description": string,
"updated": datetime,
"timeZone": string,
"accessRole": string,
"defaultReminders": [
{
"method": string,
"minutes": integer
}
],
"nextPageToken": string,
"nextSyncToken": string,
"items": [
events Resource
]
}
UPDATED:
There is a more convenient way to perform synchronization. You can use Incremental synchronization approach. Incremental sync allows you to retrieve all the resources that have been modified since the last sync request.
https://developers.google.com/google-apps/calendar/v3/sync#initial_full_sync
You just need to save sync token every time you update data and use it in the request to get new data. In this case you will get only data that was modified.
Calendar.Events.List request = client.events().list("primary");
request.setSyncToken(syncToken);
If you call then:
events = request.execute();
List<Event> items = events.getItems();
You will get only the data that was updated.
回答2:
But I do not know how to get changes.
The Google Calendar API provides push notifications that let you watch for changes to resources. You can use this feature to improve the performance of your application. It allows you to eliminate the extra network and compute costs involved with polling resources to determine if they have changed. Whenever a watched resource changes, the Google Calendar API notifies your application.
Once you have set up watch correctly your application will be informed when there has been a change. You don't need to check for it.
Example
POST https://www.googleapis.com/calendar/v3/calendars/my_calendar@gmail.com/events/watch
Authorization: Bearer auth_token_for_current_user
Content-Type: application/json
{
"id": "01234567-89ab-cdef-0123456789ab", // Your channel ID.
"type": "web_hook",
"address": "https://example.com/notifications", // Your receiving URL.
...
"token": "target=myApp-myCalendarChannelDest", // (Optional) Your channel token.
"expiration": 1426325213000 // (Optional) Your requested channel expiration time.
}
}
There is a full article on how to set this up the documentation Push Notifications
Note:
This statement wont work because Events.get requires an event Id
as its second parameter not your GoogleResourceId
client.events().get(originalCalendarId, googleResourceId).execute()
How watch works:
- You decide you want to watch for changes on a users events. You create a watch on the events. Google returns to you resourceId this identifies the watch.
- A change is made google sends you a notification in the form of a HTTP Post. It contains the resource id from your watch.
- You know that the watch with this resource id is liked to a users events. You use your refresh token to gain access to the users account. you do an events list and scan though each of the events looking for which one has changes.
The resource Id can not be used to request events. The watch does not tell you what exactly was changed or when. You have to query the API to find that out.
来源:https://stackoverflow.com/questions/42738920/google-push-notifications-java-handler