Skip to content

Commit

Permalink
Merge pull request #11 from SimformSolutionsPvtLtd/develop
Browse files Browse the repository at this point in the history
Release v1.0.2
  • Loading branch information
ravir-simform authored Jan 24, 2025
2 parents 5632e1f + 3c71c18 commit 35a877a
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 60 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ npm install -g simform-pocket-cli
## Distribution

```bash
pocket distribute --applicationId "yourApplicationID" --buildPath "yourBuildPath" --appToken "YourAppToken" --baseUrl "base url of the server" --releaseNotes "formatted release notes"
pocket distribute --applicationId "yourApplicationID" --buildPath "yourBuildPath" --appToken "YourAppToken" --releaseNotes "formatted release notes"
```

## Example

```bash
pocket distribute --applicationId "<yourApplicationId>" --buildPath "<yourPath>/Downloads/app-release.apk" --appToken "<yourAppToken>" --baseUrl "<yourBaseUrl>/functions/v1/" --releaseNotes "formatted release notes"
pocket distribute --applicationId "<yourApplicationId>" --buildPath "<yourPath>/Downloads/app-release.apk" --appToken "<yourAppToken>" --releaseNotes "formatted release notes"
```

## How to get Application ID and App Token
Expand Down
8 changes: 1 addition & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "simform-pocket-cli",
"version": "1.0.1",
"version": "1.0.2",
"description": "Pocket Deploy command-line utility",
"homepage": "https://github.com/SimformSolutionsPvtLtd/pocket-cli/#readme",
"author": "Simform Solutions",
Expand All @@ -23,16 +23,10 @@
"/dist"
],
"dependencies": {
"@plist/parse": "1.1.0",
"axios": "^1.7.9",
"bplist-parser": "0.3.2",
"build-info-parser": "1.0.0",
"bytebuffer": "5.0.1",
"cgbi-to-png": "1.0.7",
"form-data": "^4.0.1",
"isomorphic-unzip": "1.1.5",
"jsonwebtoken": "9.0.2",
"save": "^2.4.0",
"yargs": "^17.7.2"
},
"devDependencies": {
Expand Down
3 changes: 2 additions & 1 deletion src/ApiConst.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export default {
deployAppToPocketDeploy: 'deployAppToPocketDeploy'
deployAppToPocketDeploy: 'deployAppToPocketDeploy',
buildsExist: 'buildsExist'
};
2 changes: 1 addition & 1 deletion src/AppConst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ export default {
appDefaultPackage: 'com.default',
appDefaultVersion: '1.0',
appDefaultVersionCode: 1,
maximumFileSize: 100 // 100MB
chunkSize: 100 // In Bytes
};
145 changes: 98 additions & 47 deletions src/deployTheApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,13 @@ import FormData from 'form-data';
import ApiConst from './ApiConst';
import AppConst from './AppConst';
import { getApkName } from './CommonUtils';

const FileType = {
Apk: 'apk',
Ipa: 'ipa'
};

const FileContentType = {
Ipa: 'application/octet-stream',
Apk: 'application/vnd.android.package-archive'
};
import jwt from 'jsonwebtoken';
import {
AppPlatform,
DecodedToken,
FileContentType,
FileType
} from './types/CommonTypes';

/**
* Extract the build data from the file
Expand Down Expand Up @@ -83,7 +80,7 @@ const deployApp = async (
applicationId: string,
buildPath: string,
appToken: any,
baseUrl: string,
baseUrl?: string,
releaseNotes?: string
) => {
// Use applicationId and buildPath in your deployment logic
Expand All @@ -102,73 +99,127 @@ const deployApp = async (
console.error('App token is missing');
process.exit(1);
}
if (!baseUrl) {
console.error('Base URL is missing');

const decodedToken = jwt.decode(appToken) as DecodedToken;

const decodedApplicationId = decodedToken ? decodedToken.app : '';

if (applicationId !== decodedApplicationId) {
console.error('Application ID does not match the application token.');
process.exit(1);
}

const decodedBaseUrl = decodedToken?.baseUrl;
const currentUrl = baseUrl || decodedBaseUrl;

if (!currentUrl) {
console.error('Base URL is missing');
process.exit(1);
}
const fileType = buildPath?.split('.')?.pop() ?? FileType.Apk;

const currentFileContentType =
fileType === FileType.Ipa ? FileContentType.Ipa : FileContentType.Apk;

const fileBuffer = fs.readFileSync(buildPath);

const formData = new FormData();
const chunkSize = AppConst.chunkSize * 1024 * 1024; // 100MB

const fileSize = fs.statSync(buildPath).size;

const totalChunks = Math.ceil(fileSize / chunkSize);

const fileStream = fs.createReadStream(buildPath, {
highWaterMark: chunkSize
});

let chunkNumber = 1;

const blobData = new Blob([fileBuffer], {
type: currentFileContentType
});

if (blobData?.size > AppConst.maximumFileSize * 1024 * 1024) {
throw new Error(
`File size exceeds the allowed limit of ${AppConst.maximumFileSize} MB.`
);
}

try {
console.log('Processing build...');
const buildInfo = await fileDataExtract(buildPath, fileType, blobData);

formData.append('appToken', appToken);
formData.append('currentFileContentType', currentFileContentType);
formData.append('baseUrl', baseUrl);
formData.append('applicationId', applicationId);
formData.append('buildInfo', JSON.stringify(buildInfo));
// Check if the build already exists
const buildExistResponse = await axios.post(
`${currentUrl}/${ApiConst.buildsExist}`,
{
application_id: applicationId,
version_code: buildInfo.versionCode?.toString(),
version_name: buildInfo.versionName?.toString(),
platform:
buildInfo.fileType === FileType.Ipa
? AppPlatform.IOS
: AppPlatform.Android
},
{
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${appToken}`
}
}
);

if (releaseNotes) {
releaseNotes = `<pre>${releaseNotes}</pre>`;
formData.append('releaseNotes', releaseNotes);
if (buildExistResponse.status === 409) {
return buildExistResponse;
}

const fileStream = fs.createReadStream(buildPath);
for await (const chunk of fileStream) {
const formData = new FormData();

fileStream.on('error', err => {
console.error('Error reading the file:', err);
});
formData.append('applicationId', applicationId);
formData.append('buildInfo', JSON.stringify(buildInfo));
formData.append('currentFileContentType', currentFileContentType);
formData.append('baseUrl', currentUrl);
formData.append('appToken', appToken);

formData.append('file', fileStream, {
contentType: currentFileContentType,
filename: `${AppConst.appDefaultName}.${fileType}`
});
if (releaseNotes) {
formData.append('releaseNotes', `<pre>${releaseNotes}</pre>`);
}

console.log('deployAppToPocketDeploy');
const response = await axios.post(
`${baseUrl}${ApiConst.deployAppToPocketDeploy}`,
formData,
{
headers: {
...formData.getHeaders(),
Authorization: `Bearer ${appToken}`
fileStream.on('error', err => {
console.error('Error reading the file:', err);
});
// Add current chunk
formData.append('file', chunk, {
contentType: currentFileContentType,
filename: `chunk-${chunkNumber}`
});

// Add chunk metadata
formData.append('chunkNumber', chunkNumber);
formData.append('totalChunks', totalChunks);

const response = await axios.post(
`${currentUrl}/${ApiConst.deployAppToPocketDeploy}`,
formData,
{
headers: {
...formData.getHeaders(),
Authorization: `Bearer ${appToken}`
}
}
);

if (response.status === 200) {
const percentage = Math.floor((chunkNumber / totalChunks) * 100);
console.log(`Upload Progress: ${percentage}%`);

// Increment the chunk number
chunkNumber++;
} else {
throw new Error(`Failed to upload build`);
}
);
}

console.log('Build Uploaded successfully');
return response;
return;
} catch (error) {
console.error(
'Error during post-build process:',
'Error during uploading the build:',
error.response?.data ?? error
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/distribute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ yargs(hideBin(process.argv))
},
baseUrl: {
type: 'string',
demandOption: true,
demandOption: false,
describe: 'The base URL of the server.'
},
releaseNotes: {
Expand All @@ -37,7 +37,7 @@ yargs(hideBin(process.argv))
describe: 'Enter your Release Notes for this version.'
}
},
async (argv) => {
async argv => {
await deployApp(
argv.applicationId,
argv.buildPath,
Expand Down
22 changes: 22 additions & 0 deletions src/types/CommonTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export interface DecodedToken {
exp?: number; // Expiration time
sub?: string;
email?: string;
app?: string;
baseUrl?: string;
}

export enum FileType {
Apk = 'apk',
Ipa = 'ipa'
}

export enum AppPlatform {
Android = 'android',
IOS = 'ios'
}

export enum FileContentType {
Ipa = 'application/octet-stream',
Apk = 'application/vnd.android.package-archive'
}

0 comments on commit 35a877a

Please sign in to comment.