|
| 1 | +import { Buffer } from 'buffer'; |
| 2 | +import { |
| 3 | + MAX_DESIRED_APP_ORDER_PRICE, |
| 4 | + MAX_DESIRED_WORKERPOOL_ORDER_PRICE, |
| 5 | +} from '../config/config.js'; |
| 6 | +import { handleIfProtocolError, WorkflowError } from '../utils/errors.js'; |
| 7 | +import * as ipfs from '../utils/ipfs-service.js'; |
| 8 | +import { |
| 9 | + addressOrEnsSchema, |
| 10 | + telegramContentSchema, |
| 11 | + positiveNumberSchema, |
| 12 | + labelSchema, |
| 13 | + throwIfMissing, |
| 14 | + senderNameSchema, |
| 15 | +} from '../utils/validators.js'; |
| 16 | +import { GrantedAccess } from './types.js'; |
| 17 | +import { |
| 18 | + DappAddressConsumer, |
| 19 | + DataProtectorConsumer, |
| 20 | + IExecConsumer, |
| 21 | + IpfsGatewayConfigConsumer, |
| 22 | + IpfsNodeConfigConsumer, |
| 23 | +} from './internalTypes.js'; |
| 24 | +import { AddressOrENS, BulkRequest } from '@iexec/dataprotector'; |
| 25 | + |
| 26 | +export type PrepareTelegramCampaign = typeof prepareTelegramCampaign; |
| 27 | + |
| 28 | +export type PrepareTelegramCampaignParams = { |
| 29 | + /** |
| 30 | + * Granted access to process in bulk. |
| 31 | + * use `fetchMyContacts({ bulkOnly: true })` to get granted accesses. |
| 32 | + * if not provided, the single message will be processed. |
| 33 | + */ |
| 34 | + grantedAccess: GrantedAccess[]; |
| 35 | + maxProtectedDataPerTask?: number; |
| 36 | + senderName?: string; |
| 37 | + telegramContent: string; |
| 38 | + label?: string; |
| 39 | + workerpoolAddressOrEns?: AddressOrENS; |
| 40 | + dataMaxPrice?: number; |
| 41 | + appMaxPrice?: number; |
| 42 | + workerpoolMaxPrice?: number; |
| 43 | +}; |
| 44 | + |
| 45 | +export type PrepareTelegramCampaignResponse = { |
| 46 | + campaignRequest: BulkRequest; |
| 47 | +}; |
| 48 | + |
| 49 | +export const prepareTelegramCampaign = async ({ |
| 50 | + iexec = throwIfMissing(), |
| 51 | + dataProtector = throwIfMissing(), |
| 52 | + workerpoolAddressOrEns = throwIfMissing(), |
| 53 | + dappAddressOrENS, |
| 54 | + ipfsNode, |
| 55 | + ipfsGateway, |
| 56 | + senderName, |
| 57 | + telegramContent, |
| 58 | + label, |
| 59 | + appMaxPrice = MAX_DESIRED_APP_ORDER_PRICE, |
| 60 | + workerpoolMaxPrice = MAX_DESIRED_WORKERPOOL_ORDER_PRICE, |
| 61 | + grantedAccess, |
| 62 | + maxProtectedDataPerTask, |
| 63 | +}: IExecConsumer & |
| 64 | + DappAddressConsumer & |
| 65 | + IpfsNodeConfigConsumer & |
| 66 | + IpfsGatewayConfigConsumer & |
| 67 | + DataProtectorConsumer & |
| 68 | + PrepareTelegramCampaignParams): Promise<PrepareTelegramCampaignResponse> => { |
| 69 | + try { |
| 70 | + const vWorkerpoolAddressOrEns = addressOrEnsSchema() |
| 71 | + .required() |
| 72 | + .label('WorkerpoolAddressOrEns') |
| 73 | + .validateSync(workerpoolAddressOrEns); |
| 74 | + const vSenderName = senderNameSchema() |
| 75 | + .label('senderName') |
| 76 | + .validateSync(senderName); |
| 77 | + const vTelegramContent = telegramContentSchema() |
| 78 | + .required() |
| 79 | + .label('telegramContent') |
| 80 | + .validateSync(telegramContent); |
| 81 | + const vLabel = labelSchema().label('label').validateSync(label); |
| 82 | + const vDappAddressOrENS = addressOrEnsSchema() |
| 83 | + .required() |
| 84 | + .label('dappAddressOrENS') |
| 85 | + .validateSync(dappAddressOrENS); |
| 86 | + const vAppMaxPrice = positiveNumberSchema() |
| 87 | + .label('appMaxPrice') |
| 88 | + .validateSync(appMaxPrice); |
| 89 | + const vWorkerpoolMaxPrice = positiveNumberSchema() |
| 90 | + .label('workerpoolMaxPrice') |
| 91 | + .validateSync(workerpoolMaxPrice); |
| 92 | + const vMaxProtectedDataPerTask = positiveNumberSchema() |
| 93 | + .label('maxProtectedDataPerTask') |
| 94 | + .validateSync(maxProtectedDataPerTask); |
| 95 | + |
| 96 | + // TODO: factor this |
| 97 | + // Encrypt telegram content |
| 98 | + const telegramContentEncryptionKey = iexec.dataset.generateEncryptionKey(); |
| 99 | + const encryptedFile = await iexec.dataset |
| 100 | + .encrypt( |
| 101 | + Buffer.from(vTelegramContent, 'utf8'), |
| 102 | + telegramContentEncryptionKey |
| 103 | + ) |
| 104 | + .catch((e) => { |
| 105 | + throw new WorkflowError({ |
| 106 | + message: 'Failed to encrypt message content', |
| 107 | + errorCause: e, |
| 108 | + }); |
| 109 | + }); |
| 110 | + // Push telegram message to IPFS |
| 111 | + const cid = await ipfs |
| 112 | + .add(encryptedFile, { |
| 113 | + ipfsNode, |
| 114 | + ipfsGateway, |
| 115 | + }) |
| 116 | + .catch((e) => { |
| 117 | + throw new WorkflowError({ |
| 118 | + message: 'Failed to upload encrypted telegram content', |
| 119 | + errorCause: e, |
| 120 | + }); |
| 121 | + }); |
| 122 | + const multiaddr = `/ipfs/${cid}`; |
| 123 | + // Prepare secrets for the requester |
| 124 | + // Use a positive integer as secret ID (required by iexec) |
| 125 | + // Using "1" as a fixed ID for the requester secret |
| 126 | + const requesterSecretId = 1; |
| 127 | + const secrets = { |
| 128 | + [requesterSecretId]: JSON.stringify({ |
| 129 | + senderName: vSenderName, |
| 130 | + telegramContentMultiAddr: multiaddr, |
| 131 | + telegramContentEncryptionKey, |
| 132 | + }), |
| 133 | + }; |
| 134 | + // TODO: end factor this |
| 135 | + |
| 136 | + const { bulkRequest: campaignRequest } = |
| 137 | + await dataProtector.prepareBulkRequest({ |
| 138 | + app: vDappAddressOrENS, |
| 139 | + appMaxPrice: vAppMaxPrice, |
| 140 | + workerpoolMaxPrice: vWorkerpoolMaxPrice, |
| 141 | + workerpool: vWorkerpoolAddressOrEns, |
| 142 | + args: vLabel, |
| 143 | + inputFiles: [], |
| 144 | + secrets, |
| 145 | + bulkAccesses: grantedAccess, |
| 146 | + maxProtectedDataPerTask: vMaxProtectedDataPerTask, |
| 147 | + }); |
| 148 | + return { campaignRequest }; |
| 149 | + } catch (error) { |
| 150 | + // Protocol error detected, re-throwing as-is |
| 151 | + if ((error as any)?.isProtocolError === true) { |
| 152 | + throw error; |
| 153 | + } |
| 154 | + // Handle protocol errors - this will throw if it's an ApiCallError |
| 155 | + // handleIfProtocolError transforms ApiCallError into a WorkflowError with isProtocolError=true |
| 156 | + handleIfProtocolError(error); |
| 157 | + // For all other errors |
| 158 | + throw new WorkflowError({ |
| 159 | + message: 'Failed to prepareTelegramCampaign', |
| 160 | + errorCause: error, |
| 161 | + }); |
| 162 | + } |
| 163 | +}; |
0 commit comments