diff --git a/src/cli/esim.js b/src/cli/esim.js index 7114f8dec..b15be0e2c 100644 --- a/src/cli/esim.js +++ b/src/cli/esim.js @@ -41,6 +41,16 @@ module.exports = ({ commandProcessor, root }) => { TBD TBD `) }); + + commandProcessor.createCommand(esim, 'enable', 'Enables a downloaded eSIM profile', { + handler: (args) => { + const ESimCommands = require('../cmd/esim'); + return new ESimCommands().enableCommand(); + }, + examples: { + '$0 $command': 'TBD' + } + }); return esim; }; diff --git a/src/cmd/esim.js b/src/cmd/esim.js index 78dd678f4..ffdb475f0 100644 --- a/src/cmd/esim.js +++ b/src/cmd/esim.js @@ -78,6 +78,16 @@ module.exports = class ESimCommands extends CLICommandBase { console.log('Ready to bulk provision. Connect devices to start. Press Ctrl-C to exit.'); } + async enableCommand() { + this.verbose = true; + const device = await this.serial.whatSerialPortDidYouMean(); + if (device.type === 'Tachyon') { + this.isTachyon = true; + } + + await this.doEnable(device); + } + // Populate the availableProvisioningData set with the indices of the input JSON data // If a profile is already provisioned (output JSON file exists with an entry), remove it from the set async _generateAvailableProvisioningData() { @@ -246,6 +256,71 @@ module.exports = class ESimCommands extends CLICommandBase { } } + async doEnable(device) { + let provisionOutputLogs = []; + let timestamp = new Date().toISOString().replace(/:/g, '-'); + let success = false; + + const outputJsonFile = path.join(this.outputFolder, `${this.isTachyon ? 'tachyon' : device.deviceId}_${timestamp}.json`); + + const processOutput = async (failedLogs = []) => { + const logs = Array.isArray(failedLogs) ? failedLogs : [failedLogs]; + provisionOutputLogs.push({ + step: 'final_step', + timestamp: new Date().toISOString().replace(/:/g, '-'), + success: success ? 'success' : 'failed', + details: { + rawLogs: success ? ['Profile enable successful'] : ['Profile enable failed', ...logs], + } + }); + await this._changeLed(device, success ? PROVISIONING_SUCCESS : PROVISIONING_FAILURE); + this._addToJson(outputJsonFile, provisionOutputLogs.filter(Boolean)); + }; + + try { + const port = device.port; + + // Start qlril-app through ADB for Tachyon + const qlrilStep = await this._initializeQlril(); + provisionOutputLogs.push(qlrilStep); + if (qlrilStep?.status === 'failed') { + await processOutput(); + return; + } + + const iccidsOnDevice = await this._getIccidOnDevice(port); + + const iccidToEnable = this._getIccidToEnable(iccidsOnDevice); + provisionOutputLogs.push(`ICCID to enable: ${iccidToEnable}`); + if (iccidToEnable === null) { + await processOutput('No profile found on the device to enable'); + return; + } + + const enableResp = await this._enableProfile(port, iccidToEnable); + provisionOutputLogs.push(enableResp); + if (enableResp.status === 'failed') { + await processOutput(); + return; + } + + const verifyIccidEnabledResp = await this._verifyIccidEnaled(port, iccidToEnable); + provisionOutputLogs.push(verifyIccidEnabledResp); + if (verifyIccidEnabledResp.status === 'failed') { + await processOutput(); + return; + } + + success = true; + console.log('Profile enabled successfully'); + await processOutput(); + } catch (error) { + await processOutput(error.message); + } finally { + this._exitQlril(); + } + } + _validateArgs(args) { if (!args) { throw new Error('Missing args'); @@ -288,11 +363,7 @@ module.exports = class ESimCommands extends CLICommandBase { } }; - const profilesOnDeviceAfterDownload = await this._listProfiles(port); - const iccidsOnDeviceAfterDownload = profilesOnDeviceAfterDownload.map((line) => line.split('[')[1].split(',')[0].trim()); - - // remove test ICCIDs from iccidsOnDeviceAfterDownload - const iccidsOnDeviceAfterDownloadFiltered = iccidsOnDeviceAfterDownload.filter((iccid) => !TEST_ICCID.includes(iccid)); + const iccidsOnDeviceAfterDownloadFiltered = await this._getIccidOnDevice(port); const equal = _.isEqual(_.sortBy(expectedIccids), _.sortBy(iccidsOnDeviceAfterDownloadFiltered)); @@ -581,6 +652,16 @@ module.exports = class ESimCommands extends CLICommandBase { return profilesList; } + async _getIccidOnDevice(port) { + const profilesOnDeviceAfterDownload = await this._listProfiles(port); + const iccidsOnDeviceAfterDownload = profilesOnDeviceAfterDownload.map((line) => line.split('[')[1].split(',')[0].trim()); + + // remove test ICCIDs from iccidsOnDeviceAfterDownload + const iccidsOnDeviceAfterDownloadFiltered = iccidsOnDeviceAfterDownload.filter((iccid) => !TEST_ICCID.includes(iccid)); + + return iccidsOnDeviceAfterDownloadFiltered; + } + // Get the next available profile from availableProvisioningData // Once a profile is fetched, remove it from the set so other devices don't get the same profile _getProfiles() {