Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

recorder: resume logs recorded within 4 hours #3136

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/recorder/ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@
setInterval.
0.38: Tweaks to speed up track rendering
0.39: Minor code improvements
0.40: Resume previous recorder logs, if within four hours - regardless of date
2 changes: 1 addition & 1 deletion apps/recorder/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"id": "recorder",
"name": "Recorder",
"shortName": "Recorder",
"version": "0.39",
"version": "0.40",
"description": "Record GPS position, heart rate and more in the background, then download to your PC.",
"icon": "app.png",
"tags": "tool,outdoors,gps,widget,clkinfo",
Expand Down
143 changes: 143 additions & 0 deletions apps/recorder/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
let writes = {};
let testDate, now;
let files;

const testDateStamp = () => `${testDate.getYear() + 1900}${testDate.getMonth() + 1}${testDate.getDate()}`;

const mockStorage = {
readJSON(f, err) {
if(f === "recorder.json"){
return {};
}
throw new Error(`unimplemented readJSON(${args})`);

Check warning on line 12 in apps/recorder/test.js

View workflow job for this annotation

GitHub Actions / build

'args' is not defined
},
writeJSON(fname, json) {
if(!writes[fname])
writes[fname] = [];
writes[fname].push(json);
},
list(re) {
let files = [
"recorder.json",
"recorder.log20230802a.csv\1",
`recorder.log${testDateStamp()}a.csv\x01`,
"recorder.log20181219a.csv\1",
"abc",
];

if (re)
files = files.filter(f => re.test ? re.test(f) : re === f);
return files;
},
read(...args) {
throw new Error(`unimplemented read(${args})`);
},
write(...args) {
throw new Error(`unimplemented write(${args})`);
},
open(f, mode) {
f = f.replace(/\1$/, "");

const lines = files[f] || [];

return {
readLine() {
return lines.shift() || "";
}
}
},
};

const assertEq = (a, b) => {
if(typeof a !== typeof b)
throw new Error("type mismatch");
if(typeof a !== "string")
throw new Error("unimplemented");
if(a !== b)
throw new Error(`string mismatch, ${JSON.stringify(a)} != ${JSON.stringify(b)}`);
}

require = (origRequire => req => {
if (req === "Storage") {
return mockStorage;
}
return origRequire(req);
})(require);

Date = (OrigDate => function(...args) {
if (args.length === 0) {
// new Date(), pretend the time is what we're testing
return new OrigDate(now);
}
return new OrigDate(...args);
})(Date);

Bangle = {
removeListener(){},
drawWidgets(){},
}
WIDGETS = {};
const w = require("fs").readFileSync("./widget.js", "utf8");
eval(w);

let file;

/*
* if it's almost midnight but we have a recording
* from ~15 mins ago, we select it
*/
testDate = new Date("2023-11-23T23:45:00.000Z");
now = new Date("2023-11-23T23:59:00.000Z");
files = {
[`recorder.log${testDateStamp()}a.csv`]: [
"Time,Steps",
"2023-12-20T19:27:45.000Z,9",
testDate.toISOString() + ",21",
],
};
writes = {};

WIDGETS["recorder"].setRecording(true);

file = writes["recorder.json"][0].file;
assertEq(file, `recorder.log20231123a.csv`);

/*
* if it's past midnight but we have a recording
* from ~15 mins ago, we select it
*/
testDate = new Date("2023-11-23T23:45:00.000Z");
now = new Date("2023-11-24T00:01:00.000Z");
files = {
[`recorder.log${testDateStamp()}a.csv`]: [
"Time,Steps",
"2023-12-20T19:27:45.000Z,9",
testDate.toISOString() + ",21",
],
};
writes = {};

WIDGETS["recorder"].setRecording(true);

file = writes["recorder.json"][0].file;
assertEq(file, `recorder.log20231123a.csv`);

/*
* if it's a fair bit after the last recording,
* we pick a new one
*/
testDate = new Date("2023-11-23T23:45:00.000Z");
now = new Date("2023-11-24T03:45:00.000Z"); // just over the 4 hour limit
files = {
[`recorder.log${testDateStamp()}a.csv`]: [
"Time,Steps",
"2023-12-20T19:27:45.000Z,9",
testDate.toISOString() + ",21",
],
};
writes = {};

WIDGETS["recorder"].setRecording(true);

file = writes["recorder.json"][0].file;
assertEq(file, `recorder.log20231124a.csv`);
34 changes: 29 additions & 5 deletions apps/recorder/widget.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
let storageFile; // file for GPS track
let entriesWritten = 0;

Check warning on line 3 in apps/recorder/widget.js

View workflow job for this annotation

GitHub Actions / build

'entriesWritten' is assigned a value but never used
let activeRecorders = [];
let writeSetup;

Expand Down Expand Up @@ -63,7 +63,7 @@
function onHRM(h) {
bpmConfidence = h.confidence;
bpm = h.bpm;
srv = h.src;

Check warning on line 66 in apps/recorder/widget.js

View workflow job for this annotation

GitHub Actions / build

'srv' is not defined
}
return {
name : "HR",
Expand Down Expand Up @@ -194,7 +194,7 @@
}
}

let writeOnGPS = function() {writeLog(settings.period);};

Check warning on line 197 in apps/recorder/widget.js

View workflow job for this annotation

GitHub Actions / build

'settings' is not defined

// Called by the GPS app to reload settings and decide what to do
let reload = function() {
Expand Down Expand Up @@ -256,10 +256,34 @@
options = options||{};
if (isOn && !settings.recording) {
var date=(new Date()).toISOString().substr(0,10).replace(/-/g,""), trackNo=10;
function getTrackFilename() { return "recorder.log" + date + trackNo.toString(36) + ".csv"; }
if (!settings.file || !settings.file.startsWith("recorder.log" + date)) {
// if no filename set or date different, set up a new filename
settings.file = getTrackFilename();
function nextTrackFilename() { return "recorder.log" + date + trackNo.toString(36) + ".csv"; }
function mostRecentFile() {
const logs = require("Storage").list(/^recorder\.log/);

if(logs.length > 0){
logs.sort();
const latest = logs[logs.length-1].replace("\1", "");
const f = require("Storage").open(latest, "r");
const timeIdx = f.readLine().replace("\n", "").split(",").indexOf("Time");
if(timeIdx >= 0){
let last, tmp;
while((tmp = f.readLine()))
last = tmp;

const when = new Date(last.replace("\n", "").split(",")[timeIdx]);
const now = new Date;
const age = now.getTime() - when.getTime();
if (age < 14400000) { // 4 hours
return latest;
}
}
}
}
const recentlyRecorded = mostRecentFile();
if (recentlyRecorded) {
settings.file = recentlyRecorded;
} else if (!settings.file) {
settings.file = nextTrackFilename();
}
var headers = require("Storage").open(settings.file,"r").readLine();
if (headers){ // if file exists
Expand Down Expand Up @@ -289,7 +313,7 @@
// new file - use the current date
var newFileName;
do { // while a file exists, add one to the letter after the date
newFileName = getTrackFilename();
newFileName = nextTrackFilename();
trackNo++;
} while (require("Storage").list(newFileName).length);
settings.file = newFileName;
Expand Down
Loading