diff --git a/README.md b/README.md index e39e680b..96cf240d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -dexcom-uploader +android-uploader ==================== A community maintained fork of original android uploader. diff --git a/src/com/nightscout/android/upload/UploadHelper.java b/src/com/nightscout/android/upload/UploadHelper.java index 5490bbcb..50382011 100644 --- a/src/com/nightscout/android/upload/UploadHelper.java +++ b/src/com/nightscout/android/upload/UploadHelper.java @@ -20,7 +20,9 @@ import org.json.JSONObject; +import java.security.MessageDigest; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; public class UploadHelper extends AsyncTask { @@ -45,11 +47,17 @@ protected Long doInBackground(EGVRecord... records) { Boolean enableMongoUpload = prefs.getBoolean("EnableMongoUpload", false); if (enableRESTUpload) { + long start = System.currentTimeMillis(); + Log.i(TAG, String.format("Starting upload of %s record using a REST API", records.length)); doRESTUpload(prefs, records); + Log.i(TAG, String.format("Finished upload of %s record using a REST API in %s ms", records.length, System.currentTimeMillis() - start)); } if (enableMongoUpload) { + long start = System.currentTimeMillis(); + Log.i(TAG, String.format("Starting upload of %s record using a Mongo", records.length)); doMongoUpload(prefs, records); + Log.i(TAG, String.format("Finished upload of %s record using a Mongo in %s ms", records.length, System.currentTimeMillis() - start)); } return 1L; @@ -62,9 +70,50 @@ protected void onPostExecute(Long result) { } private void doRESTUpload(SharedPreferences prefs, EGVRecord... records) { + String baseURLSettings = prefs.getString("API Base URL", ""); + ArrayList baseURIs = new ArrayList(); + try { - String baseURL = prefs.getString("API Base URL", ""); - String postURL = baseURL + (baseURL.endsWith("/") ? "" : "/") + "entries"; + for (String baseURLSetting : baseURLSettings.split(" ")) { + String baseURL = baseURLSetting.trim(); + if (baseURL.isEmpty()) continue; + baseURIs.add(baseURL + (baseURL.endsWith("/") ? "" : "/")); + } + } catch (Exception e) { + Log.e(TAG, "Unable to process API Base URL setting: " + baseURLSettings, e); + return; + } + + for (String baseURI : baseURIs) { + try { + doRESTUploadTo(baseURI, records); + } catch (Exception e) { + Log.e(TAG, "Unable to do REST API Upload to: " + baseURI, e); + } + } + } + + private void doRESTUploadTo(String baseURI, EGVRecord[] records) { + try { + int apiVersion = 0; + if (baseURI.endsWith("/v1/")) apiVersion = 1; + + String baseURL = null; + String secret = null; + String[] uriParts = baseURI.split("@"); + + if (uriParts.length == 1 && apiVersion == 0) { + baseURL = uriParts[0]; + } else if (uriParts.length == 1 && apiVersion > 0) { + throw new Exception("Starting with API v1, a pass phase is required"); + } else if (uriParts.length == 2 && apiVersion > 0) { + secret = uriParts[0]; + baseURL = uriParts[1]; + } else { + throw new Exception(String.format("Unexpected baseURI: %s, uriParts.length: %s, apiVersion: %s", baseURI, uriParts.length, apiVersion)); + } + + String postURL = baseURL + "entries"; Log.i(TAG, "postURL: " + postURL); HttpParams params = new BasicHttpParams(); @@ -75,13 +124,35 @@ private void doRESTUpload(SharedPreferences prefs, EGVRecord... records) { HttpPost post = new HttpPost(postURL); + if (apiVersion > 0) { + if (secret == null || secret.isEmpty()) { + throw new Exception("Starting with API v1, a pass phase is required"); + } else { + MessageDigest digest = MessageDigest.getInstance("SHA-1"); + byte[] bytes = secret.getBytes("UTF-8"); + digest.update(bytes, 0, bytes.length); + bytes = digest.digest(); + StringBuilder sb = new StringBuilder(bytes.length * 2); + for (byte b: bytes) { + sb.append(String.format("%02x", b & 0xff)); + } + String token = sb.toString(); + post.setHeader("api-secret", token); + } + } + for (EGVRecord record : records) { - Date date = DATE_FORMAT.parse(record.displayTime); JSONObject json = new JSONObject(); - json.put("device", "dexcom"); - json.put("timestamp", date.getTime()); - json.put("bg", Integer.parseInt(record.bGValue)); - json.put("direction", record.trend); + + try { + if (apiVersion >= 1) + populateV1APIEntry(json, record); + else + populateLegacyAPIEntry(json, record); + } catch (Exception e) { + Log.w(TAG, "Unable to populate entry, apiVersion: " + apiVersion, e); + continue; + } String jsonString = json.toString(); @@ -104,6 +175,22 @@ private void doRESTUpload(SharedPreferences prefs, EGVRecord... records) { } } + private void populateV1APIEntry(JSONObject json, EGVRecord record) throws Exception { + Date date = DATE_FORMAT.parse(record.displayTime); + json.put("device", "dexcom"); + json.put("date", date.getTime()); + json.put("sgv", Integer.parseInt(record.bGValue)); + json.put("direction", record.trend); + } + + private void populateLegacyAPIEntry(JSONObject json, EGVRecord record) throws Exception { + Date date = DATE_FORMAT.parse(record.displayTime); + json.put("device", "dexcom"); + json.put("timestamp", date.getTime()); + json.put("bg", Integer.parseInt(record.bGValue)); + json.put("direction", record.trend); + } + private void doMongoUpload(SharedPreferences prefs, EGVRecord... records) { String dbURI = prefs.getString("MongoDB URI", null); @@ -113,14 +200,14 @@ private void doMongoUpload(SharedPreferences prefs, EGVRecord... records) { try { // connect to db - MongoClientURI uri = new MongoClientURI(dbURI); + MongoClientURI uri = new MongoClientURI(dbURI.trim()); MongoClient client = new MongoClient(uri); // get db DB db = client.getDB(uri.getDatabase()); // get collection - DBCollection dexcomData = db.getCollection(collectionName); + DBCollection dexcomData = db.getCollection(collectionName.trim()); Log.i(TAG, "The number of EGV records being sent to MongoDB is " + records.length); for (EGVRecord record : records) { // make db object