Skip to content

Commit 31ac019

Browse files
committed
🐛 fix "share log" error due to leftover loggerDB tmp file
e-mission/e-mission-docs#1110 After sharing the tmp DB file, we try to clear it, but if this operation fails or the app exits before we get to this, for any reason, all subsequent attempts to share the DB file would fail with error 12 (PATH_EXISTS_ERR) A simple solution is to attempt to clear the tmp file before *and* after sharing. I also changed this to async/await syntax to make it clearer what is happening. Testing done: I ran a dev build of emission on an Android test phone. From profile I clicked Share log and saw the "tmp file did not exist, that is fine..." log The share menu came up but before dismissing it I went into app settings and Force Quit the app. This caused a leftover tmp file that was not cleared. (I never saw "Successfully cleaned up file loggerDB" in the console) Then I launched the app again and repeated the same steps. This time I saw "Successfully cleaned up file..." in the console. The user-visible behavior was the same (share menu popped up). After allowing the share menu to dismiss, I saw "Successfully cleaned up file loggerDB" again
1 parent 157afec commit 31ac019

File tree

1 file changed

+98
-96
lines changed

1 file changed

+98
-96
lines changed

www/js/services/shareLocalDBFile.ts

+98-96
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,91 @@
11
import i18next from 'i18next';
2-
import { displayError, displayErrorMsg, logDebug, logWarn } from '../plugin/logger';
2+
import { displayError, displayErrorMsg, logDebug } from '../plugin/logger';
33

4-
function localDBHelpers(fileName: string, fileExtension: string = '.txt') {
5-
async function localCopyFile() {
6-
return new Promise<void>((resolve, reject) => {
7-
let pathToFile, parentDirectory;
8-
if (window['cordova'].platformId == 'android') {
9-
// parentDirectory: file:///data/user/0/edu.berkeley.eecs.emission/files/
10-
parentDirectory = window['cordova'].file.dataDirectory.replace('files', 'databases');
11-
// pathToFile: /data/user/0/edu.berkeley.eecs.emission/files/
12-
pathToFile = parentDirectory.replace('file://', '') + fileName;
13-
} else if (window['cordova'].platformId == 'ios') {
14-
// parentDirectory: file:///var/mobile/Containers/Data/Application/<32-hex-digit-id>/Library/NoCloud/../
15-
parentDirectory = window['cordova'].file.dataDirectory + '../';
16-
pathToFile = 'LocalDatabase/' + fileName;
17-
} else {
18-
displayErrorMsg('Error: Unknown OS!');
19-
throw new Error('Error: Unknown OS!');
20-
}
4+
function localCopyFile(fileName: string, fileExtension: string = '.txt') {
5+
return new Promise<void>((resolve, reject) => {
6+
let pathToFile, parentDirectory;
7+
if (window['cordova'].platformId == 'android') {
8+
// parentDirectory: file:///data/user/0/edu.berkeley.eecs.emission/files/
9+
parentDirectory = window['cordova'].file.dataDirectory.replace('files', 'databases');
10+
// pathToFile: /data/user/0/edu.berkeley.eecs.emission/files/
11+
pathToFile = parentDirectory.replace('file://', '') + fileName;
12+
} else if (window['cordova'].platformId == 'ios') {
13+
// parentDirectory: file:///var/mobile/Containers/Data/Application/<32-hex-digit-id>/Library/NoCloud/../
14+
parentDirectory = window['cordova'].file.dataDirectory + '../';
15+
pathToFile = 'LocalDatabase/' + fileName;
16+
} else {
17+
displayErrorMsg('Error: Unknown OS!');
18+
throw new Error('Error: Unknown OS!');
19+
}
2120

22-
window['resolveLocalFileSystemURL'](parentDirectory, (fs) => {
23-
// On iOS, pass in relative path to getFile https://github.com/e-mission/e-mission-phone/pull/1160#issuecomment-2192112472
24-
// On Android, pass in absolute path to getFile https://github.com/e-mission/e-mission-phone/pull/1160#issuecomment-2204297874
25-
fs.filesystem.root.getFile(pathToFile, { create: false, exclusive: false }, (fileEntry) => {
26-
// logDebug(`fileEntry ${fileEntry.nativeURL} is file? ${fileEntry.isFile.toString()}`);
27-
logDebug(`fileEntry is: ${JSON.stringify(fileEntry, null, 2)}`);
28-
window['resolveLocalFileSystemURL'](window['cordova'].file.cacheDirectory, (copyDir) => {
29-
logDebug(`DirectoryEntry is: ${JSON.stringify(copyDir.filesystem.root, null, 2)}`);
21+
window['resolveLocalFileSystemURL'](parentDirectory, (fs) => {
22+
// On iOS, pass in relative path to getFile https://github.com/e-mission/e-mission-phone/pull/1160#issuecomment-2192112472
23+
// On Android, pass in absolute path to getFile https://github.com/e-mission/e-mission-phone/pull/1160#issuecomment-2204297874
24+
fs.filesystem.root.getFile(pathToFile, { create: false, exclusive: false }, (fileEntry) => {
25+
// logDebug(`fileEntry ${fileEntry.nativeURL} is file? ${fileEntry.isFile.toString()}`);
26+
logDebug(`fileEntry is: ${JSON.stringify(fileEntry, null, 2)}`);
27+
window['resolveLocalFileSystemURL'](window['cordova'].file.cacheDirectory, (copyDir) => {
28+
logDebug(`DirectoryEntry is: ${JSON.stringify(copyDir.filesystem.root, null, 2)}`);
3029

31-
fileEntry.copyTo(
32-
copyDir.filesystem.root,
33-
fileName + fileExtension,
34-
(res) => {
35-
logDebug(`Res: ${res}`);
36-
resolve();
37-
},
38-
(rej) => {
39-
displayErrorMsg(`Rej: ${JSON.stringify(rej, null, 2)}`);
40-
reject();
41-
},
42-
);
43-
});
30+
fileEntry.copyTo(
31+
copyDir.filesystem.root,
32+
fileName + fileExtension,
33+
(res) => {
34+
logDebug(`Res: ${res}`);
35+
resolve();
36+
},
37+
(rej) => {
38+
displayErrorMsg(`Rej: ${JSON.stringify(rej, null, 2)}`);
39+
reject();
40+
},
41+
);
4442
});
4543
});
4644
});
47-
}
45+
});
46+
}
4847

49-
function localShareFile() {
50-
return new Promise<void>((resolve, reject) => {
51-
window['resolveLocalFileSystemURL'](window['cordova'].file.cacheDirectory, (fs) => {
52-
fs.filesystem.root.getFile(
53-
fileName + fileExtension,
54-
null,
55-
(fileEntry) => {
56-
const shareObj = {
57-
files: [fileEntry.nativeURL],
58-
message: i18next.t('shareFile-service.send-log.body-please-fill-in-what-is-wrong'),
59-
subject: i18next.t('shareFile-service.send-log.subject-logs'),
60-
};
61-
window['plugins'].socialsharing.shareWithOptions(
62-
shareObj,
63-
(result) => {
64-
logDebug(`Share Completed? ${result.completed}`); // On Android, most likely returns false
65-
logDebug(`Shared to app: ${result.app}`);
66-
resolve();
67-
},
68-
(error) => {
69-
displayError(error, `Sharing failed with error`);
70-
},
71-
);
72-
},
73-
(error) => {
74-
displayError(error, 'Error while sharing logs');
75-
reject(error);
76-
},
77-
);
78-
});
48+
function localShareFile(fileName: string, fileExtension: string = '.txt') {
49+
return new Promise<void>((resolve, reject) => {
50+
window['resolveLocalFileSystemURL'](window['cordova'].file.cacheDirectory, (fs) => {
51+
fs.filesystem.root.getFile(
52+
fileName + fileExtension,
53+
null,
54+
(fileEntry) => {
55+
const shareObj = {
56+
files: [fileEntry.nativeURL],
57+
message: i18next.t('shareFile-service.send-log.body-please-fill-in-what-is-wrong'),
58+
subject: i18next.t('shareFile-service.send-log.subject-logs'),
59+
};
60+
window['plugins'].socialsharing.shareWithOptions(
61+
shareObj,
62+
(result) => {
63+
logDebug(`Share Completed? ${result.completed}`); // On Android, most likely returns false
64+
logDebug(`Shared to app: ${result.app}`);
65+
resolve();
66+
},
67+
(error) => {
68+
displayError(error, `Sharing failed with error`);
69+
},
70+
);
71+
},
72+
(error) => {
73+
displayError(error, 'Error while sharing logs');
74+
reject(error);
75+
},
76+
);
7977
});
80-
}
78+
});
79+
}
8180

82-
function localClearTmpFile() {
83-
return new Promise<void>((resolve, reject) => {
84-
window['resolveLocalFileSystemURL'](window['cordova'].file.cacheDirectory, (fs) => {
85-
fs.filesystem.root.getFile(fileName + fileExtension, null, (fileEntry) => {
81+
function localClearTmpFile(fileName: string, fileExtension: string = '.txt') {
82+
return new Promise<void>((resolve, reject) => {
83+
window['resolveLocalFileSystemURL'](window['cordova'].file.cacheDirectory, (fs) => {
84+
fs.filesystem.root.getFile(
85+
fileName + fileExtension,
86+
null,
87+
(fileEntry) => {
88+
logDebug(`got fileEntry: ${JSON.stringify(fileEntry, null, 2)}`);
8689
fileEntry.remove(
8790
() => {
8891
logDebug(`Successfully cleaned up file ${fileName}`);
@@ -93,29 +96,28 @@ function localDBHelpers(fileName: string, fileExtension: string = '.txt') {
9396
reject(err);
9497
},
9598
);
96-
});
97-
});
99+
},
100+
(getFileError) => {
101+
logDebug(`tmp file did not exist, that is fine: ${JSON.stringify(getFileError)}`);
102+
resolve();
103+
},
104+
);
98105
});
99-
}
100-
101-
return {
102-
copyFile: localCopyFile,
103-
shareData: localShareFile,
104-
clearTmpFile: localClearTmpFile,
105-
};
106+
});
106107
}
107-
export async function sendLocalDBFile(database: string) {
108+
109+
export async function sendLocalDBFile(dbFileName: string) {
108110
alert(i18next.t('shareFile-service.send-to'));
109111

110-
const dataMethods = localDBHelpers(database);
111-
dataMethods
112-
.copyFile()
113-
.then(dataMethods.shareData)
114-
.then(dataMethods.clearTmpFile)
115-
.then(() => {
116-
logDebug(`File Shared!`);
117-
})
118-
.catch((err) => {
119-
displayError(err);
120-
});
112+
try {
113+
// in case there is a leftover tmp file, clear it before sharing
114+
await localClearTmpFile(dbFileName);
115+
await localCopyFile(dbFileName);
116+
await localShareFile(dbFileName);
117+
// clear the tmp file after sharing
118+
await localClearTmpFile(dbFileName);
119+
logDebug(`File Shared!`);
120+
} catch (err) {
121+
displayError(err);
122+
}
121123
}

0 commit comments

Comments
 (0)