// Copyright 2012 (C) Matthew Brejza
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
package ukhas;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Queue;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.commons.codec.binary.Base64;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;
import net.sf.json.*;
import com.fourspaces.couchdb.CouchResponse;
import com.fourspaces.couchdb.Database;
import com.fourspaces.couchdb.Document;
import com.fourspaces.couchdb.Session;
import com.fourspaces.couchdb.View;
import com.fourspaces.couchdb.ViewResults;
public class Habitat_interface {
private String _habitat_url = "habitat.habhub.org";
private String _habitat_db = "habitat";
private Listener _listener_info;
private String _listener_telem_UUID="";
private String _listener_info_UUID="";
protected ArrayList<HabitatRxEvent> _listeners = new ArrayList<HabitatRxEvent>();
public ConcurrentHashMap<String,String> payload_configs = new ConcurrentHashMap<String,String>();
public ConcurrentHashMap<String,String> flight_configs = new ConcurrentHashMap<String,String>();
private ConcurrentHashMap<String,TelemetryConfig> telem_configs = new ConcurrentHashMap<String,TelemetryConfig>();
private boolean _newTelemConfigs = false;
private Session s;
private Database db;
private Thread sdThread;
public String device = "device";//"XOOM";
public String device_software = "";//"4.0.x";
public String application = "HAB Modem";
public String application_version = "pre-alpha";
private int _prev_query_time = 5 * 60 * 60;
private boolean _queried_current_flights = false;
//TODO: if failed due to connection error, identify error and dont clear the list.
private Queue<Telemetry_string> out_buff = new LinkedBlockingQueue<Telemetry_string>();
private Queue<QueueItem> _operations = new LinkedBlockingQueue<QueueItem>();
public Habitat_interface(String callsign) {
_listener_info = new Listener(callsign,false);
}
public Habitat_interface(String habitat_url, String habitat_db, Listener listener_info) {
_habitat_url = habitat_url;
_habitat_db = habitat_db;
_listener_info = listener_info;
}
public Habitat_interface(String habitat_url, String habitat_db) {
_habitat_url = habitat_url;
_habitat_db = habitat_db;
}
public void Test()
{
s = new Session(_habitat_url,80);
db = s.getDatabase(_habitat_db);
List<Document> foodoc;
View v = new View("payload_configuration/callsign_time_created_index");
//View v = new View("payload_configuration/callsign_time_created_index&startkey%3D[%22APEX%22]");
// v.setKey("startkey=APEX");
v.setStartKey("[%22APEX%22]");
v.setLimit(1);
//foodoc = db.view("flight/end_start_including_payloads").getResults();
foodoc = db.view(v).getResults();
foodoc.toString();
}
public void addHabitatRecievedListener(HabitatRxEvent listener)
{
_listeners.add(listener);
}
public void addDataFetchTask(String callsign, long startTime, long stopTime, int limit)
{
_operations.offer(new QueueItem(1,callsign, startTime, stopTime, limit));
StartThread();
}
public void updateChaseCar(Listener newlocation)
{
_listener_info = newlocation;
_operations.offer(new QueueItem(3,0));
StartThread();
}
public void updateListener(Listener newlistener)
{
_listener_info = newlistener;
}
public void addGetActiveFlightsTask()
{
_operations.offer(new QueueItem(2,0));
StartThread();
}
private String resolvePayloadID(String callsign)
{
String c = callsign.toUpperCase();
if (payload_configs.containsKey(c))
return payload_configs.get(c);
else if (!_queried_current_flights)
_queried_current_flights = queryActiveFlights();
if (payload_configs.containsKey(c))
return payload_configs.get(c);
else
{
queryAllPayloadDocs(c);
if (payload_configs.containsKey(c))
return payload_configs.get(c);
else
return null; //TODO: add list of non payloads
}
}
public boolean queryAllPayloadDocs(String callsign)
{
String docid = null;
try
{
//open DB connection
if (s == null)
{
s = new Session(_habitat_url,80);
db = s.getDatabase(_habitat_db);// + "/_design/payload_telemetry/_update/add_listener");
}
else if (db == null)
db = s.getDatabase(_habitat_db);
List<Document> docsout;
View v = new View("payload_configuration/callsign_time_created_index");
//startkey=["CRAAG1",1357396479]&endkey=["CRAAG1",0]&descending=true
v.setStartKey("[%22" + callsign.toUpperCase() + "%22," + Long.toString((System.currentTimeMillis() / 1000L)) + "]");
v.setEndKey("[%22" + callsign.toLowerCase() + "%22,0]");
//v.setWithDocs(true);
v.setLimit(1);
v.setDescending(true);
ViewResults r = db.view(v);
docsout = r.getResults();
//docsout.toString();
//docsout.get(0).getJSONObject().getJSONObject("doc").getString("type")
//docsout.get(1).getJSONObject().getJSONObject("doc").getJSONArray("sentences").getJSONObject(0).getString("callsign")
if (docsout.size() > 0)
{
JSONArray ja = docsout.get(0).getJSONArray("key");
String ss = docsout.get(0).getId();
if (ja.getString(0).equals(callsign))
docid = ss;
}
}
catch (Exception e)
{
System.out.println("ERROR: "+ e.toString());
return false;
}
if (docid != null)
payload_configs.put(callsign.toUpperCase(),docid);
return true;
}
private boolean queryPayloadConfig(String docID)
{
try
{
//open DB connection
if (s == null)
{
s = new Session(_habitat_url,80);
db = s.getDatabase(_habitat_db);// + "/_design/payload_telemetry/_update/add_listener");
}
else if (db == null)
db = s.getDatabase(_habitat_db);
Document doc = db.getDocument(docID);
if (doc == null)
return false;
CouchResponse cr = s.getLastResponse();
if (!cr.isOk())
return false;
JSONObject obj;
JSONArray sentences;
JSONArray fields;
JSONArray filters;
TelemetryConfig tc = new TelemetryConfig();
obj = doc.getJSONObject();
if (obj.containsKey("sentences")){
sentences = obj.getJSONArray("sentences");
for (int i = 0; i < sentences.size(); i++){
String call = "";
if (sentences.getJSONObject(i).containsKey("callsign")){
call = sentences.getJSONObject(i).getString("callsign");
}
else
return false;
if (sentences.getJSONObject(i).containsKey("fields")){
fields = sentences.getJSONObject(i).getJSONArray("fields");
for (int j = 0; j < fields.size(); j++)
{
String name = fields.getJSONObject(j).getString("name");
String sensor = "";
String format = "";
TelemetryConfig.DataType dt = TelemetryConfig.DataType.IGNORE;
if (fields.getJSONObject(j).containsKey("sensor"))
sensor = fields.getJSONObject(j).getString("sensor");
if (fields.getJSONObject(j).containsKey("format"))
format = fields.getJSONObject(j).getString("format");
if (name.equals("sentence_id")){
}
else if (name.equals("time")){
}
else if (name.equals("latitude" )){
if (sensor.equals("base.ascii_int"))
{
//TODO
tc.gpsFormat = TelemetryConfig.GPSFormat.INT;
}
}
else if (name.equals("longitude" )){
if (sensor.equals("base.ascii_int"))
{
//TODO
tc.gpsFormat = TelemetryConfig.GPSFormat.INT;
}
}
else if (name.equals("altitude" )){
}
else {
if (sensor.equals("base.ascii_int"))
{
dt = TelemetryConfig.DataType.INT;
}
else if (sensor.equals("base.string"))
{
dt = TelemetryConfig.DataType.STRING;
}
else if (sensor.equals("base.ascii_float"))
{
dt = TelemetryConfig.DataType.FLOAT;
}
}
tc.addField(name, dt);
}
if (sentences.getJSONObject(i).containsKey("filters")){
if (sentences.getJSONObject(i).getJSONObject("filters").containsKey("post")){
filters = sentences.getJSONObject(i).getJSONObject("filters").getJSONArray("post");
for (int j = 0; j < filters.size(); j++)
{
String filtertype = "";
String source = "";
String factor = "";
String offset = "";
String round = "";
String type = "";
if (filters.getJSONObject(j).containsKey("filter"))
filtertype = filters.getJSONObject(j).getString("filter");
if (filters.getJSONObject(j).containsKey("source"))
source = filters.getJSONObject(j).getString("source");
if (filters.getJSONObject(j).containsKey("factor"))
factor = filters.getJSONObject(j).getString("factor");
if (filters.getJSONObject(j).containsKey("type"))
type = filters.getJSONObject(j).getString("type");
if (filters.getJSONObject(j).containsKey("offset"))
offset = filters.getJSONObject(j).getString("offset");
if (filters.getJSONObject(j).containsKey("round"))
round = filters.getJSONObject(j).getString("round");
if (filtertype.equals("common.numeric_scale")){
tc.addFilter(source,factor,offset,round);
}
else{
}
}
}
}
}
//save tc to some sort of data structure
telem_configs.put(call.toUpperCase(), tc);
_newTelemConfigs = true;
}
}
}
catch (Exception e)
{
System.out.println("ERROR: "+ e.toString());
return false;
}
return true;
}
private boolean queryActiveFlights()
{
try
{
//open DB connection
if (s == null)
{
s = new Session(_habitat_url,80);
db = s.getDatabase(_habitat_db);// + "/_design/payload_telemetry/_update/add_listener");
}
else if (db == null)
db = s.getDatabase(_habitat_db);
List<Document> docsout;
View v = new View("flight/end_start_including_payloads");
v.setStartKey("[" + Long.toString((System.currentTimeMillis() / 1000L)-(2*60*60)) + "]");
v.setWithDocs(true);
v.setLimit(30);
ViewResults r = db.view(v);
docsout = r.getResults();
//docsout.toString();
//docsout.get(0).getJSONObject().getJSONObject("doc").getString("type")
//docsout.get(1).getJSONObject().getJSONObject("doc").getJSONArray("sentences").getJSONObject(0).getString("callsign")
for (int i = 0; i < docsout.size(); i++)
{
JSONObject obj;
obj = docsout.get(i).getJSONObject().getJSONObject("doc");
if (obj != null) {
if (obj.containsKey("type")) {
if (obj.getString("type").equals("payload_configuration")) {
if (obj.containsKey("sentences")){
JSONArray jar = obj.getJSONArray("sentences");
for (int j = 0; j < jar.size(); j++){
if (jar.getJSONObject(j).containsKey("callsign")){
String call = jar.getJSONObject(j).getString("callsign");
if (!flight_configs.containsKey(call.toUpperCase()))
flight_configs.put(call.toUpperCase(), docsout.get(i).getId());
if (obj.containsKey("_id"))
payload_configs.put(call.toUpperCase(),obj.getString("_id"));
}
}
}
}
}
}
}
return true;
}
catch (Exception e)
{
return false;
}
}
//TODO: if flight doc exists, query that view instead
private boolean getPayloadDataSince(long timestampStart, long timestampStop, int limit, String payloadID, String callsign)
{
double prevAltitude = -99999999;
double maxAltitude = -99999999;
long prevtime = -1;
try
{
//open DB connection
if (s == null)
{
s = new Session(_habitat_url,80);
db = s.getDatabase(_habitat_db);// + "/_design/payload_telemetry/_update/add_listener");
}
else if (db == null)
db = s.getDatabase(_habitat_db);
View v = new View("payload_telemetry/payload_time");
long starttime;
if (timestampStart > 0)
starttime = timestampStart;
else
starttime = (System.currentTimeMillis() / 1000L)-_prev_query_time;
v.setStartKey("[%22" + payloadID + "%22," +Long.toString(starttime) + "]");
v.setEndKey("[%22" + payloadID + "%22," +Long.toString(timestampStop)+ "]");
v.setWithDocs(true);
v.setLimit(limit);
System.out.println("DEBUG: DATABASE GOT QUERY");
TreeMap<Long,Telemetry_string> out = new TreeMap<Long,Telemetry_string>();
JsonFactory fac = new JsonFactory();
InputStream is = db.view_dont_parse(v);
long lasttime = 0;
if (is != null)
{
JsonParser jp = fac.createJsonParser(is);
String str,str1;
boolean gotkey = false;
boolean keypt1 = false;
TelemetryConfig tc = null;
if (telem_configs.containsKey(callsign))
{
tc = telem_configs.get(callsign);
}
while(jp.nextToken() != null )// || (jp.getCurrentLocation().getCharOffset() < body.length()-50)) && nullcount < 20) //100000 > out.size())
{
//jp.nextToken();
str = jp.getCurrentName();
str1 = jp.getText();
if (str == "key" && str1 == "[")
gotkey = true;
else if (gotkey){
keypt1 = true;
gotkey = false;
} else if (keypt1) {
keypt1 = false;
try {
lasttime = Long.parseLong(str1); }
catch (NumberFormatException e) {
System.out.println("ERROR PARSING - NUMBER FORMAT EXCEPTION!!!"); }
}
if (str != null && str1 != null)
{
if (str.equals("_sentence") && !str1.equals("_sentence")){
Telemetry_string ts = new Telemetry_string(str1,lasttime, tc);
if (!ts.isZeroGPS() && ts.time != null) {
if (out.size() > 0){
if (out.lastEntry().getValue().coords.alt_valid) {
prevAltitude = out.lastEntry().getValue().coords.altitude;
prevtime = out.lastEntry().getValue().time.getTime();
}
}
out.put(new Long(ts.time.getTime()),ts);
if (ts.coords.alt_valid)
maxAltitude = Math.max(ts.coords.altitude, maxAltitude);
}
}
//nullcount = 0;
}
//else
// nullcount++;
}
jp.close();
is.close();
}
s.clearCouchResponse();
System.out.println("DEBUG: DATABASE PROCESSING DONE");
AscentRate as = new AscentRate();
if (out.size() >= 2 && prevAltitude > -9999){
as = new AscentRate();
as.addData(prevtime, prevAltitude);
if (out.lastEntry().getValue().coords.alt_valid) {
as.addData(out.lastEntry().getValue().time.getTime(),
out.lastEntry().getValue().coords.altitude);
}
else
as = new AscentRate();
}
lasttime += 1000;
if (lasttime >= timestampStart && lasttime <= timestampStop)
fireDataReceived(out,true,callsign,timestampStart, lasttime,as,maxAltitude);
else
fireDataReceived(out,true,callsign,timestampStart, timestampStop,as,maxAltitude);
return true;
}
catch (Exception e)
{
fireDataReceived(null,false,e.toString(),timestampStart, timestampStop,null,-99999999);
return false;
}
}
public void getActivePayloads()
{
try
{
//open DB connection
if (s == null)
{
s = new Session(_habitat_url,80);
db = s.getDatabase(_habitat_db);// + "/_design/payload_telemetry/_update/add_listener");
}
else if (db == null)
db = s.getDatabase(_habitat_db);
List<Document> foodoc;
View v = new View("payload_telemetry/time");
v.setStartKey(Long.toString((System.currentTimeMillis() / 1000L)-_prev_query_time));
v.setWithDocs(true);
v.setLimit(40);
ViewResults r = db.view(v);
foodoc = r.getResults();
// foodoc = db.view(v).getResults();
foodoc.toString();
//((JSONObject)((JSONObject)foodoc.get(1).getJSONObject().get("doc")).get("data")).get("payload")
}
catch (Exception e)
{
}
}
public void upload_payload_telem(Telemetry_string input)
{
boolean added=false;
added=out_buff.offer(input);
if (added)
{
_operations.offer(new QueueItem(0,1));
StartThread();
}
}
private synchronized void StartThread()
{
if (sdThread == null)
{
sdThread = new SendThread();
sdThread.start();
}
else if (!sdThread.isAlive())
{
sdThread = new SendThread();
sdThread.start();
}
}
private boolean _update_chasecar()
{
try
{
//open DB connection
if (s == null)
{
s = new Session(_habitat_url,80);
db = s.getDatabase(_habitat_db);// + "/_design/payload_telemetry/_update/add_listener");
}
else if (db == null)
db = s.getDatabase(_habitat_db);
if (_listener_info != null)
{
update_listener_telem();
/*
Document doc = new Document ();
Document doc_info = new Document ();
//date uploaded
Date time = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
String t = dateFormat.format(time);
t = t.substring(0, t.length()-2) + ":" + t.substring(t.length()-2, t.length());
doc.put("type", "listener_telemetry");
doc.put("time_created", t);
doc.put("time_uploaded", t);
doc_info.put("type", "listener_information");
doc_info.put("time_created", t);
doc_info.put("time_uploaded", t);
JSONObject client = new JSONObject();
JSONObject l_info = new JSONObject();
client.put("device", device);
client.put("device_software", device_software);
client.put("application", application);
client.put("application_version", application_version);
l_info.put("callsign", _listener_info.CallSign());
JSONObject data = _listener_info.getJSONDataField();
data.put("client", client);
doc.put("data", data);
doc_info.put("data",l_info);
String sha = _listener_info.toSha256();
String sha_info = _listener_info.toSha256();
db.saveDocument(doc,sha);
CouchResponse cr = s.getLastResponse();
System.out.println(cr);
if (cr.isOk())
_listener_telem_UUID = sha;
db.saveDocument(doc_info,sha_info);
cr = s.getLastResponse();
System.out.println(cr);
if (cr.isOk())
_listener_info_UUID = sha_info;
*/
}
return true;
}
catch (Exception e)
{
return false;
}
}
private boolean _upload(Telemetry_string input)
{
try
{
//open DB connection
if (s == null)
{
s = new Session(_habitat_url,80);
db = s.getDatabase(_habitat_db);// + "/_design/payload_telemetry/_update/add_listener");
}
else if (db == null)
db = s.getDatabase(_habitat_db);
if (_listener_info != null)
{
if (_listener_info.data_changed_info())
update_listener_info();
if (_listener_info.data_changed_telem()) //upload listeners location
{
update_listener_telem();
/*
Document doc = new Document ();
//date uploaded
Date time = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
String t = dateFormat.format(time);
t = t.substring(0, t.length()-2) + ":" + t.substring(t.length()-2, t.length());
doc.put("type", "listener_telemetry");
doc.put("time_created", t);
doc.put("time_uploaded", t);
JSONObject client = new JSONObject();
client.put("device", device);
client.put("device_software", device_software);
client.put("application", application);
client.put("application_version", application_version);
JSONObject data = _listener_info.getJSONDataField();
data.put("client", client);
doc.put("data", data);
String sha = _listener_info.toSha256();
db.saveDocument(doc,sha);
CouchResponse cr = s.getLastResponse();
System.out.println(cr);
if (cr.isOk())
_listener_telem_UUID = sha;
*/
}
}
Document doc = new Document();
JSONObject data = new JSONObject();
JSONObject receivers = new JSONObject();
JSONObject receiver = new JSONObject();
//date uploaded
Date time = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
String t = dateFormat.format(time);
t = t.substring(0, t.length()-2) + ":" + t.substring(t.length()-2, t.length());
String str64 = input.raw_64_str();
data.put("_raw", str64);
receiver.put("time_created", input.doc_time_created);
receiver.put("time_uploaded",t);
if (input.habitat_metadata != null)
receiver.putAll(input.habitat_metadata);
if (_listener_telem_UUID != "")
receiver.put("latest_listener_telemtry",_listener_telem_UUID);
if (_listener_info_UUID != "")
receiver.put("latest_listener_information",_listener_info_UUID);
receivers.put(_listener_info.CallSign(),receiver);
doc.put("type","payload_telemetry");
doc.put("data",data.toString());
doc.put("receivers",receivers.toString());
String sha = input.toSha256();
//System.out.println(doc.toString());
db.saveDocument(doc,sha); //try to upload as only listener
CouchResponse cr = s.getLastResponse(); //see if successful
if (cr.isOk())
{ //addition went well, but get the payload config ID if not already
if (payload_configs.containsKey(input.callsign))
return true;
//if not already existing, query the now parsed document
Document result = db.getDocument(sha);
if (result != null)
{
if (result.getJSONObject().containsKey("data"))
{
JSONObject objdata = result.getJSONObject().getJSONObject("data");
if (objdata.containsKey("_parsed"))
{
objdata = objdata.getJSONObject("_parsed");
if (objdata.containsKey("payload_configuration"))
payload_configs.put(input.callsign, objdata.getString("payload_configuration"));
if (objdata.containsKey("flight"))
flight_configs.put(input.callsign, objdata.getString("flight"));
}
}
}
return true;
}
if (!cr.getErrorId().equals("conflict"))
{
//throw error but continue
}
Document result = db.getDocument(sha);
//if payload configs does not contain the payload config ID, get it
if (!payload_configs.containsKey(input.callsign))
{
if (result != null)
{
if (result.getJSONObject().containsKey("data"))
{
JSONObject objdata = (JSONObject)(result.getJSONObject().get("data"));
if (objdata.containsKey("_parsed"))
{
JSONObject obparse = (JSONObject)objdata.get("_parsed");
if (obparse.containsKey("payload_configuration"))
payload_configs.put(input.callsign, obparse.get("payload_configuration").toString());
}
}
}
}
int its = 0;
//start of main loop
while(its < 30)
{
its++;
if (result == null)
return false; //somethings gone wrong
//instead try to append document
JSONObject existing_receivers = new JSONObject();
JSONObject _dat_a = (JSONObject) result.get("data");
if (_dat_a == null)
{
System.out.println("DID NOT PARSE DATA SECTION");
}
/*
double gf = 4.3600000000000003197;
double ss = 0.0000000000000003197;
double p = gf - 4.36;
System.out.println(_dat_a.get("battery") + " " + gf + " " + ss + " " + p); */
if (!result.containsKey("receivers"))
return false; //somethings gone wrong
existing_receivers = (JSONObject) result.remove("receivers");
existing_receivers.put(_listener_info.CallSign(),receiver);
result.put("receivers", existing_receivers);
db.saveDocument(result,sha);
cr = s.getLastResponse();
//System.out.println(cr.statusCode);
if (cr.isOk())
return true;
if (cr.getErrorId() == null)
{
//throw error but continue
its += 9;
}
else if (!cr.getErrorId().equals("conflict"))
{
//throw error but continue
its += 9;
}
//get document for next run through
result = db.getDocument(sha);
}
//System.out.println(cr.isOk() + " " + cr.getErrorId() + " " + cr.getErrorReason());
//System.out.println(s.getLastResponse());
}
catch (Exception e)
{
return false;
}
return false;
}
protected void fireDataReceived(TreeMap<Long, Telemetry_string> out, boolean success, String callsign, long startTime, long endTime, AscentRate as, double maxAltitude)
{
for (int i = 0; i < _listeners.size(); i++)
{
_listeners.get(i).HabitatRx(out, success, callsign, startTime, endTime,as,maxAltitude);
}
}
public void addStringRecievedListener(HabitatRxEvent listener)
{
_listeners.add(listener);
}
class SendThread extends Thread
{
public void run()
{
boolean buff_empty = false;
while(!buff_empty)
{
if (!_operations.isEmpty())
{
QueueItem qi = _operations.poll();
if (qi != null)
{
if (qi.type == 0)
{ //upload telem
Telemetry_string tosend = out_buff.peek();
boolean res = true;
if (tosend != null)
res = _upload(tosend); //now we have some telem, lets send it
if (!res)
System.out.println("UPLOAD FAILED :(");
else //success, remove data from queue
out_buff.poll();
}
else if (qi.type == 1)
{ //get data
String id = resolvePayloadID(qi.callsign);
if (!telem_configs.containsKey(qi.callsign.toUpperCase()))
queryPayloadConfig(id);
if (id != null)
getPayloadDataSince(qi.startTime, qi.stopTime,qi.count, id, qi.callsign);
}
else if (qi.type == 2) //update list of active flights
{
_queried_current_flights = queryActiveFlights();
}
else //upload chasecar
{
_update_chasecar();
}
}
else
buff_empty = true;
}
else
buff_empty = true;
}
//deal with any items in the send queue which are left over
buff_empty = false;
while(!buff_empty)
{
if (out_buff.isEmpty())
{
buff_empty = true;
}
else
{
Telemetry_string tosend = out_buff.poll();
boolean res = true;
if (tosend == null)
buff_empty = true;
else
res = _upload(tosend); //now we have some telem, lets send it
if (!res)
System.out.println("UPLOAD FAILED :(");
}
}
}
}
private boolean update_listener_telem()
{
try
{
Document doc = new Document ();
Document doc_info = new Document ();
//date uploaded
Date time = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
String t = dateFormat.format(time);
t = t.substring(0, t.length()-2) + ":" + t.substring(t.length()-2, t.length());
doc.put("type", "listener_telemetry");
doc.put("time_created", t);
doc.put("time_uploaded", t);
JSONObject client = new JSONObject();
JSONObject l_info = new JSONObject();
client.put("device", device);
client.put("device_software", device_software);
client.put("application", application);
client.put("application_version", application_version);
JSONObject data = _listener_info.getJSONDataFieldTelem();
data.put("client", client);
doc.put("data", data);
doc_info.put("data",l_info);
String sha = _listener_info.toSha256();
db.saveDocument(doc,sha);
CouchResponse cr = s.getLastResponse();
System.out.println(cr);
if (cr.isOk())
_listener_telem_UUID = sha;
}
catch (Exception e)
{
return false;
}
return true;
}
private boolean update_listener_info()
{
try
{
Document doc_info = new Document ();
//date uploaded
Date time = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
String t = dateFormat.format(time);
t = t.substring(0, t.length()-2) + ":" + t.substring(t.length()-2, t.length());
doc_info.put("type", "listener_information");
doc_info.put("time_created", t);
doc_info.put("time_uploaded", t);
doc_info.put("data",_listener_info.getJSONDataFieldInfo());
String sha_info = toSha256(doc_info.toString());
db.saveDocument(doc_info,sha_info);
CouchResponse cr = s.getLastResponse();
System.out.println(cr);
if (cr.isOk())
_listener_info_UUID = sha_info;
}
catch (Exception e)
{
return false;
}
return true;
}
public boolean newTelemConfigs()
{
return _newTelemConfigs;
}
public ConcurrentHashMap<String,TelemetryConfig> getTelemConfigs()
{
_newTelemConfigs = false;
return telem_configs;
}
class QueueItem
{
public int type; //0: upload payload, 1: get payload telem, 2: update active flight list, 3: update chase car
public String callsign = "";
public long startTime = 0;
public long stopTime = 0;
public int count = 0;
public QueueItem(int _type,int _count)
{
type = _type;
count = _count;
}
public QueueItem(int _type, String _callsign, long _startTime, long _stopTime, int _count)
{
type = _type;
callsign = _callsign;
startTime = _startTime;
stopTime = _stopTime;
count = _count;
}
}
public static String toSha256(String str)
{
byte [] enc = Base64.encodeBase64(str.getBytes());
byte[] sha = null;
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-256");
md.update(enc);
sha = md.digest();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return bytesToHexStr(sha);
}
//ref: http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java
public static String bytesToHexStr(byte[] bytes) {
final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
char[] hexChars = new char[bytes.length * 2];
int v;
for ( int j = 0; j < bytes.length; j++ ) {
v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
}