mirror of
https://github.com/Team4388/RidgeScout.git
synced 2026-06-09 00:37:59 -06:00
Add FTP server
This commit is contained in:
@@ -25,6 +25,7 @@ import com.ridgebotics.ridgescout.utility.settingsManager;
|
||||
import com.google.android.material.navigation.NavigationBarView;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
@@ -51,6 +52,9 @@ public class MainActivity extends AppCompatActivity {
|
||||
fields.save(fields.pitsFieldsFilename, fields.default_pit_fields);
|
||||
}
|
||||
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
|
||||
|
||||
AlertManager.init(this);
|
||||
SentimentAnalysis.init(this);
|
||||
|
||||
|
||||
@@ -1,166 +1,163 @@
|
||||
package com.ridgebotics.ridgescout.ui.transfer;
|
||||
|
||||
import static com.ridgebotics.ridgescout.utility.DataManager.evcode;
|
||||
//import static com.ridgebotics.ridgescout.utility.DataManager.evcode;
|
||||
import static com.ridgebotics.ridgescout.utility.fileEditor.baseDir;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.DataManager;
|
||||
import com.ridgebotics.ridgescout.utility.fileEditor;
|
||||
import com.ridgebotics.ridgescout.utility.settingsManager;
|
||||
|
||||
import org.apache.commons.net.ftp.FTP;
|
||||
import org.apache.commons.net.ftp.FTPClient;
|
||||
import org.apache.commons.net.ftp.FTPCmd;
|
||||
import org.apache.commons.net.ftp.FTPFile;
|
||||
import org.checkerframework.checker.units.qual.C;
|
||||
import org.apache.commons.net.ftp.FTPReply;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class FTPSync extends Thread {
|
||||
private static final String remoteBasePath = "/RidgeScout/";
|
||||
public static final String remoteBasePath = "/RidgeScout/";
|
||||
public static final long timeTolerance = 60000; // One min
|
||||
public static long lastSyncTime = 0;
|
||||
|
||||
public interface onResult {
|
||||
void onResult(boolean error);
|
||||
void onResult(boolean error, int upCount, int downCount);
|
||||
}
|
||||
|
||||
public onResult onResult;
|
||||
|
||||
public static void sync(onResult onResult){
|
||||
DataManager.reload_event();
|
||||
// DataManager.reload_event();
|
||||
FTPSync ftpSync = new FTPSync();
|
||||
ftpSync.onResult = onResult;
|
||||
ftpSync.start();
|
||||
|
||||
lastSyncTime = new Date().getTime();
|
||||
}
|
||||
|
||||
private class FileDate {
|
||||
public String filename;
|
||||
public Calendar lastModified;
|
||||
FTPClient ftpClient;
|
||||
|
||||
// private class FileDate {
|
||||
// public String filename;
|
||||
// public Calendar lastModified;
|
||||
// }
|
||||
|
||||
private int upCount = 0;
|
||||
private int downCount = 0;
|
||||
|
||||
private void downloadFile(FTPFile remoteFile, File localFile) throws IOException {
|
||||
try (FileOutputStream fos = new FileOutputStream(localFile)) {
|
||||
ftpClient.retrieveFile(remoteBasePath + remoteFile.getName(), fos);
|
||||
}
|
||||
Date d = getUtcTimestamp(remoteFile);
|
||||
System.out.println(d);
|
||||
setLocalFileTimestamp(localFile, d);
|
||||
}
|
||||
|
||||
public boolean sendFile(FTPClient ftpClient, String filename) throws Exception{
|
||||
FileInputStream fin = new FileInputStream(baseDir + filename);
|
||||
boolean worked = ftpClient.storeFile(remoteBasePath + filename, fin);
|
||||
fin.close();
|
||||
return worked;
|
||||
private void uploadFile(File localFile) throws IOException {
|
||||
try (FileInputStream fis = new FileInputStream(localFile)) {
|
||||
ftpClient.storeFile(remoteBasePath + localFile.getName(), fis);
|
||||
}
|
||||
setLocalFileTimestamp(localFile, new Date());
|
||||
}
|
||||
|
||||
private FTPFile findRemoteFile(FTPFile[] remoteFiles, String fileName) {
|
||||
for (FTPFile file : remoteFiles) {
|
||||
if (file.getName().equals(fileName)) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Date getUtcTimestamp(FTPFile file) {
|
||||
return file.getTimestamp().getTime();
|
||||
}
|
||||
|
||||
private Date getLocalFileUtcTimestamp(File file) {
|
||||
return new Date(file.lastModified());
|
||||
}
|
||||
|
||||
private void setLocalFileTimestamp(File file, Date date) {
|
||||
file.setLastModified(date.getTime());
|
||||
}
|
||||
|
||||
// private long longAbs(long n){
|
||||
// return n>0 ? n : -n;
|
||||
// }
|
||||
|
||||
private boolean toleranceCompareAfter(Date d1, Date d2){
|
||||
long diff = d1.getTime() - d2.getTime();
|
||||
System.out.println(diff);
|
||||
return diff > timeTolerance;
|
||||
}
|
||||
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
FTPClient ftpClient = new FTPClient();
|
||||
// localTimeZone = TimeZone.getDefault();
|
||||
ftpClient = new FTPClient();
|
||||
InetAddress address = InetAddress.getByName(settingsManager.getFTPServer());
|
||||
ftpClient.connect(address);
|
||||
ftpClient.login("anonymous", null);
|
||||
ftpClient.enterLocalPassiveMode();
|
||||
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
|
||||
// ftpClient.setFileTransferMode(FTP.BLOCK_TRANSFER_MODE)
|
||||
|
||||
FTPFile[] remoteFilestmp = ftpClient.listFiles(remoteBasePath);
|
||||
String[] localFilestmp = fileEditor.getEventFiles(evcode);
|
||||
File localDir = new File(baseDir);
|
||||
File[] localFiles = localDir.listFiles();
|
||||
FTPFile[] remoteFiles = ftpClient.listFiles(remoteBasePath);
|
||||
|
||||
FileDate[] remoteFiles = new FileDate[remoteFilestmp.length];
|
||||
for(int i = 0; i < remoteFilestmp.length; i++){
|
||||
// System.out.println(remoteFilestmp[i].getName());
|
||||
remoteFiles[i] = new FileDate();
|
||||
remoteFiles[i].filename = remoteFilestmp[i].getName();
|
||||
System.out.println(remoteFiles[i].filename);
|
||||
remoteFiles[i].lastModified = remoteFilestmp[i].getTimestamp();
|
||||
}
|
||||
if (localFiles != null) {
|
||||
for (File localFile : localFiles) {
|
||||
if (localFile.isFile()) {
|
||||
FTPFile remoteFile = findRemoteFile(remoteFiles, localFile.getName());
|
||||
//
|
||||
// Date t1 = getLocalFileUtcTimestamp(localFile);
|
||||
// Date t2 = getUtcTimestamp(remoteFile);
|
||||
////
|
||||
// System.out.println("- " + t1.getTime() + (t1.after(t2) ? ">" : "<") + t2.getTime());
|
||||
|
||||
FileDate[] localFiles = new FileDate[localFilestmp.length];
|
||||
for(int i = 0; i < localFilestmp.length; i++){
|
||||
// sendFile(localFilestmp[i]);
|
||||
String filename = "matches.fields";
|
||||
File f = new File(baseDir + filename);
|
||||
// File f = new File(baseDir + localFilestmp[i]);
|
||||
// System.out.println(f.exists());
|
||||
// FileInputStream fin = new FileInputStream(f);
|
||||
// System.out.println(f.getName() + ", " + f.exists() + ", " + sendFile(ftpClient, f));
|
||||
// fin.close();
|
||||
|
||||
// System.out.println(ftpClient.getStatus());
|
||||
|
||||
|
||||
localFiles[i] = new FileDate();
|
||||
localFiles[i].filename = localFilestmp[i];
|
||||
localFiles[i].lastModified = fileEditor.getLastModified(localFilestmp[i]);
|
||||
}
|
||||
|
||||
FileAction[] localActions = compareDates(localFiles, fd2map(remoteFiles), false);
|
||||
System.out.println(localActions.length);
|
||||
for(int i = 0 ; i < localActions.length; i++){
|
||||
|
||||
System.out.println(localActions[i].filename + ", " + localActions[i].action);
|
||||
switch (localActions[i].action){
|
||||
case SEND:
|
||||
sendFile(ftpClient, localActions[i].filename);
|
||||
fileEditor.setLastModified(localActions[i].filename, localActions[i].otherTimestamp);
|
||||
break;
|
||||
case RECIEVE:
|
||||
|
||||
break;
|
||||
if (remoteFile == null || toleranceCompareAfter(getLocalFileUtcTimestamp(localFile), (getUtcTimestamp(remoteFile)))) {
|
||||
uploadFile(localFile);
|
||||
System.out.println("Uploaded " + localFile.getName());
|
||||
upCount++;
|
||||
}else{
|
||||
System.out.println("Did not upload " + localFile.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (FTPFile remoteFile : remoteFiles) {
|
||||
if (!remoteFile.isDirectory()) {
|
||||
File localFile = new File(baseDir, remoteFile.getName());
|
||||
|
||||
// Date t1 = getLocalFileUtcTimestamp(localFile);
|
||||
// Date t2 = getUtcTimestamp(remoteFile);
|
||||
////
|
||||
// System.out.println("- " + t1 + (t1.after(t2) ? ">" : "<") + t2);
|
||||
|
||||
if (!localFile.exists() || toleranceCompareAfter(getUtcTimestamp(remoteFile), (getLocalFileUtcTimestamp(localFile)))) {
|
||||
downloadFile(remoteFile, localFile);
|
||||
System.out.println("Downloaded " + localFile.getName());
|
||||
downCount++;
|
||||
}else{
|
||||
System.out.println("Did not download " + remoteFile.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
AlertManager.error(e);
|
||||
onResult.onResult(true);
|
||||
AlertManager.toast("Error Syncing!");
|
||||
onResult.onResult(true, upCount, downCount);
|
||||
} finally {
|
||||
onResult.onResult(false, upCount, downCount);
|
||||
}
|
||||
// } finally {
|
||||
// AlertManager.toast("Synced!");
|
||||
// onResult.onResult(false);
|
||||
// }
|
||||
}
|
||||
|
||||
private Map<String, Calendar> fd2map(FileDate[] fdarr){
|
||||
Map<String, Calendar> map = new HashMap<>();
|
||||
for(int i = 0; i < fdarr.length; i++)
|
||||
map.put(fdarr[i].filename, fdarr[i].lastModified);
|
||||
return map;
|
||||
}
|
||||
|
||||
private enum SyncAction {
|
||||
SEND,
|
||||
RECIEVE,
|
||||
NONE
|
||||
}
|
||||
|
||||
private class FileAction {
|
||||
String filename;
|
||||
SyncAction action;
|
||||
Calendar otherTimestamp;
|
||||
public FileAction(String filename, SyncAction action, Calendar otherTimestamp){
|
||||
this.filename = filename;
|
||||
this.action = action;
|
||||
this.otherTimestamp = otherTimestamp;
|
||||
}
|
||||
}
|
||||
|
||||
private FileAction[] compareDates(FileDate[] files, Map<String, Calendar> refrence, boolean reverse){
|
||||
FileAction[] actions = new FileAction[files.length];
|
||||
for(int i = 0; i < files.length; i++){
|
||||
Calendar ref = refrence.get(files[i].filename);
|
||||
|
||||
System.out.println(ref);
|
||||
|
||||
if(ref == null || files[i].lastModified.after(ref)) {
|
||||
actions[i] = new FileAction(files[i].filename, !reverse ? SyncAction.SEND : SyncAction.RECIEVE, ref);
|
||||
}else if(files[i].lastModified.before(ref)){
|
||||
actions[i] = new FileAction(files[i].filename, !reverse ? SyncAction.RECIEVE : SyncAction.SEND, ref);
|
||||
}else {
|
||||
actions[i] = new FileAction(files[i].filename, SyncAction.NONE, ref);
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,14 @@ import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.ridgebotics.ridgescout.R;
|
||||
import com.ridgebotics.ridgescout.utility.AlertManager;
|
||||
import com.ridgebotics.ridgescout.utility.settingsManager;
|
||||
import com.ridgebotics.ridgescout.databinding.FragmentTransferBinding;
|
||||
import com.ridgebotics.ridgescout.ui.transfer.bluetooth.BluetoothSenderFragment;
|
||||
import com.ridgebotics.ridgescout.ui.transfer.codes.CodeGeneratorView;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class TransferFragment extends Fragment {
|
||||
private FragmentTransferBinding binding;
|
||||
|
||||
@@ -66,12 +69,31 @@ public class TransferFragment extends Fragment {
|
||||
alert.create().show();
|
||||
});
|
||||
|
||||
|
||||
if(!settingsManager.getWifiMode()) {
|
||||
binding.TBAButton.setEnabled(false);
|
||||
binding.SyncButton.setEnabled(false);
|
||||
}
|
||||
|
||||
if(!settingsManager.getFTPEnabled() ||
|
||||
new Date().getTime()-FTPSync.lastSyncTime < FTPSync.timeTolerance) {
|
||||
binding.SyncButton.setEnabled(false);
|
||||
}
|
||||
|
||||
binding.SyncButton.setOnClickListener(v -> {
|
||||
binding.SyncButton.setEnabled(false);
|
||||
FTPSync.sync((error, upcount, downcount) -> getActivity().runOnUiThread(() -> {
|
||||
// binding.SyncButton.setEnabled(true);
|
||||
AlertManager.toast((!error ? "Synced! " : "Error Syncing. ") + upcount + " Up " + downcount + " Down");
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
if(evcode.equals("unset")){
|
||||
binding.noEventError.setVisibility(View.VISIBLE);
|
||||
binding.uploadButton.setEnabled(false);
|
||||
binding.CSVButton.setEnabled(false);
|
||||
binding.downloadButton.setEnabled(true);
|
||||
binding.SyncButton.setEnabled(false);
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@@ -107,20 +129,6 @@ public class TransferFragment extends Fragment {
|
||||
builder.show();
|
||||
});
|
||||
|
||||
if(!settingsManager.getWifiMode()) {
|
||||
binding.TBAButton.setEnabled(false);
|
||||
binding.SyncButton.setEnabled(false);
|
||||
}
|
||||
|
||||
if(!settingsManager.getFTPEnabled()) {
|
||||
binding.SyncButton.setEnabled(false);
|
||||
}
|
||||
|
||||
binding.SyncButton.setOnClickListener(v -> {
|
||||
binding.SyncButton.setEnabled(false);
|
||||
FTPSync.sync(error -> getActivity().runOnUiThread(() -> binding.SyncButton.setEnabled(true)));
|
||||
});
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@ package com.ridgebotics.ridgescout.ui.transfer.codes;
|
||||
|
||||
import static androidx.core.math.MathUtils.clamp;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.media.Image;
|
||||
import android.os.Bundle;
|
||||
@@ -25,6 +27,7 @@ import androidx.camera.core.ImageProxy;
|
||||
import androidx.camera.core.Preview;
|
||||
import androidx.camera.lifecycle.ProcessCameraProvider;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
@@ -150,6 +153,9 @@ public class CodeScannerView extends Fragment {
|
||||
|
||||
this.lifecycle = getViewLifecycleOwner();
|
||||
|
||||
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.CAMERA}, 1);
|
||||
}
|
||||
|
||||
|
||||
uiHandler = new Handler();
|
||||
|
||||
@@ -15,6 +15,8 @@ import java.io.IOException;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
@@ -22,6 +24,7 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
import java.util.zip.DataFormatException;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.Inflater;
|
||||
@@ -30,6 +33,7 @@ public final class fileEditor {
|
||||
public final static String baseDir = "/data/data/com.ridgebotics.ridgescout/";
|
||||
public static final byte internalDataVersion = 0x01;
|
||||
public static final int maxCompressedBlockSize = 4096;
|
||||
// private TimeZone localTimeZone = TimeZone.getDefault();
|
||||
|
||||
|
||||
|
||||
@@ -190,22 +194,22 @@ public final class fileEditor {
|
||||
|
||||
|
||||
|
||||
public static Calendar getLastModified(String filepath){
|
||||
File f = new File(baseDir + filepath);
|
||||
if(f.exists()){
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(f.lastModified());
|
||||
return calendar;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void setLastModified(String filepath, Calendar calendar){
|
||||
File f = new File(baseDir + filepath);
|
||||
if(f.exists()){
|
||||
f.setLastModified(calendar.getTimeInMillis());
|
||||
}
|
||||
}
|
||||
// public static Calendar getLastModified(String filepath){
|
||||
// File f = new File(baseDir + filepath);
|
||||
// if(f.exists()){
|
||||
// Calendar calendar = Calendar.getInstance();
|
||||
// calendar.setTimeInMillis(f.lastModified());
|
||||
// return calendar;
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// public static void setLastModified(String filepath, Calendar calendar){
|
||||
// File f = new File(baseDir + filepath);
|
||||
// if(f.exists()){
|
||||
// f.setLastModified(calendar.getTimeInMillis());
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
@@ -214,6 +218,10 @@ public final class fileEditor {
|
||||
FileOutputStream output = new FileOutputStream(baseDir + filepath);
|
||||
output.write(data);
|
||||
output.close();
|
||||
|
||||
// Date d = new Date();
|
||||
|
||||
new File(baseDir + filepath).setLastModified(new Date().getTime());
|
||||
return true;
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
||||
Reference in New Issue
Block a user