-
Notifications
You must be signed in to change notification settings - Fork 444
/
Main.java
211 lines (188 loc) · 8.47 KB
/
Main.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
package com.dropbox.core.examples.longpoll;
import com.dropbox.core.DbxApiException;
import com.dropbox.core.DbxAuthInfo;
import com.dropbox.core.DbxException;
import com.dropbox.core.DbxRequestConfig;
import com.dropbox.core.DbxWebAuth;
import com.dropbox.core.json.JsonReader;
import com.dropbox.core.http.StandardHttpRequestor;
import com.dropbox.core.v2.DbxClientV2;
import com.dropbox.core.v2.files.DeletedMetadata;
import com.dropbox.core.v2.files.FileMetadata;
import com.dropbox.core.v2.files.FolderMetadata;
import com.dropbox.core.v2.files.ListFolderGetLatestCursorResult;
import com.dropbox.core.v2.files.ListFolderLongpollResult;
import com.dropbox.core.v2.files.ListFolderResult;
import com.dropbox.core.v2.files.Metadata;
import java.io.IOException;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* An example command-line application that demonstrates how to use
* longpolling to watch for file changes in a Dropbox account.
*/
public class Main {
/**
* Will perform longpoll request for changes in the user's Dropbox
* account and display those changes. This is more efficient that
* periodic polling the endpoint.
*/
public static void longpoll(DbxAuthInfo auth, String path) throws IOException {
long longpollTimeoutSecs = TimeUnit.MINUTES.toSeconds(2);
// need 2 Dropbox clients for making calls:
//
// (1) One for longpoll requests, with its read timeout set longer than our polling timeout
// (2) One for all other requests, with its read timeout set to the default, shorter timeout
//
StandardHttpRequestor.Config config = StandardHttpRequestor.Config.DEFAULT_INSTANCE;
StandardHttpRequestor.Config longpollConfig = config.copy()
// read timeout should be well above longpoll timeout to allow for flucuations in response times.
.withReadTimeout(5, TimeUnit.MINUTES)
.build();
DbxClientV2 dbxClient = createClient(auth, config);
DbxClientV2 dbxLongpollClient = createClient(auth, longpollConfig);
try {
// We only care about file changes, not existing files, so grab latest cursor for this
// path and then longpoll for changes.
String cursor = getLatestCursor(dbxClient, path);
System.out.println("Longpolling for changes... press CTRL-C to exit.");
while (true) {
// will block for longpollTimeoutSecs or until a change is made in the folder
ListFolderLongpollResult result = dbxLongpollClient.files.listFolderLongpoll(cursor, longpollTimeoutSecs);
// we have changes, list them
if (result.getChanges()) {
cursor = printChanges(dbxClient, cursor);
}
// we were asked to back off from our polling, wait the requested amount of seconds
// before issuing another longpoll request.
Long backoff = result.getBackoff();
if (backoff != null) {
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(backoff));
} catch (InterruptedException ex) {
System.exit(0);
}
}
}
} catch (DbxApiException ex) {
// if a user message is available, try using that instead
String message = ex.getUserMessage() != null ? ex.getUserMessage().getText() : ex.getMessage();
System.err.println("Error making API call: " + message);
System.exit(1);
return;
} catch (DbxException ex) {
System.err.println("Error making API call: " + ex.getMessage());
System.exit(1);
return;
}
}
/**
* Create a new Dropbox client using the given authentication
* information and HTTP client config.
*
* @param auth Authentication information
* @param config HTTP request configuration
*
* @return new Dropbox V2 client
*/
private static DbxClientV2 createClient(DbxAuthInfo auth, StandardHttpRequestor.Config config) {
String clientUserAgentId = "examples-longpoll";
String userLocale = Locale.getDefault().toString();
StandardHttpRequestor requestor = new StandardHttpRequestor(config);
DbxRequestConfig requestConfig = new DbxRequestConfig(clientUserAgentId, userLocale, requestor);
return new DbxClientV2(requestConfig, auth.getAccessToken(), auth.getHost());
}
/**
* Returns latest cursor for listing changes to a directory in
* Dropbox with the given path.
*
* @param dbxClient Dropbox client to use for fetching the latest cursor
* @param path path to directory in Dropbox
*
* @return cursor for listing changes to the given Dropbox directory
*/
private static String getLatestCursor(DbxClientV2 dbxClient, String path)
throws DbxApiException, DbxException {
ListFolderGetLatestCursorResult result = dbxClient.files.listFolderGetLatestCursorBuilder(path)
.withIncludeDeleted(true)
.withIncludeMediaInfo(false)
.withRecursive(true)
.start();
return result.getCursor();
}
/**
* Prints changes made to a folder in Dropbox since the given
* cursor was retrieved.
*
* @param dbxClient Dropbox client to use for fetching folder changes
* @param cursor lastest cursor received since last set of changes
*
* @return latest cursor after changes
*/
private static String printChanges(DbxClientV2 client, String cursor)
throws DbxApiException, DbxException {
while (true) {
ListFolderResult result = client.files.listFolderContinue(cursor);
for (Metadata metadata : result.getEntries()) {
String type;
String details;
if (metadata instanceof FileMetadata) {
FileMetadata fileMetadata = (FileMetadata) metadata;
type = "file";
details = "(rev=" + fileMetadata.getRev() + ")";
} else if (metadata instanceof FolderMetadata) {
FolderMetadata folderMetadata = (FolderMetadata) metadata;
type = "folder";
details = folderMetadata.getSharingInfo() != null ? "(shared)" : "";
} else if (metadata instanceof DeletedMetadata) {
type = "deleted";
details = "";
} else {
throw new IllegalStateException("Unrecognized metadata type: " + metadata.getClass());
}
System.out.printf("\t%10s %24s \"%s\"\n", type, details, metadata.getPathLower());
}
// update cursor to fetch remaining results
cursor = result.getCursor();
if (!result.getHasMore()) {
break;
}
}
return cursor;
}
public static void main(String[] args) throws IOException {
// Only display important log messages.
Logger.getLogger("").setLevel(Level.WARNING);
if (args.length == 0) {
System.out.println("");
System.out.println("Usage: COMMAND <auth-file> <dropbox-path>");
System.out.println("");
System.out.println(" <auth-file>: An \"auth file\" that contains the information necessary to make");
System.out.println(" an authorized Dropbox API request. Generate this file using the \"authorize\"");
System.out.println(" example program.");
System.out.println("");
System.out.println(" <dropbox-path>: The path on Dropbox to watch for changes.");
System.out.println("");
return;
}
if (args.length != 2) {
System.err.println("Expecting exactly 2 arguments, got " + args.length + ".");
System.err.println("Run with no arguments for help.");
System.exit(1); return;
}
String authFile = args[0];
String path = args[1];
// Read auth info file.
DbxAuthInfo auth;
try {
auth = DbxAuthInfo.Reader.readFromFile(authFile);
}
catch (JsonReader.FileLoadException ex) {
System.err.println("Error loading <auth-file>: " + ex.getMessage());
System.exit(1); return;
}
longpoll(auth, path);
}
}