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