|
3 | 3 | import android.content.Context; |
4 | 4 | import android.net.Uri; |
5 | 5 | import android.os.Build; |
6 | | -import android.os.Handler; |
7 | 6 |
|
8 | 7 | import androidx.annotation.RequiresApi; |
9 | 8 |
|
10 | | -import com.google.android.gms.tasks.Task; |
11 | | -import com.google.android.gms.tasks.Tasks; |
12 | | -import com.google.firebase.auth.AuthResult; |
13 | | -import com.google.firebase.auth.FirebaseAuth; |
14 | | -import com.google.firebase.storage.FirebaseStorage; |
15 | | -import com.google.firebase.storage.StorageMetadata; |
16 | | -import com.google.firebase.storage.StorageReference; |
17 | | -import com.google.firebase.storage.UploadTask; |
18 | | - |
19 | 9 | import java.io.File; |
20 | 10 | import java.io.IOException; |
| 11 | +import java.io.InputStream; |
21 | 12 | import java.io.OutputStream; |
22 | 13 | import java.io.OutputStreamWriter; |
23 | 14 | import java.io.PrintWriter; |
|
26 | 17 | import java.net.URL; |
27 | 18 | import java.net.URLEncoder; |
28 | 19 | import java.nio.file.Files; |
29 | | -import java.util.UUID; |
30 | | -import java.util.concurrent.ExecutionException; |
31 | | - |
32 | | -import at.tomtasche.reader.nonfree.AnalyticsManager; |
33 | | -import at.tomtasche.reader.nonfree.CrashManager; |
34 | 20 |
|
35 | 21 | public class OnlineLoader extends FileLoader { |
36 | 22 |
|
| 23 | + private static final String TRANSFER_BASE_URL = "https://transfershxuil1jyq-transfer-sh.functions.fnc.nl-ams.scw.cloud"; |
| 24 | + |
37 | 25 | // https://help.joomlatools.com/article/169-google-viewer |
38 | 26 | // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_types |
39 | 27 | private static final String[] MIME_WHITELIST = {"text/", "image/", "video/", "audio/", |
@@ -76,26 +64,11 @@ public class OnlineLoader extends FileLoader { |
76 | 64 |
|
77 | 65 | private final CoreLoader coreLoader; |
78 | 66 |
|
79 | | - private StorageReference storage; |
80 | | - private FirebaseAuth auth; |
81 | | - |
82 | 67 | public OnlineLoader(Context context, CoreLoader coreLoader) { |
83 | 68 | super(context, LoaderType.ONLINE); |
84 | 69 | this.coreLoader = coreLoader; |
85 | 70 | } |
86 | 71 |
|
87 | | - @Override |
88 | | - public void initialize(FileLoaderListener listener, Handler mainHandler, Handler backgroundHandler, AnalyticsManager analyticsManager, CrashManager crashManager) { |
89 | | - super.initialize(listener, mainHandler, backgroundHandler, analyticsManager, crashManager); |
90 | | - |
91 | | - try { |
92 | | - storage = FirebaseStorage.getInstance().getReference(); |
93 | | - auth = FirebaseAuth.getInstance(); |
94 | | - } catch (Throwable e) { |
95 | | - crashManager.log(e); |
96 | | - } |
97 | | - } |
98 | | - |
99 | 72 | @Override |
100 | 73 | public boolean isSupported(Options options) { |
101 | 74 | String fileType = options.fileType; |
@@ -126,10 +99,10 @@ public void loadSync(Options options) { |
126 | 99 | try { |
127 | 100 | Uri viewerUri; |
128 | 101 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && |
129 | | - ("text/rtf".equals(options.fileType) || "application/vnd.wordperfect".equals(options.fileType) || coreLoader.isSupported(options) || "application/vnd.ms-excel".equals(options.fileType) || "application/msword".equals(options.fileType) || "application/vnd.ms-powerpoint".equals(options.fileType) || options.fileType.startsWith("application/vnd.openxmlformats-officedocument.") || options.fileType.equals("application/pdf"))) { |
| 102 | + ("text/rtf".equals(options.fileType))) { |
130 | 103 | viewerUri = doOnlineConvert(options); |
131 | 104 | } else { |
132 | | - viewerUri = doFirebaseConvert(options); |
| 105 | + viewerUri = doTransferUpload(options); |
133 | 106 | } |
134 | 107 |
|
135 | 108 | result.partTitles.add(null); |
@@ -175,66 +148,82 @@ private Uri doOnlineConvert(Options options) throws IOException { |
175 | 148 | return Uri.parse(basePath + redirectUrl); |
176 | 149 | } |
177 | 150 |
|
178 | | - private Uri doFirebaseConvert(Options options) throws ExecutionException, InterruptedException, UnsupportedEncodingException { |
179 | | - if (auth == null || storage == null) { |
180 | | - throw new RuntimeException("firebase not initialized"); |
| 151 | + private Uri doTransferUpload(Options options) throws IOException { |
| 152 | + File binaryFile = AndroidFileCache.getCacheFile(context, options.cacheUri); |
| 153 | + String filename = options.filename; |
| 154 | + if (filename == null || filename.isEmpty()) { |
| 155 | + filename = "document." + options.fileExtension; |
181 | 156 | } |
182 | 157 |
|
183 | | - Task<AuthResult> authenticationTask = null; |
184 | | - String currentUserId = null; |
185 | | - if (auth.getCurrentUser() != null) { |
186 | | - currentUserId = auth.getCurrentUser().getUid(); |
187 | | - } else { |
188 | | - authenticationTask = auth.signInAnonymously(); |
| 158 | + String encodedFilename = URLEncoder.encode(filename, StreamUtil.ENCODING); |
| 159 | + String basePath = ensureTrailingSlash(TRANSFER_BASE_URL); |
| 160 | + HttpURLConnection connection = (HttpURLConnection) new URL(basePath + encodedFilename).openConnection(); |
| 161 | + connection.setRequestMethod("PUT"); |
| 162 | + connection.setDoOutput(true); |
| 163 | + connection.setInstanceFollowRedirects(false); |
| 164 | + if (!"N/A".equals(options.fileType)) { |
| 165 | + connection.setRequestProperty("Content-Type", options.fileType); |
189 | 166 | } |
190 | 167 |
|
191 | | - if (authenticationTask != null) { |
192 | | - Tasks.await(authenticationTask); |
193 | | - |
194 | | - currentUserId = authenticationTask.getResult().getUser().getUid(); |
| 168 | + try (OutputStream outputStream = connection.getOutputStream()) { |
| 169 | + Files.copy(binaryFile.toPath(), outputStream); |
| 170 | + outputStream.flush(); |
195 | 171 | } |
196 | 172 |
|
197 | | - StorageMetadata.Builder metadataBuilder = new StorageMetadata.Builder(); |
198 | | - if (!"N/A".equals(options.fileType)) { |
199 | | - metadataBuilder.setContentType(options.fileType); |
200 | | - } |
| 173 | + int responseCode = connection.getResponseCode(); |
| 174 | + if (responseCode >= 200 && responseCode < 300) { |
| 175 | + String downloadUrl = readBody(connection); |
| 176 | + if (downloadUrl == null || downloadUrl.isEmpty()) { |
| 177 | + downloadUrl = connection.getHeaderField("Location"); |
| 178 | + } |
201 | 179 |
|
202 | | - String filePath = currentUserId + "/" + UUID.randomUUID() + "." + options.fileExtension; |
203 | | - StorageReference reference = storage.child("uploads/" + filePath); |
204 | | - UploadTask uploadTask = reference.putFile(options.cacheUri, metadataBuilder.build()); |
205 | | - Tasks.await(uploadTask); |
| 180 | + if (downloadUrl == null || downloadUrl.isEmpty()) { |
| 181 | + throw new IOException("server couldn't handle request"); |
| 182 | + } |
206 | 183 |
|
207 | | - if (uploadTask.isSuccessful()) { |
208 | | - Uri viewerUri; |
209 | | - if (coreLoader.isSupported(options)) { |
210 | | - // ODF does not seem to be supported by google docs viewer |
211 | | - String downloadUrl = "https://us-central1-admob-app-id-9025061963.cloudfunctions.net/download?filePath=" + filePath; |
| 184 | + return buildViewerUri(options, downloadUrl.trim()); |
| 185 | + } else { |
| 186 | + String error = readError(connection); |
| 187 | + throw new IOException("server couldn't handle request: " + responseCode + " " + error); |
| 188 | + } |
| 189 | + } |
212 | 190 |
|
213 | | - viewerUri = Uri.parse(MICROSOFT_VIEWER_URL + downloadUrl); |
214 | | - } else { |
215 | | - Task<Uri> urlTask = reference.getDownloadUrl(); |
216 | | - Tasks.await(urlTask); |
217 | | - String downloadUrl = urlTask.getResult().toString(); |
| 191 | + private Uri buildViewerUri(Options options, String downloadUrl) throws UnsupportedEncodingException { |
| 192 | + if (coreLoader.isSupported(options)) { |
| 193 | + // ODF does not seem to be supported by google docs viewer |
| 194 | + return Uri.parse(MICROSOFT_VIEWER_URL + downloadUrl); |
| 195 | + } else { |
| 196 | + return Uri.parse(GOOGLE_VIEWER_URL + URLEncoder.encode(downloadUrl, StreamUtil.ENCODING)); |
| 197 | + } |
| 198 | + } |
218 | 199 |
|
219 | | - viewerUri = Uri.parse(GOOGLE_VIEWER_URL + URLEncoder.encode(downloadUrl, StreamUtil.ENCODING)); |
220 | | - } |
| 200 | + private String ensureTrailingSlash(String base) { |
| 201 | + if (base.endsWith("/")) { |
| 202 | + return base; |
| 203 | + } |
221 | 204 |
|
222 | | - return viewerUri; |
223 | | - } else { |
224 | | - throw new RuntimeException("server couldn't handle request"); |
| 205 | + return base + "/"; |
| 206 | + } |
| 207 | + |
| 208 | + private String readBody(HttpURLConnection connection) throws IOException { |
| 209 | + InputStream inputStream = connection.getInputStream(); |
| 210 | + if (inputStream == null) { |
| 211 | + return null; |
225 | 212 | } |
| 213 | + |
| 214 | + return StreamUtil.readFully(inputStream); |
226 | 215 | } |
227 | 216 |
|
228 | | - @Override |
229 | | - public void close() { |
230 | | - super.close(); |
231 | | - |
232 | | - backgroundHandler.post(new Runnable() { |
233 | | - @Override |
234 | | - public void run() { |
235 | | - auth = null; |
236 | | - storage = null; |
| 217 | + private String readError(HttpURLConnection connection) { |
| 218 | + try { |
| 219 | + InputStream errorStream = connection.getErrorStream(); |
| 220 | + if (errorStream == null) { |
| 221 | + return null; |
237 | 222 | } |
238 | | - }); |
| 223 | + |
| 224 | + return StreamUtil.readFully(errorStream); |
| 225 | + } catch (Throwable t) { |
| 226 | + return null; |
| 227 | + } |
239 | 228 | } |
240 | 229 | } |
0 commit comments