Page MenuHomec4science

AdbDevice.js
No OneTemporary

File Metadata

Created
Sun, Nov 10, 02:28

AdbDevice.js

const Device = require("./Device")
const fs = require("fs-extra");
const toast = require("../helper/toasts");
const files = require("../helper/files");
const path = require("path");
const {Adb} = require("@devicefarmer/adbkit");
const Bluebird = require('bluebird')
let client = Adb.createClient()
class AdbDevice extends Device {
constructor(brand, model, id) {
super()
this.brand = brand
this.model = model
this.id = id
this.name = `${brand} ${model} - ${id}`
this.deviceClient = client.getDevice(id)
}
/**
* Download all logs found inside the sub-folder /ExperimentLogs. The files are downloaded recursively.
* @param destinationFolder where the files should be saved to
* @returns {Promise<boolean>} true: download complete, false otherwise
*/
async downloadLogs(destinationFolder) {
try {
// get all files to download
const fileList = await this.getFilesRecursively('', AdbDevice.PATH + '/ExperimentLogs')
// download one file after the other
for (const file of fileList) {
const transfer = await this.deviceClient.pull(AdbDevice.PATH + '/ExperimentLogs' + file)
await new Bluebird(function (resolve, reject) {
const filename = destinationFolder + file
// make sure the target folder exists
if (!fs.existsSync(path.dirname(filename))) {
fs.mkdirSync(path.dirname(filename), {recursive: true})
}
transfer.on('end', () => {
console.log(`download complete: ${file}`)
resolve();
})
transfer.on('error', () => {
console.error(`download error on file: ${file}`)
reject();
})
transfer.pipe(fs.createWriteStream(filename))
})
}
} catch (e) {
console.error(e.message)
return false
}
return true
}
/**
* Upload a list of files. Each entry in the array must contain full source and target name of the file.
*
* @param fileList array of objects having the attributes "source" and "target"
* @returns {Promise<boolean>} true: all uploads complete, false otherwise
*/
async upload(fileList) {
try {
for (const file of fileList) {
// start the upload of one file
const transfer = await this.deviceClient.push(file.source, file.target)
// wait for a result to arrive. will throw an exception if something goes wrong
await new Bluebird(function (resolve, reject) {
transfer.on('end', () => {
console.log(`upload completed: ${file.source}`)
resolve()
})
transfer.on('error', () => {
console.error(`upload error on file: ${file.source}`)
reject()
})
})
}
} catch (e) {
console.error(e.message)
return false
}
return true
}
/**
* Upload a file and rename it "config.json". The file will be placed where the game is looking for the
* configuration.
* @param file configuration file to rename and upload
* @returns {Promise<boolean>} true: upload complete, false otherwise
*/
async uploadConfig(file) {
return await this.upload([{source: file, target: AdbDevice.PATH + '/config.json'}])
}
/**
* Prepares a list of files and uploads them after preparing. Preparing means: converting the list into list of
* objects with properties "source" and "target". The files will be uploaded into the given sub-folder.
* @param filePaths list of files to upload with full (absolute) file names
* @param subFolder sub-folder on the target device
* @returns {Promise<boolean>} true: all files uploaded, false otherwise
*/
async prepareAndUpload(filePaths, subFolder) {
let fileList = files.prepare(filePaths, AdbDevice.PATH + '/' + subFolder + '/')
return await this.upload(fileList)
}
/**
* Deletes a list of files with names that are relative to "rootFolder".
* @param fileList list of files to delete, with relative file names
* @param rootFolder root folder where all files to be deleted are contained
* @returns {Promise<boolean>} true: all files deleted successfully, false otherwise
*/
async remove(fileList, rootFolder) {
try {
for (const file of fileList) {
// delete a file
const command = await this.deviceClient.shell(`rm -rf "${rootFolder}${file}"`)
// wait for the result of this command
await new Bluebird(function (resolve, reject) {
command.on('end', () => {
console.log(`file deleted: ${rootFolder + file}`)
resolve()
})
command.on('error', () => {
console.error(`error deleting file: ${rootFolder + file}`)
reject()
})
})
}
} catch (e) {
console.error(e.message)
return false
}
return true
}
/**
* Get a list of all files inside "rootFolder" recursively. Can include folders if flag is set. The resulting list
* will contain file names relative to "rootFolder".
* @param subFolder <b>leave empty</b>. used on recursive calls.
* @param rootFolder root folder where to start looking for files
* @param includeFolders whether or not the resulting list should include folders
* @returns {Promise<*[]>} list of files
*/
async getFilesRecursively(subFolder, rootFolder, includeFolders) {
let results = []
const fileList = await this.deviceClient.readdir(rootFolder)
// for each entry in the directory
for (const file of fileList) {
if (!file.isFile()) {
// for folders: read the content of this folder and add all files to the result list
results = results.concat(await this.getFilesRecursively(subFolder + "/" + file.name, rootFolder + "/" + file.name))
}
if (file.isFile() || includeFolders) {
// for files: add relative path of this file to the result list. add folders as well if the flag is set
results.push(subFolder + "/" + file)
}
}
return results
}
/**
* Get the absolute path of the game files and concatenate it if a given list of sub-folders (if present).
* @param subFolders string to concatenate to the path. should not have any "/" at start and end
* @returns {string} path of game files, concatenated with "subFolder"
*/
getPath(subFolders) {
let result = AdbDevice.PATH
if (subFolders) {
for (const folder of subFolders) {
result += '/' + folder
}
}
return result
}
/**
* The name of this device.
* @returns {string} the name
*/
toString() {
return this.name
}
/**
* Get a list of connected ADB devices. For this to work, a standalone ADB server must be running on the host
* device.
* @returns {Promise<*[]>} list of devices
*/
static async getDevices() {
let devices = []
if (client) {
try {
let adbDevices = await client.listDevices()
// read all devices that answer to ADB
const deviceList = await Bluebird.map(adbDevices, async (device) => {
const properties = await client.getDevice(device.id).getProperties()
return new AdbDevice(properties['ro.product.manufacturer'], properties['ro.product.model'], device.id)
})
// store devices in variable for later use
devices = devices.concat(deviceList)
} catch (err) {
console.error(err.message)
toast.create("Erreur de detection d'appareil adb. Acceptez la connexion sur l'appareil.", 'text-bg-danger', 10)
}
}
return devices
}
// ---------
// constants
// ---------
/**
* The root folder where the game files are stored.
*/
static get PATH() {
return '/sdcard/Android/data/com.HEIAFR.ImmersiveSeriousGameFactory/files'
}
/**
* The type of this device.
*/
static get TYPE() {
return 'adb'
}
}
module.exports = AdbDevice;

Event Timeline