Skip to content

Commit

Permalink
Provision the device(s) with the next available provisioning data blo…
Browse files Browse the repository at this point in the history
…ck from the input json
  • Loading branch information
keeramis committed Nov 26, 2024
1 parent ac886ad commit e3abb1c
Showing 1 changed file with 105 additions and 74 deletions.
179 changes: 105 additions & 74 deletions src/cmd/esim.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ module.exports = class ESimCommands extends CLICommandBase {
this.downloadedProfiles = [];
this.binaries = null;
this.verbose = false;
this.availableProvisioningData = new Set();
}

async provisionCommand(args) {
this.verbose = true;
this._validateArgs(args);
await this._generateAvailableProvisioningData();

// Get the serial port and device details
const devices = await this.serial.findDevices();
Expand All @@ -45,14 +47,12 @@ module.exports = class ESimCommands extends CLICommandBase {
throw new Error(errorMessage);
}
const device = devices[0];
const resp = await this.doProvision(device);
await this._changeLed(device, resp.success ? PROVISIONING_SUCCESS : PROVISIONING_FAILURE);
const outputJsonForDevice = path.join(this.outputFolder, `${device.deviceId}.json`);
this._addToJson(outputJsonForDevice, resp);
await this.doProvision(device);
}

async bulkProvisionCommand(args) {
this._validateArgs(args);
await this._generateAvailableProvisioningData();

const provisionedDevices = new Set();
setInterval(async () => {
Expand All @@ -62,28 +62,50 @@ module.exports = class ESimCommands extends CLICommandBase {
const deviceId = device.deviceId;
provisionedDevices.add(deviceId);
console.log(`Device ${deviceId} connected`);
const outputJsonForDevice = path.join(this.outputFolder, `${deviceId}.json`);
const resp = await this.doProvision(device, { verbose: false });
await this._changeLed(device, resp.success ? PROVISIONING_SUCCESS : PROVISIONING_FAILURE);
this._addToJson(outputJsonForDevice, resp);
// Do not await here, so that the next device can be processed
await this.doProvision(device);
}
}
}, 1000);

console.log('Ready to bulk provision. Connect devices to start. Press Ctrl-C to exit.');
}

// Push to availableProvisioningData intergers from 0 to how many are in inputJsonData
// and then go through all the outut jsons from the folder of previous runs and for each entry, find the index in inputJsonData of the expectedProfiles
// and then remove that integer from availableProvisioningData
async _generateAvailableProvisioningData() {
const files = fs.readdirSync(this.outputFolder);
const jsonFiles = files.filter((file) => file.endsWith('.json'));
for (let i = 0; i < this.inputJsonData.provisioning_data.length; i++) {
this.availableProvisioningData.add(i);
}
for (const file of jsonFiles) {
const json = fs.readFileSync(path.join(this.outputFolder, file));
const data = JSON.parse(json);
for (const entry of data) {
const index = this.inputJsonData.provisioning_data.findIndex((block) => {
return _.isEqual(block.profiles, entry.expectedProfiles);
});
if (index !== -1) {
this.availableProvisioningData.delete(index);
}
}
}
}

async doProvision(device) {
let provisionOutputLogs = [];
let eid = null;
let timestamp = null;
let timestamp = new Date().toISOString();
let expectedProfilesArray = [];
let downloadedProfilesArray = [];
let success = false;
const outputJsonFile = path.join(this.outputFolder, `${device.deviceId}-${timestamp}.json`);

// Add the output logs to the output JSON file in one msg
const outputMsg = () => {
return {
const processOutput = async () => {
const resp = {
esim_id: eid,
device_id: device.deviceId,
expectedProfiles: expectedProfilesArray,
Expand All @@ -92,79 +114,61 @@ module.exports = class ESimCommands extends CLICommandBase {
timestamp: timestamp,
output: provisionOutputLogs
};
await this._changeLed(device, resp.success ? PROVISIONING_SUCCESS : PROVISIONING_FAILURE);
this._addToJson(outputJsonFile, resp);
};

try {
timestamp = new Date().toISOString();
const platform = platformForId(device.specs.productId).name;
const port = device.port;

provisionOutputLogs.push(`${os.EOL}Provisioning device ${device.deviceId} with platform ${platform}`);

// Flash firmware and wait for AT to work
const flashResp = await this._flashATPassThroughFirmware(device, platform);
provisionOutputLogs.push(...flashResp.output);
if (!flashResp.success) {
return outputMsg();
}
provisionOutputLogs.push(`${os.EOL}Firmware flashed successfully`);
// const flashResp = await this._flashATPassThroughFirmware(device, platform);
// provisionOutputLogs.push(...flashResp.output);
// if (!flashResp.success) {
// await processOutput();
// return;
// }
// provisionOutputLogs.push(`${os.EOL}Firmware flashed successfully`);

// Get the EID
const eidResp = await this._getEid(port);
provisionOutputLogs.push(...eidResp.output);
if (!eidResp.success) {
return outputMsg();
await processOutput();
return;
}
eid = (eidResp.eid).trim();
provisionOutputLogs.push(`EID: ${eid}`);

// Get the profiles for this EID and compare them against the list in the input JSON under the same EID
const matchingEsim = this.inputJsonData.provisioning_data.find(item => item.esim_id === eid);
const iccidFromJson = matchingEsim.profiles.map((profile) => profile.iccid);
expectedProfilesArray = matchingEsim.profiles;

if (!matchingEsim || iccidFromJson?.length === 0 || expectedProfilesArray?.length === 0) {
provisionOutputLogs.push('No profiles found for the given EID in the input JSON');
return outputMsg();
}

// TODO: If profiles exist, dont check anything, just bail
const profileCmdResp = await this._checkForExistingProfiles(port);
provisionOutputLogs.push(...profileCmdResp.output);
if (!profileCmdResp.success) {
return outputMsg();
await processOutput();
return;
}

const profilesListOnDevice = profileCmdResp.profilesList;
const existingIccids = profilesListOnDevice.map((line) => line.split('[')[1].split(',')[0].trim());
provisionOutputLogs.push(`${os.EOL}profilesListOnDevice: ${profilesListOnDevice}`);
provisionOutputLogs.push(`${os.EOL}existingIccids: ${existingIccids}`);

if (profilesListOnDevice.length > 0) {
// extract the iccids that belong to this EID
const matchingEsim = this.inputJsonData.provisioning_data.find(item => item.esim_id === eid);
if (!matchingEsim) {
provisionOutputLogs.push('No profiles found for the given EID in the input JSON');
return outputMsg();
}
const iccidFromJson = matchingEsim.profiles.map((profile) => profile.iccid);
const equal = _.isEqual(_.sortBy(existingIccids), _.sortBy(iccidFromJson));
if (equal) {
success = true;
provisionOutputLogs.push('Profiles already provisioned correctly on the device for the given EID');
return outputMsg();
} else {
provisionOutputLogs.push('Profiles exist on the device but do not match the profiles in the input JSON');
return outputMsg();
}
if (profileCmdResp.profilesList.length > 0) {
success = false;
provisionOutputLogs.push('Profiles already exist on the device');
await processOutput();
return;
}

// Get profiles for this EID from the input JSON
const profileResp = this._getProfiles(eid);
// Get the next available profile from availableProvisioningData
const profileResp = this._getProfiles();
provisionOutputLogs.push(...profileResp.output);
if (!profileResp.success) {
return outputMsg();
await processOutput();
return;
}

expectedProfilesArray = profileResp.profiles; // TODO: test this
const expectedIccids = profileResp.profiles.map((profile) => profile.iccid);

provisionOutputLogs.push(`${os.EOL}Provisioning the following profiles to EID ${eid}:`);

const profiles = profileResp.profiles;
Expand All @@ -191,26 +195,30 @@ module.exports = class ESimCommands extends CLICommandBase {

if (!downloadResp.success) {
provisionOutputLogs.push('Profile download failed');
return outputMsg();
await processOutput();
return;
}

const profilesOnDeviceAfterDownload = await this._listProfiles(port);
const iccidsOnDeviceAfterDownload = profilesOnDeviceAfterDownload.map((line) => line.split('[')[1].split(',')[0].trim());
const equal = _.isEqual(_.sortBy(iccidsOnDeviceAfterDownload), _.sortBy(iccidFromJson));
const equal = _.isEqual(_.sortBy(iccidsOnDeviceAfterDownload), _.sortBy(expectedIccids));
if (!equal) {
provisionOutputLogs.push('Profiles did not match after download');
return outputMsg();
await processOutput();
return;
}

// Update the JSON output with the downloaded profiles
// Success case
success = true;
console.log(`${os.EOL}Provisioning complete for EID ${eid}`);
provisionOutputLogs.push(`${os.EOL}Provisioning complete for EID ${eid}`);
return outputMsg();
await processOutput();
return;
} catch (error) {
provisionOutputLogs.push(`Error during provisioning: ${error.message}`);
return outputMsg();
await processOutput();
return;
}
}

Expand All @@ -221,9 +229,6 @@ module.exports = class ESimCommands extends CLICommandBase {
if (!args.input) {
throw new Error('Missing input json file');
}
if (!args.output) {
throw new Error('Missing input output json file');
}
if (!args.lpa) {
throw new Error('Missing input LPA tool path');
}
Expand All @@ -234,7 +239,7 @@ module.exports = class ESimCommands extends CLICommandBase {
const input = fs.readFileSync(this.inputJson);
this.inputJsonData = JSON.parse(input);

this.outputFolder = args.output;
this.outputFolder = args.output || 'esim_loading_logs';
this.lpa = args.lpa;
this.binaries = args.binary;
}
Expand Down Expand Up @@ -396,9 +401,35 @@ module.exports = class ESimCommands extends CLICommandBase {
}
}

// Get the profiles that match the EID from the input JSON
_getProfiles(eid) {
// Get the profile list that matches the EID that is given by the field eid
// // Get the profiles that match the EID from the input JSON
// _getProfiles(eid) {
// // Get the profile list that matches the EID that is given by the field eid
// let outputLogs = [];
// const logAndPush = (message) => {
// const messages = Array.isArray(message) ? message : [message];
// messages.forEach(msg => {
// outputLogs.push(msg);
// if (this.verbose) {
// console.log(msg);
// }
// });
// };
// logAndPush(`${os.EOL}Getting profiles for EID ${eid}...`);
// const eidBlock = this.inputJsonData.provisioning_data.find((block) => block.esim_id === eid);

// if (!eidBlock || !eidBlock.profiles || eidBlock.profiles.length === 0) {
// logAndPush('No profiles found for the given EID in the input JSON');
// return { success: false, output: outputLogs };
// }

// return { success: true, profiles: eidBlock?.profiles, output: outputLogs };
// }

// take the first element from availableProvisioningData
// if availableProvisioningData is empty, logAndPush success false - no more profiles to provision
// remove it from availableProvisioningData
// return the data from inputJsonData at that index
_getProfiles() {
let outputLogs = [];
const logAndPush = (message) => {
const messages = Array.isArray(message) ? message : [message];
Expand All @@ -409,15 +440,15 @@ module.exports = class ESimCommands extends CLICommandBase {
}
});
};
logAndPush(`${os.EOL}Getting profiles for EID ${eid}...`);
const eidBlock = this.inputJsonData.provisioning_data.find((block) => block.esim_id === eid);

if (!eidBlock || !eidBlock.profiles || eidBlock.profiles.length === 0) {
logAndPush('No profiles found for the given EID in the input JSON');
logAndPush(`${os.EOL}Getting profiles...`);
if (this.availableProvisioningData.size === 0) {
logAndPush('No more profiles to provision');
return { success: false, output: outputLogs };
}

return { success: true, profiles: eidBlock?.profiles, output: outputLogs };
const index = this.availableProvisioningData.values().next().value;
const profiles = this.inputJsonData.provisioning_data[index].profiles;
this.availableProvisioningData.delete(index);
return { success: true, profiles, output: outputLogs };
}

// Download profiles to the device
Expand Down

0 comments on commit e3abb1c

Please sign in to comment.