From e278bc10a1617a9b5bd6bee7653632e99bd3c9b4 Mon Sep 17 00:00:00 2001 From: Michael Mikovsky <77305074+Astatin3@users.noreply.github.com> Date: Sun, 25 May 2025 18:48:02 -0600 Subject: [PATCH] Add java side of http syncing --- .gitignore | 6 + .../ui/settings/SettingsFragment.java | 9 +- .../ridgescout/ui/transfer/FTPSync.java | 3 +- .../ridgescout/ui/transfer/HttpSync.java | 369 ++++++++++++++++++ .../ui/transfer/TransferFragment.java | 10 +- .../ridgescout/utility/HttpGetFile.java | 168 ++++++++ .../ridgescout/utility/HttpPutFile.java | 161 ++++++++ .../ridgescout/utility/SettingsManager.java | 7 +- server/main.py | 4 +- server/utils.py | 2 +- 10 files changed, 726 insertions(+), 13 deletions(-) create mode 100644 app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/HttpSync.java create mode 100644 app/src/main/java/com/ridgebotics/ridgescout/utility/HttpGetFile.java create mode 100644 app/src/main/java/com/ridgebotics/ridgescout/utility/HttpPutFile.java diff --git a/.gitignore b/.gitignore index f512cf7..24b0a61 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ +# Python server +__pycache__/ +metadata.json +api_key.txt +server_data/ + # Gradle files .gradle/ build/ diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/settings/SettingsFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/settings/SettingsFragment.java index 2695244..7e47aca 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/settings/SettingsFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/settings/SettingsFragment.java @@ -46,6 +46,7 @@ import com.ridgebotics.ridgescout.ui.views.CustomSpinnerView; import com.ridgebotics.ridgescout.ui.views.TallyCounterView; import com.ridgebotics.ridgescout.utility.DataManager; import com.ridgebotics.ridgescout.utility.FileEditor; +import com.ridgebotics.ridgescout.utility.SettingsManager; import java.util.ArrayList; import java.util.Arrays; @@ -92,11 +93,13 @@ public class SettingsFragment extends Fragment { manager.addItem(new CheckboxSettingsItem(CustomEventsKey, "Custom Events")); - StringSettingsItem FTPServer = new StringSettingsItem(com.ridgebotics.ridgescout.utility.SettingsManager.FTPServer, "FTP Server (Sync)"); + StringSettingsItem FTPKey = new StringSettingsItem(com.ridgebotics.ridgescout.utility.SettingsManager.FTPKey, "Sync Key"); + manager.addItem(FTPKey); + StringSettingsItem FTPServer = new StringSettingsItem(com.ridgebotics.ridgescout.utility.SettingsManager.FTPServer, "Sync Server (Sync)"); manager.addItem(FTPServer); - CheckboxSettingsItem FTPSendMetaFiles = new CheckboxSettingsItem(com.ridgebotics.ridgescout.utility.SettingsManager.FTPSendMetaFiles, "Sync meta files"); + CheckboxSettingsItem FTPSendMetaFiles = new CheckboxSettingsItem(com.ridgebotics.ridgescout.utility.SettingsManager.FTPSendMetaFiles, "⚠ Send meta files"); manager.addItem(FTPSendMetaFiles); - CheckboxSettingsItem FTPEnabled = new CheckboxSettingsItem(com.ridgebotics.ridgescout.utility.SettingsManager.FTPEnabled, "FTP Enabled", FTPServer, FTPSendMetaFiles); + CheckboxSettingsItem FTPEnabled = new CheckboxSettingsItem(com.ridgebotics.ridgescout.utility.SettingsManager.FTPEnabled, "FTP Enabled", FTPServer, FTPKey, FTPSendMetaFiles); manager.addItem(FTPEnabled); manager.addItem(new CheckboxSettingsItem(WifiModeKey, "Wifi Mode", FTPEnabled)); diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/FTPSync.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/FTPSync.java index 4c05be6..1cefd16 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/FTPSync.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/FTPSync.java @@ -26,7 +26,8 @@ import java.util.List; import java.util.Map; import java.util.Set; -// This is now deprsicated +// This is now deprecated +// Class to synchronise data over FTP. public class FTPSync extends Thread { public static final String remoteBasePath = "/RidgeScout/"; public static final String timestampsFilename = "timestamps"; diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/HttpSync.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/HttpSync.java new file mode 100644 index 0000000..53d5bc7 --- /dev/null +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/HttpSync.java @@ -0,0 +1,369 @@ +package com.ridgebotics.ridgescout.ui.transfer; + +import static com.ridgebotics.ridgescout.utility.FileEditor.baseDir; + +import com.ridgebotics.ridgescout.utility.AlertManager; +import com.ridgebotics.ridgescout.utility.BuiltByteParser; +import com.ridgebotics.ridgescout.utility.ByteBuilder; +import com.ridgebotics.ridgescout.utility.FileEditor; +import com.ridgebotics.ridgescout.utility.HttpGetFile; +import com.ridgebotics.ridgescout.utility.HttpPutFile; +import com.ridgebotics.ridgescout.utility.RequestTask; +import com.ridgebotics.ridgescout.utility.SettingsManager; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; + +// This is now deprsicated +// Class to syncronise data over FTP. +public class HttpSync extends Thread { + public static final String timestampsFilename = "timestamps"; + + private static final long millisTolerance = 1000; + + private boolean after(Date a, Date b){ + return a.getTime() - b.getTime() > millisTolerance; + } + + + public interface onResult { + void onResult(boolean error, int upCount, int downCount); + } + public interface UpdateIndicator { + void onText(String text); + } + private static UpdateIndicator updateIndicator = text -> {}; + public static String text = ""; + private static void setUpdateIndicator(String m_text){ + text = m_text; + updateIndicator.onText(m_text); + } + public static void setOnUpdateIndicator(UpdateIndicator m_updateIndicator){ + updateIndicator = m_updateIndicator; + } + + private static onResult onResult = (error, upCount, downCount) -> {}; + public static void setOnResult(onResult result){ + onResult = result; + } + + private static boolean isRunning = false; + public static boolean getIsRunning(){return isRunning;} + + public static void sync(){ +// DataManager.reload_event(); + HttpSync sync = new HttpSync(); + + sync.start(); + } + + private int upCount = 0; + private int downCount = 0; + + private class TransferFile { + public String filename; + public Date updated; + public String checksum; + } + + private List localFiles = new ArrayList<>(); + private List remoteFiles = new ArrayList<>(); + + + + private void await() { + while(!runningRequest.get()) { + try { + Thread.sleep(100); + } catch (InterruptedException e) {} + } + } + + + AtomicBoolean runningRequest = new AtomicBoolean(false); + + public void run() { + isRunning = true; + boolean sendMetaFiles = SettingsManager.getFTPSendMetaFiles(); + String serverIP = SettingsManager.getFTPServer(); + String serverKey = SettingsManager.getFTPKey(); + + setUpdateIndicator("Getting Metadata..."); + + // Load metadata from server + getRemoteFileMetadata(serverIP, serverKey); + + if(!isRunning){ + setUpdateIndicator("Error Connecting"); + onResult.onResult(true, upCount, downCount); + return; + } + + + getLocalFileMetadata(); + + + + + // Wait for metadata request to finish + + setUpdateIndicator("Uploading 0%"); + + for(int i = 0; i < localFiles.size(); i++){ + TransferFile localFile = localFiles.get(i); + + System.out.print("LocalFile: " + localFile.filename + ", " + localFile.checksum + ", " + localFile.updated + ": "); + TransferFile remoteFile = findInFileArray(remoteFiles, localFile.filename); + + + + if( + ( + sendMetaFiles || !( + localFile.filename.endsWith(".fields") + ) + + ) + && (remoteFile == null || + ( + !Objects.equals(localFile.checksum, remoteFile.checksum) && + after(localFile.updated, remoteFile.updated) + ) + )) { + uploadFile(localFile, serverIP, serverKey); +// await(); + System.out.println("Uploaded"); + upCount++; + }else { + System.out.println("Did not upload"); + } + + setUpdateIndicator("Uploading " + (Math.floor((double) (i * 1000) / localFiles.size()) / 10) + "%"); + } + + setUpdateIndicator("Downloading 0%"); + + for(int i = 0; i < remoteFiles.size(); i++){ + TransferFile remoteFile = remoteFiles.get(i); + + System.out.print("RemoteFile: " + remoteFile.filename + ", " + remoteFile.checksum + ", " + remoteFile.updated + ": "); + TransferFile localFile = findInFileArray(localFiles, remoteFile.filename); + + if(localFile == null || + ( + !Objects.equals(localFile.checksum, remoteFile.checksum) && + after(remoteFile.updated, localFile.updated) && + !localFile.updated.equals(remoteFile.updated) + ) + ) { + downloadFile(remoteFile, serverIP); +// await(); + System.out.println("Downloaded"); + downCount++; + } else { + System.out.println("Did not download"); + } + + + setUpdateIndicator("Downloading " + (Math.floor((double) (i * 1000) / remoteFiles.size()) / 10) + "%"); + } + + + + + setUpdateIndicator("Finished, " + upCount + " Up, " + downCount + " Down"); + + + onResult.onResult(false, upCount, downCount); + isRunning = false; + } + + + private TransferFile findInFileArray(List files, String filename){ + for(TransferFile file : files) { + if(file.filename.equals(filename)) + return file; + } + return null; + } + + private Date getLocalFileUtcTimestamp(File file) { + return new Date(file.lastModified()); + } + + public static String getSHA256Hash(String filePath) throws IOException, NoSuchAlgorithmException { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + FileInputStream fis = new FileInputStream(filePath); + byte[] byteArray = new byte[1024]; + int bytesCount = 0; + + while ((bytesCount = fis.read(byteArray)) != -1) { + digest.update(byteArray, 0, bytesCount); + } + fis.close(); + + byte[] bytes = digest.digest(); + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } + + private void getLocalFileMetadata() { + File localDir = new File(baseDir); + File[] localFileNames = localDir.listFiles(); + + assert localFileNames != null; + for (int i = 0; i < localFileNames.length; i++) { + File file = localFileNames[i]; + + if(file.isDirectory()) continue; + // Remove timestamts file + if(file.getName().equals(timestampsFilename)) continue; + + TransferFile tf = new TransferFile(); + tf.filename = file.getName(); + tf.updated = getLocalFileUtcTimestamp(file); + try { + tf.checksum = getSHA256Hash(file.getPath()); + } catch (Exception e) { + + } + localFiles.add(tf); + } + } + + // Send request to server and retrieve metadata + private void getRemoteFileMetadata(String serverURL, String serverKey) { + final RequestTask rq = new RequestTask(); + runningRequest.set(false); + rq.onResult(metadata -> { + try { + JSONObject j = new JSONObject(metadata); + for (Iterator it = j.keys(); it.hasNext(); ) { + String key = it.next(); + + JSONObject obj = j.getJSONObject(key); + + TransferFile tf = new TransferFile(); + tf.filename = key; + tf.updated = new Date(Long.parseLong(obj.getString("modified"))); + tf.checksum = obj.getString("sha256"); + + remoteFiles.add(tf); + } + }catch(JSONException | NullPointerException e ) { + AlertManager.error(e); + isRunning = false; + } + runningRequest.set(true); + return null; + }); + rq.execute((serverURL + "/api/metadata"), "api_key: " + serverKey); + await(); + } + + +// private boolean setTimestamps(Map timestamps){ +// try { +// ByteBuilder bb = new ByteBuilder(); +// String[] filenames = timestamps.keySet().toArray(new String[0]); +// +// for(int i = 0; i < filenames.length; i++){ +// bb.addString(filenames[i]); +// bb.addLong(timestamps.get(filenames[i]).getTime()); +// } +// +// FileEditor.writeFile(timestampsFilename, bb.build()); +// +// uploadFile(new File(baseDir + timestampsFilename)); +// return true; +// } catch (ByteBuilder.buildingException | IOException e) { +// AlertManager.error("Failed Syncing!", e); +// return false; +// } +// } +// +// private Map getTimestamps() { +// try { +// downloadFile(timestampsFilename, new File(baseDir + timestampsFilename)); +// +// byte[] data = FileEditor.readFile(timestampsFilename); +// +// if(data == null || data.length == 0) +// return new HashMap<>(); +// +// BuiltByteParser bbp = new BuiltByteParser(data); +// List pa = bbp.parse(); +// +// Map output = new HashMap<>(); +// for(int i = 0; i < pa.size(); i+=2){ +//// System.out.println((long) pa.get(i).get()); +// output.put( +// (String) pa.get(i).get(), +// new Date((long) pa.get(i+1).get()) +// ); +// } +// return output; +// +// }catch (IOException | BuiltByteParser.byteParsingExeption e){ +// AlertManager.error("Failed Syncing!", e); +// return new HashMap<>(); +// } +// } + void uploadFile(TransferFile tf, String serverURL, String apiKey) { + runningRequest.set(false); + HttpPutFile uploadTask = new HttpPutFile(serverURL + "/api/" + tf.filename, new File(baseDir + tf.filename), new HttpPutFile.UploadCallback() { + @Override + public void onResult(String error) { + if(error != null) + AlertManager.error(error); + runningRequest.set(true); + } + }, new String[]{ + "api_key: " + apiKey, + ("modified: " + tf.updated.getTime()) + }); // Pass auth token if needed + + uploadTask.execute(); + await(); + } + + + private void setLocalFileTimestamp(File file, Date date) { + file.setLastModified(date.getTime()); + } + void downloadFile(TransferFile tf, String serverURL) { + runningRequest.set(false); + File f = new File(baseDir + tf.filename); + HttpGetFile uploadTask = new HttpGetFile(serverURL + "/api/" + tf.filename, f, new HttpGetFile.DownloadCallback() { + @Override + public void onResult(String error) { + if(error != null) + AlertManager.error(error); + else + setLocalFileTimestamp(f, tf.updated); + runningRequest.set(true); + + } + }); // Pass auth token if needed + + uploadTask.execute(); + await(); + } +} diff --git a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/TransferFragment.java b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/TransferFragment.java index d44413c..10a062b 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/TransferFragment.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/ui/transfer/TransferFragment.java @@ -65,13 +65,13 @@ public class TransferFragment extends Fragment { binding.SyncButton.setOnClickListener(v -> { binding.SyncButton.setEnabled(false); - FTPSync.sync(); + HttpSync.sync(); }); - if(FTPSync.getIsRunning()) + if(HttpSync.getIsRunning()) binding.SyncButton.setEnabled(false); - FTPSync.setOnResult((error, upcount, downcount) -> { + HttpSync.setOnResult((error, upcount, downcount) -> { if (getActivity() != null) getActivity().runOnUiThread(() -> { binding.SyncButton.setEnabled(true); @@ -79,8 +79,8 @@ public class TransferFragment extends Fragment { }); }); - binding.syncIndicator.setText(FTPSync.text); - FTPSync.setOnUpdateIndicator(text -> {if(getActivity() != null) getActivity().runOnUiThread(() -> binding.syncIndicator.setText(text));}); + binding.syncIndicator.setText(HttpSync.text); + HttpSync.setOnUpdateIndicator(text -> {if(getActivity() != null) getActivity().runOnUiThread(() -> binding.syncIndicator.setText(text));}); if(evcode.equals("unset")){ binding.noEventError.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/HttpGetFile.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/HttpGetFile.java new file mode 100644 index 0000000..bbc8b66 --- /dev/null +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/HttpGetFile.java @@ -0,0 +1,168 @@ +package com.ridgebotics.ridgescout.utility; + +import android.os.AsyncTask; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; + +public class HttpGetFile extends AsyncTask { + + public interface DownloadCallback { + void onResult(String error); + } + + private String downloadUrl; + private File destinationFile; + private DownloadCallback callback; + private String errorMessage; + public HttpGetFile(String downloadUrl, File destinationFile, DownloadCallback callback) { + this.downloadUrl = downloadUrl; + this.destinationFile = destinationFile; + this.callback = callback; + } + + @Override + protected File doInBackground(Void... voids) { + HttpURLConnection connection = null; + InputStream inputStream = null; + FileOutputStream outputStream = null; + + try { + URL url = new URL(downloadUrl); + connection = (HttpURLConnection) url.openConnection(); + + // Configure connection for GET request + connection.setRequestMethod("GET"); + connection.setDoInput(true); + connection.setConnectTimeout(30000); // 30 seconds + connection.setReadTimeout(60000); // 60 seconds + + connection.connect(); + + // Check response code + int responseCode = connection.getResponseCode(); + if (responseCode < 200 || responseCode >= 300) { + String errorResponse = readErrorResponse(connection); + errorMessage = "Download failed. Response code: " + responseCode + + (errorResponse != null ? ". Error: " + errorResponse : ""); + return null; + } + + // Get file size for progress tracking + long fileSize = connection.getContentLengthLong(); + if (fileSize == -1) { + fileSize = connection.getContentLength(); // fallback for older API + } + + inputStream = connection.getInputStream(); + + // Create destination file and directories if needed + if (destinationFile.getParentFile() != null && !destinationFile.getParentFile().exists()) { + if (!destinationFile.getParentFile().mkdirs()) { + errorMessage = "Failed to create destination directory: " + destinationFile.getParentFile().getAbsolutePath(); + return null; + } + } + + outputStream = new FileOutputStream(destinationFile); + + byte[] buffer = new byte[8192]; + long downloadedBytes = 0; + int bytesRead; + + while ((bytesRead = inputStream.read(buffer)) != -1) { + if (isCancelled()) { + deletePartialFile(); + return null; + } + + outputStream.write(buffer, 0, bytesRead); + downloadedBytes += bytesRead; + + // Update progress if file size is known + if (fileSize > 0) { + int progress = (int) ((downloadedBytes * 100) / fileSize); + publishProgress(progress); + } + } + + outputStream.flush(); +// Log.d(TAG, "Download successful. File saved to: " + destinationFile.getAbsolutePath()); + return destinationFile; + + } catch (Exception e) { + AlertManager.error(e); + errorMessage = "Download error: " + e.getMessage(); +// Log.e(TAG, errorMessage, e); + deletePartialFile(); + return null; + } finally { + closeResources(inputStream, outputStream, connection); + } + } + + @Override + protected void onPostExecute(File result) { + if (callback != null) { + callback.onResult(errorMessage); + } + } + + @Override + protected void onCancelled() { + deletePartialFile(); + if (callback != null) { + callback.onResult("Download cancelled"); + } + } + + private String readErrorResponse(HttpURLConnection connection) { + try { + InputStream errorStream = connection.getErrorStream(); + if (errorStream != null) { + BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream)); + StringBuilder response = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + response.append(line); + } + reader.close(); + return response.toString(); + } + } catch (IOException e) { + AlertManager.error(e); +// Log.e(TAG, "Error reading error response", e); + } + return null; + } + + private void deletePartialFile() { + if (destinationFile != null && destinationFile.exists()) { + if (destinationFile.delete()) { +// Log.d(TAG, "Partial download file deleted"); + } else { +// Log.w(TAG, "Failed to delete partial download file"); + } + } + } + + private void closeResources(InputStream inputStream, OutputStream outputStream, HttpURLConnection connection) { + try { + if (inputStream != null) inputStream.close(); + } catch (IOException e) { + AlertManager.error(e); +// Log.e(TAG, "Error closing input stream", e); + } + + try { + if (outputStream != null) outputStream.close(); + } catch (IOException e) { + AlertManager.error(e); +// Log.e(TAG, "Error closing output stream", e); + } + + if (connection != null) { + connection.disconnect(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/HttpPutFile.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/HttpPutFile.java new file mode 100644 index 0000000..73b3583 --- /dev/null +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/HttpPutFile.java @@ -0,0 +1,161 @@ +package com.ridgebotics.ridgescout.utility; + +import android.os.AsyncTask; +//import android.util.Log; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; + +public class HttpPutFile extends AsyncTask { + +// private static final String TAG = "FileUploadTask"; + + public interface UploadCallback { + void onResult(String error); + } + + private String uploadUrl; + private File fileToUpload; + private UploadCallback callback; + private String errorMessage; + private String[] headers; + + public HttpPutFile(String uploadUrl, File fileToUpload, UploadCallback callback, String[] headers) { + this.uploadUrl = uploadUrl; + this.fileToUpload = fileToUpload; + this.callback = callback; + this.headers = headers; + } + + @Override + protected Boolean doInBackground(Void... voids) { + HttpURLConnection connection = null; + InputStream fileInputStream = null; + OutputStream outputStream = null; + + try { + if (!fileToUpload.exists()) { + errorMessage = "File does not exist: " + fileToUpload.getAbsolutePath(); + return false; + } + + URL url = new URL(uploadUrl); + connection = (HttpURLConnection) url.openConnection(); + + // Configure connection for PUT request + connection.setRequestMethod("PUT"); + connection.setDoOutput(true); + connection.setDoInput(true); + connection.setUseCaches(false); + connection.setRequestProperty("Content-Type", "application/octet-stream"); + connection.setRequestProperty("Content-Length", String.valueOf(fileToUpload.length())); + connection.setConnectTimeout(30000); // 30 seconds + connection.setReadTimeout(60000); // 60 seconds + + for(int i = 0; i < headers.length; i++){ + String[] split = headers[i].split(": "); + connection.setRequestProperty(split[0], split[1]); + } + connection.connect(); + + outputStream = connection.getOutputStream(); + fileInputStream = new FileInputStream(fileToUpload); + + byte[] buffer = new byte[8192]; + long totalBytes = fileToUpload.length(); + long uploadedBytes = 0; + int bytesRead; + + while ((bytesRead = fileInputStream.read(buffer)) != -1) { + if (isCancelled()) { + return false; + } + + outputStream.write(buffer, 0, bytesRead); + uploadedBytes += bytesRead; + + // Update progress + int progress = (int) ((uploadedBytes * 100) / totalBytes); + publishProgress(progress); + } + + outputStream.flush(); + + // Check response code + int responseCode = connection.getResponseCode(); + if (responseCode >= 200 && responseCode < 300) { +// Log.d(TAG, "Upload successful. Response code: " + responseCode); + return true; + } else { + // Read error response if available + String errorResponse = readErrorResponse(connection); + errorMessage = "Upload failed. Response code: " + responseCode + + (errorResponse != null ? ". Error: " + errorResponse : ""); + return false; + } + + } catch (Exception e) { + AlertManager.error(e); + errorMessage = "Upload error: " + e.getMessage(); +// Log.e(TAG, errorMessage, e); + return false; + } finally { + closeResources(fileInputStream, outputStream, connection); + } + } + + + @Override + protected void onPostExecute(Boolean success) { + if (callback != null) { + callback.onResult(errorMessage); + } + } + + @Override + protected void onCancelled() { + if (callback != null) { + callback.onResult("Upload cancelled"); + } + } + + private String readErrorResponse(HttpURLConnection connection) { + try { + InputStream errorStream = connection.getErrorStream(); + if (errorStream != null) { + BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream)); + StringBuilder response = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + response.append(line); + } + reader.close(); + return response.toString(); + } + } catch (IOException e) { + AlertManager.error(e); +// Log.e(TAG, "Error reading error response", e); + } + return null; + } + + private void closeResources(InputStream inputStream, OutputStream outputStream, HttpURLConnection connection) { + try { + if (inputStream != null) inputStream.close(); + } catch (IOException e) { + AlertManager.error(e); +// Log.e(TAG, "Error closing input stream", e); + } + + try { + if (outputStream != null) outputStream.close(); + } catch (IOException e) { + AlertManager.error(e); +// Log.e(TAG, "Error closing output stream", e); + } + + if (connection != null) { + connection.disconnect(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ridgebotics/ridgescout/utility/SettingsManager.java b/app/src/main/java/com/ridgebotics/ridgescout/utility/SettingsManager.java index dd13829..897d12d 100644 --- a/app/src/main/java/com/ridgebotics/ridgescout/utility/SettingsManager.java +++ b/app/src/main/java/com/ridgebotics/ridgescout/utility/SettingsManager.java @@ -28,6 +28,7 @@ public class SettingsManager { public static final String BtUUIDKey = "bt_uuid"; public static final String FTPEnabled = "ftp_enabled"; public static final String FTPServer = "ftp_server"; + public static final String FTPKey = "ftp_key"; public static final String FTPSendMetaFiles = "ftp_send_meta_files"; public static final String EnableQuickAllianceChangeKey = "enable_quick_alliance_change"; @@ -53,7 +54,8 @@ public class SettingsManager { hm.put(TeamsDataModeKey, 0); hm.put(BtUUIDKey, UUID.randomUUID().toString()); hm.put(FTPEnabled, false); - hm.put(FTPServer, "0.0.0.0"); + hm.put(FTPServer, "http://127.0.0.1:8080"); + hm.put(FTPKey, "5uper_5ecure_k3y"); hm.put(FTPSendMetaFiles, false); hm.put(EnableQuickAllianceChangeKey, false); hm.put(CustomEventsKey, false); @@ -131,6 +133,9 @@ public class SettingsManager { public static String getFTPServer(){return prefs.getString( FTPServer, (String) defaults.get(FTPServer));} public static void setFTPServer(String str){ getEditor().putString( FTPServer,str).apply();} + public static String getFTPKey(){return prefs.getString( FTPKey, (String) defaults.get(FTPKey));} + public static void setFTPKey(String str){ getEditor().putString( FTPKey,str).apply();} + public static boolean getFTPSendMetaFiles(){return prefs.getBoolean(FTPSendMetaFiles, (boolean) defaults.get(FTPSendMetaFiles));} public static void setFTPSendMetaFiles(boolean bool){getEditor().putBoolean(FTPSendMetaFiles,bool).apply();} diff --git a/server/main.py b/server/main.py index 457abd5..012c88f 100644 --- a/server/main.py +++ b/server/main.py @@ -76,7 +76,7 @@ def upload(filename): try: sentkey = request.headers[API_KEY_HEADER] if sentkey != api_key: - return HTTPResponse(status=403, body=f"Invalid Key {sentkey}, {api_key}") + return HTTPResponse(status=403, body=f"Invalid Key") except: return HTTPResponse(status=403, body="You must specify an 'api_key' header") @@ -124,4 +124,4 @@ def download(filename): if __name__ == '__main__': mkdir(DATA_ROOT) aquire_key() - app.run(host='localhost', port=8080) + app.run(host='0.0.0.0', port=8080) diff --git a/server/utils.py b/server/utils.py index 48114b7..a1e6c5e 100644 --- a/server/utils.py +++ b/server/utils.py @@ -1,7 +1,7 @@ import os ROOT = os.path.dirname(__file__) -DATA_ROOT = os.path.join(os.path.dirname(__file__), 'data') +DATA_ROOT = os.path.join(os.path.dirname(__file__), 'server_data') METADATA_PATH4 = os.path.join(ROOT, 'metadata.json') API_KEY_PATH = os.path.join(ROOT, 'api_key.txt')