@@ -30,11 +30,13 @@ module.exports = class ESimCommands extends CLICommandBase {
30
30
this . downloadedProfiles = [ ] ;
31
31
this . binaries = null ;
32
32
this . verbose = false ;
33
+ this . availableProvisioningData = new Set ( ) ;
33
34
}
34
35
35
36
async provisionCommand ( args ) {
36
37
this . verbose = true ;
37
38
this . _validateArgs ( args ) ;
39
+ await this . _generateAvailableProvisioningData ( ) ;
38
40
39
41
// Get the serial port and device details
40
42
const devices = await this . serial . findDevices ( ) ;
@@ -45,14 +47,12 @@ module.exports = class ESimCommands extends CLICommandBase {
45
47
throw new Error ( errorMessage ) ;
46
48
}
47
49
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 ) ;
52
51
}
53
52
54
53
async bulkProvisionCommand ( args ) {
55
54
this . _validateArgs ( args ) ;
55
+ await this . _generateAvailableProvisioningData ( ) ;
56
56
57
57
const provisionedDevices = new Set ( ) ;
58
58
setInterval ( async ( ) => {
@@ -62,28 +62,49 @@ module.exports = class ESimCommands extends CLICommandBase {
62
62
const deviceId = device . deviceId ;
63
63
provisionedDevices . add ( deviceId ) ;
64
64
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 ) ;
69
67
}
70
68
}
71
69
} , 1000 ) ;
72
70
73
71
console . log ( 'Ready to bulk provision. Connect devices to start. Press Ctrl-C to exit.' ) ;
74
72
}
75
73
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
+
76
96
async doProvision ( device ) {
77
97
let provisionOutputLogs = [ ] ;
78
98
let eid = null ;
79
- let timestamp = null ;
99
+ let timestamp = new Date ( ) . toISOString ( ) ;
80
100
let expectedProfilesArray = [ ] ;
81
101
let downloadedProfilesArray = [ ] ;
82
102
let success = false ;
103
+ const outputJsonFile = path . join ( this . outputFolder , `${ device . deviceId } -${ timestamp } .json` ) ;
83
104
84
105
// Add the output logs to the output JSON file in one msg
85
- const outputMsg = ( ) => {
86
- return {
106
+ const processOutput = async ( ) => {
107
+ const resp = {
87
108
esim_id : eid ,
88
109
device_id : device . deviceId ,
89
110
expectedProfiles : expectedProfilesArray ,
@@ -92,10 +113,11 @@ module.exports = class ESimCommands extends CLICommandBase {
92
113
timestamp : timestamp ,
93
114
output : provisionOutputLogs
94
115
} ;
116
+ await this . _changeLed ( device , resp . success ? PROVISIONING_SUCCESS : PROVISIONING_FAILURE ) ;
117
+ this . _addToJson ( outputJsonFile , resp ) ;
95
118
} ;
96
119
97
120
try {
98
- timestamp = new Date ( ) . toISOString ( ) ;
99
121
const platform = platformForId ( device . specs . productId ) . name ;
100
122
const port = device . port ;
101
123
@@ -105,66 +127,48 @@ module.exports = class ESimCommands extends CLICommandBase {
105
127
const flashResp = await this . _flashATPassThroughFirmware ( device , platform ) ;
106
128
provisionOutputLogs . push ( ...flashResp . output ) ;
107
129
if ( ! flashResp . success ) {
108
- return outputMsg ( ) ;
130
+ await processOutput ( ) ;
131
+ return ;
109
132
}
110
133
provisionOutputLogs . push ( `${ os . EOL } Firmware flashed successfully` ) ;
111
134
112
135
// Get the EID
113
136
const eidResp = await this . _getEid ( port ) ;
114
137
provisionOutputLogs . push ( ...eidResp . output ) ;
115
138
if ( ! eidResp . success ) {
116
- return outputMsg ( ) ;
139
+ await processOutput ( ) ;
140
+ return ;
117
141
}
118
142
eid = ( eidResp . eid ) . trim ( ) ;
119
143
provisionOutputLogs . push ( `EID: ${ eid } ` ) ;
120
144
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
131
147
const profileCmdResp = await this . _checkForExistingProfiles ( port ) ;
132
148
provisionOutputLogs . push ( ...profileCmdResp . output ) ;
133
149
if ( ! profileCmdResp . success ) {
134
- return outputMsg ( ) ;
150
+ await processOutput ( ) ;
151
+ return ;
135
152
}
136
153
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 ;
159
159
}
160
160
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 ( ) ;
163
163
provisionOutputLogs . push ( ...profileResp . output ) ;
164
164
if ( ! profileResp . success ) {
165
- return outputMsg ( ) ;
165
+ await processOutput ( ) ;
166
+ return ;
166
167
}
167
168
169
+ expectedProfilesArray = profileResp . profiles ; // TODO: test this
170
+ const expectedIccids = profileResp . profiles . map ( ( profile ) => profile . iccid ) ;
171
+
168
172
provisionOutputLogs . push ( `${ os . EOL } Provisioning the following profiles to EID ${ eid } :` ) ;
169
173
170
174
const profiles = profileResp . profiles ;
@@ -191,26 +195,30 @@ module.exports = class ESimCommands extends CLICommandBase {
191
195
192
196
if ( ! downloadResp . success ) {
193
197
provisionOutputLogs . push ( 'Profile download failed' ) ;
194
- return outputMsg ( ) ;
198
+ await processOutput ( ) ;
199
+ return ;
195
200
}
196
201
197
202
const profilesOnDeviceAfterDownload = await this . _listProfiles ( port ) ;
198
203
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 ) ) ;
200
205
if ( ! equal ) {
201
206
provisionOutputLogs . push ( 'Profiles did not match after download' ) ;
202
- return outputMsg ( ) ;
207
+ await processOutput ( ) ;
208
+ return ;
203
209
}
204
210
205
211
// Update the JSON output with the downloaded profiles
206
212
// Success case
207
213
success = true ;
208
214
console . log ( `${ os . EOL } Provisioning complete for EID ${ eid } ` ) ;
209
215
provisionOutputLogs . push ( `${ os . EOL } Provisioning complete for EID ${ eid } ` ) ;
210
- return outputMsg ( ) ;
216
+ await processOutput ( ) ;
217
+ return ;
211
218
} catch ( error ) {
212
219
provisionOutputLogs . push ( `Error during provisioning: ${ error . message } ` ) ;
213
- return outputMsg ( ) ;
220
+ await processOutput ( ) ;
221
+ return ;
214
222
}
215
223
}
216
224
@@ -221,9 +229,6 @@ module.exports = class ESimCommands extends CLICommandBase {
221
229
if ( ! args . input ) {
222
230
throw new Error ( 'Missing input json file' ) ;
223
231
}
224
- if ( ! args . output ) {
225
- throw new Error ( 'Missing input output json file' ) ;
226
- }
227
232
if ( ! args . lpa ) {
228
233
throw new Error ( 'Missing input LPA tool path' ) ;
229
234
}
@@ -234,7 +239,7 @@ module.exports = class ESimCommands extends CLICommandBase {
234
239
const input = fs . readFileSync ( this . inputJson ) ;
235
240
this . inputJsonData = JSON . parse ( input ) ;
236
241
237
- this . outputFolder = args . output ;
242
+ this . outputFolder = args . output || 'esim_loading_logs' ;
238
243
this . lpa = args . lpa ;
239
244
this . binaries = args . binary ;
240
245
}
@@ -396,9 +401,9 @@ module.exports = class ESimCommands extends CLICommandBase {
396
401
}
397
402
}
398
403
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 ( ) {
402
407
let outputLogs = [ ] ;
403
408
const logAndPush = ( message ) => {
404
409
const messages = Array . isArray ( message ) ? message : [ message ] ;
@@ -409,15 +414,15 @@ module.exports = class ESimCommands extends CLICommandBase {
409
414
}
410
415
} ) ;
411
416
} ;
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' ) ;
417
420
return { success : false , output : outputLogs } ;
418
421
}
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 } ;
421
426
}
422
427
423
428
// Download profiles to the device
0 commit comments