Skip to content

Commit e3f0625

Browse files
committed
Provision the device(s) with the next available provisioning data block from the input json
1 parent ac886ad commit e3f0625

File tree

1 file changed

+74
-69
lines changed

1 file changed

+74
-69
lines changed

src/cmd/esim.js

+74-69
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ module.exports = class ESimCommands extends CLICommandBase {
3030
this.downloadedProfiles = [];
3131
this.binaries = null;
3232
this.verbose = false;
33+
this.availableProvisioningData = new Set();
3334
}
3435

3536
async provisionCommand(args) {
3637
this.verbose = true;
3738
this._validateArgs(args);
39+
await this._generateAvailableProvisioningData();
3840

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

5453
async bulkProvisionCommand(args) {
5554
this._validateArgs(args);
55+
await this._generateAvailableProvisioningData();
5656

5757
const provisionedDevices = new Set();
5858
setInterval(async () => {
@@ -62,28 +62,49 @@ module.exports = class ESimCommands extends CLICommandBase {
6262
const deviceId = device.deviceId;
6363
provisionedDevices.add(deviceId);
6464
console.log(`Device ${deviceId} connected`);
65-
const outputJsonForDevice = path.join(this.outputFolder, `${deviceId}.json`);
66-
const resp = await this.doProvision(device, { verbose: false });
67-
await this._changeLed(device, resp.success ? PROVISIONING_SUCCESS : PROVISIONING_FAILURE);
68-
this._addToJson(outputJsonForDevice, resp);
65+
// Do not await here, so that the next device can be processed
66+
await this.doProvision(device);
6967
}
7068
}
7169
}, 1000);
7270

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

74+
// Populate the availableProvisioningData set with the indices of the input JSON data
75+
// If a profile is already provisioned (output JSON file exists with an entry), remove it from the set
76+
async _generateAvailableProvisioningData() {
77+
const files = fs.readdirSync(this.outputFolder);
78+
const jsonFiles = files.filter((file) => file.endsWith('.json'));
79+
for (let i = 0; i < this.inputJsonData.provisioning_data.length; i++) {
80+
this.availableProvisioningData.add(i);
81+
}
82+
for (const file of jsonFiles) {
83+
const json = fs.readFileSync(path.join(this.outputFolder, file));
84+
const data = JSON.parse(json);
85+
for (const entry of data) {
86+
const index = this.inputJsonData.provisioning_data.findIndex((block) => {
87+
return _.isEqual(block.profiles, entry.expectedProfiles);
88+
});
89+
if (index !== -1) {
90+
this.availableProvisioningData.delete(index);
91+
}
92+
}
93+
}
94+
}
95+
7696
async doProvision(device) {
7797
let provisionOutputLogs = [];
7898
let eid = null;
79-
let timestamp = null;
99+
let timestamp = new Date().toISOString();
80100
let expectedProfilesArray = [];
81101
let downloadedProfilesArray = [];
82102
let success = false;
103+
const outputJsonFile = path.join(this.outputFolder, `${device.deviceId}-${timestamp}.json`);
83104

84105
// Add the output logs to the output JSON file in one msg
85-
const outputMsg = () => {
86-
return {
106+
const processOutput = async () => {
107+
const resp = {
87108
esim_id: eid,
88109
device_id: device.deviceId,
89110
expectedProfiles: expectedProfilesArray,
@@ -92,10 +113,11 @@ module.exports = class ESimCommands extends CLICommandBase {
92113
timestamp: timestamp,
93114
output: provisionOutputLogs
94115
};
116+
await this._changeLed(device, resp.success ? PROVISIONING_SUCCESS : PROVISIONING_FAILURE);
117+
this._addToJson(outputJsonFile, resp);
95118
};
96119

97120
try {
98-
timestamp = new Date().toISOString();
99121
const platform = platformForId(device.specs.productId).name;
100122
const port = device.port;
101123

@@ -105,66 +127,48 @@ module.exports = class ESimCommands extends CLICommandBase {
105127
const flashResp = await this._flashATPassThroughFirmware(device, platform);
106128
provisionOutputLogs.push(...flashResp.output);
107129
if (!flashResp.success) {
108-
return outputMsg();
130+
await processOutput();
131+
return;
109132
}
110133
provisionOutputLogs.push(`${os.EOL}Firmware flashed successfully`);
111134

112135
// Get the EID
113136
const eidResp = await this._getEid(port);
114137
provisionOutputLogs.push(...eidResp.output);
115138
if (!eidResp.success) {
116-
return outputMsg();
139+
await processOutput();
140+
return;
117141
}
118142
eid = (eidResp.eid).trim();
119143
provisionOutputLogs.push(`EID: ${eid}`);
120144

121-
// Get the profiles for this EID and compare them against the list in the input JSON under the same EID
122-
const matchingEsim = this.inputJsonData.provisioning_data.find(item => item.esim_id === eid);
123-
const iccidFromJson = matchingEsim.profiles.map((profile) => profile.iccid);
124-
expectedProfilesArray = matchingEsim.profiles;
125-
126-
if (!matchingEsim || iccidFromJson?.length === 0 || expectedProfilesArray?.length === 0) {
127-
provisionOutputLogs.push('No profiles found for the given EID in the input JSON');
128-
return outputMsg();
129-
}
130-
145+
// If any profiles already exist on the device, skip provisioning
146+
// TODO: Check the TEST PROFILE situation with a brand new eSIM
131147
const profileCmdResp = await this._checkForExistingProfiles(port);
132148
provisionOutputLogs.push(...profileCmdResp.output);
133149
if (!profileCmdResp.success) {
134-
return outputMsg();
150+
await processOutput();
151+
return;
135152
}
136153

137-
const profilesListOnDevice = profileCmdResp.profilesList;
138-
const existingIccids = profilesListOnDevice.map((line) => line.split('[')[1].split(',')[0].trim());
139-
provisionOutputLogs.push(`${os.EOL}profilesListOnDevice: ${profilesListOnDevice}`);
140-
provisionOutputLogs.push(`${os.EOL}existingIccids: ${existingIccids}`);
141-
142-
if (profilesListOnDevice.length > 0) {
143-
// extract the iccids that belong to this EID
144-
const matchingEsim = this.inputJsonData.provisioning_data.find(item => item.esim_id === eid);
145-
if (!matchingEsim) {
146-
provisionOutputLogs.push('No profiles found for the given EID in the input JSON');
147-
return outputMsg();
148-
}
149-
const iccidFromJson = matchingEsim.profiles.map((profile) => profile.iccid);
150-
const equal = _.isEqual(_.sortBy(existingIccids), _.sortBy(iccidFromJson));
151-
if (equal) {
152-
success = true;
153-
provisionOutputLogs.push('Profiles already provisioned correctly on the device for the given EID');
154-
return outputMsg();
155-
} else {
156-
provisionOutputLogs.push('Profiles exist on the device but do not match the profiles in the input JSON');
157-
return outputMsg();
158-
}
154+
if (profileCmdResp.profilesList.length > 0) {
155+
success = false;
156+
provisionOutputLogs.push('Profiles already exist on the device');
157+
await processOutput();
158+
return;
159159
}
160160

161-
// Get profiles for this EID from the input JSON
162-
const profileResp = this._getProfiles(eid);
161+
// Get the next available profile from availableProvisioningData
162+
const profileResp = this._getProfiles();
163163
provisionOutputLogs.push(...profileResp.output);
164164
if (!profileResp.success) {
165-
return outputMsg();
165+
await processOutput();
166+
return;
166167
}
167168

169+
expectedProfilesArray = profileResp.profiles; // TODO: test this
170+
const expectedIccids = profileResp.profiles.map((profile) => profile.iccid);
171+
168172
provisionOutputLogs.push(`${os.EOL}Provisioning the following profiles to EID ${eid}:`);
169173

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

192196
if (!downloadResp.success) {
193197
provisionOutputLogs.push('Profile download failed');
194-
return outputMsg();
198+
await processOutput();
199+
return;
195200
}
196201

197202
const profilesOnDeviceAfterDownload = await this._listProfiles(port);
198203
const iccidsOnDeviceAfterDownload = profilesOnDeviceAfterDownload.map((line) => line.split('[')[1].split(',')[0].trim());
199-
const equal = _.isEqual(_.sortBy(iccidsOnDeviceAfterDownload), _.sortBy(iccidFromJson));
204+
const equal = _.isEqual(_.sortBy(iccidsOnDeviceAfterDownload), _.sortBy(expectedIccids));
200205
if (!equal) {
201206
provisionOutputLogs.push('Profiles did not match after download');
202-
return outputMsg();
207+
await processOutput();
208+
return;
203209
}
204210

205211
// Update the JSON output with the downloaded profiles
206212
// Success case
207213
success = true;
208214
console.log(`${os.EOL}Provisioning complete for EID ${eid}`);
209215
provisionOutputLogs.push(`${os.EOL}Provisioning complete for EID ${eid}`);
210-
return outputMsg();
216+
await processOutput();
217+
return;
211218
} catch (error) {
212219
provisionOutputLogs.push(`Error during provisioning: ${error.message}`);
213-
return outputMsg();
220+
await processOutput();
221+
return;
214222
}
215223
}
216224

@@ -221,9 +229,6 @@ module.exports = class ESimCommands extends CLICommandBase {
221229
if (!args.input) {
222230
throw new Error('Missing input json file');
223231
}
224-
if (!args.output) {
225-
throw new Error('Missing input output json file');
226-
}
227232
if (!args.lpa) {
228233
throw new Error('Missing input LPA tool path');
229234
}
@@ -234,7 +239,7 @@ module.exports = class ESimCommands extends CLICommandBase {
234239
const input = fs.readFileSync(this.inputJson);
235240
this.inputJsonData = JSON.parse(input);
236241

237-
this.outputFolder = args.output;
242+
this.outputFolder = args.output || 'esim_loading_logs';
238243
this.lpa = args.lpa;
239244
this.binaries = args.binary;
240245
}
@@ -396,9 +401,9 @@ module.exports = class ESimCommands extends CLICommandBase {
396401
}
397402
}
398403

399-
// Get the profiles that match the EID from the input JSON
400-
_getProfiles(eid) {
401-
// Get the profile list that matches the EID that is given by the field eid
404+
// Get the next available profile from availableProvisioningData
405+
// Once a profile is fetched, remove it from the set so other devices don't get the same profile
406+
_getProfiles() {
402407
let outputLogs = [];
403408
const logAndPush = (message) => {
404409
const messages = Array.isArray(message) ? message : [message];
@@ -409,15 +414,15 @@ module.exports = class ESimCommands extends CLICommandBase {
409414
}
410415
});
411416
};
412-
logAndPush(`${os.EOL}Getting profiles for EID ${eid}...`);
413-
const eidBlock = this.inputJsonData.provisioning_data.find((block) => block.esim_id === eid);
414-
415-
if (!eidBlock || !eidBlock.profiles || eidBlock.profiles.length === 0) {
416-
logAndPush('No profiles found for the given EID in the input JSON');
417+
logAndPush(`${os.EOL}Getting profiles...`);
418+
if (this.availableProvisioningData.size === 0) {
419+
logAndPush('No more profiles to provision');
417420
return { success: false, output: outputLogs };
418421
}
419-
420-
return { success: true, profiles: eidBlock?.profiles, output: outputLogs };
422+
const index = this.availableProvisioningData.values().next().value;
423+
const profiles = this.inputJsonData.provisioning_data[index].profiles;
424+
this.availableProvisioningData.delete(index);
425+
return { success: true, profiles, output: outputLogs };
421426
}
422427

423428
// Download profiles to the device

0 commit comments

Comments
 (0)