private string sendRemoteMessage(RemoteMessage remoteMsg, int version = 1, byte[] attachmentData = null, string attachmentUrl = null, string attachmentEncoding = null) { remoteMsg.packageName = this.packageName; remoteMsg.remoteApplicationID = remoteApplicationID; remoteMsg.remoteSourceSDK = remoteSourceSDK; remoteMsg.version = version; if (remoteMsg.version > 1) { bool hasAttachmentURI = attachmentUrl != null; bool hasAttachmentData = attachmentData != null; int payloadHelper = 0; if (remoteMsg.attachment != null) { payloadHelper = (remoteMsg.attachment.Length != 0 ? remoteMsg.attachment.Length : 0); } if (remoteMsg.payload != null) { payloadHelper += (remoteMsg.payload.Length != 0 ? remoteMsg.payload.Length : 0); } // maxMessageSizeInChars is controlled by user, make sure it is a positive number or use a reasonable default to avoid infinite loop etc. problems int maxSize = maxMessageSizeInChars <= 0 ? 1000 : maxMessageSizeInChars; bool payloadTooLarge = payloadHelper > maxSize; bool shouldFrag = hasAttachmentURI || payloadTooLarge || hasAttachmentData; if (shouldFrag) { if ((remoteMsg.attachment != null && remoteMsg.attachment.Length > MAX_PAYLOAD_SIZE)) { // Console.WriteLine("Error sending message - payload size is greater than the maximum allowed"); return(null); } int fragmentIndex = 0; string payloadStr = remoteMsg.payload ?? ""; int startIndex = 0; while (startIndex < payloadStr.Length) { int length = (maxSize < payloadStr.Length ? maxSize : payloadStr.Length); string fPayload = payloadStr.Substring(startIndex, length); startIndex += length; bool noAttachmentAvailable = string.IsNullOrEmpty(remoteMsg.attachment); bool noAttachmentUriAvailable = string.IsNullOrEmpty(remoteMsg.attachmentUri); bool lastFragment = payloadStr.Length == 0 && (noAttachmentAvailable && noAttachmentUriAvailable); sendMessageFragment(remoteMsg, fPayload, null, fragmentIndex++, lastFragment); } // now let's fragment the attachment or attachmentData string attach = remoteMsg.attachment; if (attach != null) { if (remoteMsg.attachmentEncoding == "BASE64") { remoteMsg.attachmentEncoding = "BASE64.ATTACHMENT"; int start = 0; while (attach.Length > 0) { string aPayload = attach.Substring(start, maxSize < attach.Length ? maxSize : attach.Length); start += maxSize < attach.Length ? maxSize : attach.Length; sendMessageFragment(remoteMsg, null, aPayload, fragmentIndex++, attach.Length == 0); } } else { // TODO: chunk as-is } } else if (attachmentData != null) { int start = 0; int count = attachmentData.Length; remoteMsg.attachmentEncoding = "BASE64.FRAGMENT"; while (start < count) { int length = Math.Min(maxSize, count - start); byte[] chunkData = new byte[length]; Array.Copy(attachmentData, start, chunkData, 0, length); start = start + maxSize; //FRAGMENT Payload string fAttachment = Convert.ToBase64String(chunkData); sendMessageFragment(remoteMsg: remoteMsg, fPayload: null, fAttachment: fAttachment, fragmentIndex: fragmentIndex++, lastFragment: start > count); } } } else //we DON'T need to fragment { // note: attachmentData is always null here because we take earlier if branch "if shouldFrag" when it's not if (attachmentData != null) { string base64string = Convert.ToBase64String(attachmentData); doPrintImage(base64string); } } } return(remoteMsg.id); }
public static RemoteMessage createMessage(Methods meth, MessageTypes msgType, Message payload, string packageName, string remoteSourceSDK, string remoteApplicationID) { RemoteMessage msg = new RemoteMessage(); msg.method = meth; msg.type = msgType; if (null == payload) { payload = new Message(meth); } msg.payload = JsonUtils.serialize(payload); msg.packageName = packageName; msg.remoteSourceSDK = remoteSourceSDK; msg.remoteApplicationID = remoteApplicationID; return msg; }
/// <summary> /// Parse the generic message and figure out which handler should be used for processing /// </summary> /// <param name="message">The message.</param> public void onMessage(string message) { #if DEBUG Console.WriteLine("Received raw message: " + message); #endif RemoteMessage rMessage = null; try { // Note: This handling was changed after the 1.4.2 release to properly suppress uknown messages. // Old versions of the WinSDK will crash with unknown messages, and old versions are still expected to be in customer's hands. // When testing releases, make sure any suppressed errors here are paid proper backwards-compatible attention and tested // Deserialize the message object to a real object rMessage = JsonUtils.DeserializeSdk <RemoteMessage>(message); remoteMessageVersion = Math.Max(remoteMessageVersion, rMessage.version); } catch (Newtonsoft.Json.JsonSerializationException) { // if a remote message can't be parsed, ignore this unknown message; log as appropriate // - and verify backwards compatiblility story since old WinSDK releases will crash // TODO: Log message and exception in new logging } try { // Handle and route known messages appropriately if (rMessage != null) { switch (rMessage.method) { case Methods.BREAK: break; case Methods.ACK: AcknowledgementMessage ackMessage = JsonUtils.DeserializeSdk <AcknowledgementMessage>(rMessage.payload); notifyObserverAck(ackMessage); break; case Methods.CASHBACK_SELECTED: CashbackSelectedMessage cbsMessage = JsonUtils.DeserializeSdk <CashbackSelectedMessage>(rMessage.payload); notifyObserversCashbackSelected(cbsMessage); break; case Methods.DISCOVERY_RESPONSE: DiscoveryResponseMessage drMessage = JsonUtils.DeserializeSdk <DiscoveryResponseMessage>(rMessage.payload); deviceInfo.name = drMessage.name; deviceInfo.serial = drMessage.serial; deviceInfo.model = drMessage.model; notifyObserversDiscoveryResponse(drMessage); break; case Methods.FINISH_CANCEL: FinishCancelMessage finishCancelMessage = JsonUtils.DeserializeSdk <FinishCancelMessage>(rMessage.payload); notifyObserversFinishCancel(finishCancelMessage.requestInfo); break; case Methods.FINISH_OK: FinishOkMessage fokmsg = JsonUtils.DeserializeSdk <FinishOkMessage>(rMessage.payload); notifyObserversFinishOk(fokmsg); break; case Methods.KEY_PRESS: KeyPressMessage kpm = JsonUtils.DeserializeSdk <KeyPressMessage>(rMessage.payload); notifyObserversKeyPressed(kpm); break; case Methods.PARTIAL_AUTH: PartialAuthMessage partialAuth = JsonUtils.DeserializeSdk <PartialAuthMessage>(rMessage.payload); notifyObserversPartialAuth(partialAuth); break; case Methods.CONFIRM_PAYMENT_MESSAGE: setPaymentConfirmationIdle(false); ConfirmPaymentMessage confirmPaymentMessage = JsonUtils.DeserializeSdk <ConfirmPaymentMessage>(rMessage.payload); notifyObserversConfirmPayment(confirmPaymentMessage); break; case Methods.TIP_ADDED: TipAddedMessage tipMessage = JsonUtils.DeserializeSdk <TipAddedMessage>(rMessage.payload); notifyObserversTipAdded(tipMessage); break; case Methods.TX_START_RESPONSE: TxStartResponseMessage txsrm = JsonUtils.DeserializeSdk <TxStartResponseMessage>(rMessage.payload); notifyObserversTxStartResponse(txsrm); break; case Methods.TX_STATE: TxStateMessage txStateMsg = JsonUtils.DeserializeSdk <TxStateMessage>(rMessage.payload); notifyObserversTxState(txStateMsg); break; case Methods.UI_STATE: UiStateMessage uiStateMsg = JsonUtils.DeserializeSdk <UiStateMessage>(rMessage.payload); notifyObserversUiState(uiStateMsg); break; case Methods.VERIFY_SIGNATURE: paymentRejected = false; VerifySignatureMessage vsigMsg = JsonUtils.DeserializeSdk <VerifySignatureMessage>(rMessage.payload); notifyObserversVerifySignature(vsigMsg); break; case Methods.REFUND_RESPONSE: RefundResponseMessage refRespMsg = JsonUtils.DeserializeSdk <RefundResponseMessage>(rMessage.payload); notifyObserversRefundPaymentResponse(refRespMsg); break; case Methods.TIP_ADJUST_RESPONSE: TipAdjustResponseMessage tipAdjustMsg = JsonUtils.DeserializeSdk <TipAdjustResponseMessage>(rMessage.payload); notifyObserversTipAdjusted(tipAdjustMsg); break; case Methods.VAULT_CARD_RESPONSE: VaultCardResponseMessage vcrMsg = JsonUtils.DeserializeSdk <VaultCardResponseMessage>(rMessage.payload); notifyObserversVaultCardResponse(vcrMsg); break; case Methods.CARD_DATA_RESPONSE: ReadCardDataResponseMessage rcdrMsg = JsonUtils.DeserializeSdk <ReadCardDataResponseMessage>(rMessage.payload); notifyObserversReadCardDataResponse(rcdrMsg); break; case Methods.CAPTURE_PREAUTH_RESPONSE: CapturePreAuthResponseMessage carMsg = JsonUtils.DeserializeSdk <CapturePreAuthResponseMessage>(rMessage.payload); notifyObserversCapturePreAuthResponse(carMsg); break; case Methods.CLOSEOUT_RESPONSE: CloseoutResponseMessage crMsg = JsonUtils.DeserializeSdk <CloseoutResponseMessage>(rMessage.payload); notifyObserversCloseoutResponse(crMsg); break; case Methods.RETRIEVE_PENDING_PAYMENTS_RESPONSE: RetrievePendingPaymentsResponseMessage rpprMsg = JsonUtils.DeserializeSdk <RetrievePendingPaymentsResponseMessage>(rMessage.payload); notifyObserversPendingPaymentsResponse(rpprMsg); break; case Methods.ACTIVITY_RESPONSE: ActivityResponseMessage arm = JsonUtils.DeserializeSdk <ActivityResponseMessage>(rMessage.payload); notifyObserversActivityResponse(arm); break; case Methods.ACTIVITY_MESSAGE_FROM_ACTIVITY: ActivityMessageFromActivity amfa = JsonUtils.DeserializeSdk <ActivityMessageFromActivity>(rMessage.payload); notifyObserversActivityMessage(amfa); break; case Methods.RESET_DEVICE_RESPONSE: ResetDeviceResponseMessage rdrm = JsonUtils.DeserializeSdk <ResetDeviceResponseMessage>(rMessage.payload); notifyObserversDeviceReset(rdrm); break; case Methods.RETRIEVE_DEVICE_STATUS_RESPONSE: RetrieveDeviceStatusResponseMessage rdsrm = JsonUtils.DeserializeSdk <RetrieveDeviceStatusResponseMessage>(rMessage.payload); notifyObserversRetrieveDeviceStatusResponse(rdsrm); break; case Methods.PRINT_CREDIT: CreditPrintMessage cpm = JsonUtils.DeserializeSdk <CreditPrintMessage>(rMessage.payload); notifyObserversPrintCredit(cpm); break; case Methods.PRINT_CREDIT_DECLINE: DeclineCreditPrintMessage dcpm = JsonUtils.DeserializeSdk <DeclineCreditPrintMessage>(rMessage.payload); notifyObserversPrintCreditDecline(dcpm); break; case Methods.PRINT_PAYMENT: PaymentPrintMessage ppm = JsonUtils.DeserializeSdk <PaymentPrintMessage>(rMessage.payload); notifyObserversPrintPayment(ppm); break; case Methods.PRINT_PAYMENT_DECLINE: DeclinePaymentPrintMessage dppm = JsonUtils.DeserializeSdk <DeclinePaymentPrintMessage>(rMessage.payload); notifyObserversPrintPaymentDecline(dppm); break; case Methods.PRINT_PAYMENT_MERCHANT_COPY: PaymentPrintMerchantCopyMessage ppmcm = JsonUtils.DeserializeSdk <PaymentPrintMerchantCopyMessage>(rMessage.payload); notifyObserversPrintMerchantCopy(ppmcm); break; case Methods.REFUND_PRINT_PAYMENT: RefundPaymentPrintMessage rppm = JsonUtils.DeserializeSdk <RefundPaymentPrintMessage>(rMessage.payload); notifyObserversPrintRefund(rppm); break; case Methods.RETRIEVE_PAYMENT_RESPONSE: RetrievePaymentResponseMessage rprm = JsonUtils.DeserializeSdk <RetrievePaymentResponseMessage>(rMessage.payload); notifyObserversRetrievePaymentResponse(rprm); break; case Methods.GET_PRINTERS_RESPONSE: RetrievePrintersResponseMessage rtrm = JsonUtils.DeserializeSdk <RetrievePrintersResponseMessage>(rMessage.payload); notifyObserversRetrievePrinterResponse(rtrm); break; case Methods.PRINT_JOB_STATUS_RESPONSE: PrintJobStatusResponseMessage pjsrm = JsonUtils.DeserializeSdk <PrintJobStatusResponseMessage>(rMessage.payload); notifyObserversRetrievePrintJobStatus(pjsrm); break; case Methods.SHOW_RECEIPT_OPTIONS_RESPONSE: ShowReceiptOptionsResponseMessage srorm = JsonUtils.DeserializeSdk <ShowReceiptOptionsResponseMessage>(rMessage.payload); notifyObserverDisplayReceiptOptionsResponse(srorm); break; case Methods.CUSTOMER_PROVIDED_DATA_MESSAGE: notifyObserversCustomerProvidedData(JsonUtils.DeserializeSdk <CustomerProvidedDataResponseMessage>(rMessage.payload)); break; case Methods.VOID_PAYMENT_RESPONSE: VoidPaymentResponseMessage vprm = JsonUtils.DeserializeSdk <VoidPaymentResponseMessage>(rMessage.payload); notifyObserversPaymentVoided(vprm); break; case Methods.REFUND_REQUEST: case Methods.PAYMENT_VOIDED: case Methods.ORDER_ACTION_RESPONSE: case Methods.DISCOVERY_REQUEST: case Methods.ORDER_ACTION_ADD_DISCOUNT: case Methods.ORDER_ACTION_ADD_LINE_ITEM: case Methods.ORDER_ACTION_REMOVE_LINE_ITEM: case Methods.ORDER_ACTION_REMOVE_DISCOUNT: case Methods.PRINT_IMAGE: case Methods.PRINT_TEXT: case Methods.SHOW_ORDER_SCREEN: case Methods.SHOW_PAYMENT_RECEIPT_OPTIONS: case Methods.SHOW_REFUND_RECEIPT_OPTIONS: case Methods.SHOW_CREDIT_RECEIPT_OPTIONS: case Methods.SHOW_THANK_YOU_SCREEN: case Methods.SHOW_WELCOME_SCREEN: case Methods.SIGNATURE_VERIFIED: case Methods.TERMINAL_MESSAGE: case Methods.TX_START: case Methods.VOID_PAYMENT: case Methods.CLOSEOUT_REQUEST: case Methods.VAULT_CARD: case Methods.CARD_DATA: case Methods.CLOVER_DEVICE_LOG_REQUEST: //Outbound no-op break; default: // Messsage Method not recognized or null: usually rMessage.type == MessageTypes.PING instead of normal Command message if (rMessage.type == MessageTypes.PING) { onPing(); } break; } } } catch (Newtonsoft.Json.JsonSerializationException exception) { // if a remote message's details can't be parsed, ignore this misformed/unrecognized message; log as appropriate // - and verify backwards compatiblility story since old WinSDK releases will crash // TODO: Log message and exception in new logging // TODO: Send a warning to the point of sale that a message arrived but failed to parse. Perhaps leverage DeviceError or create a DeviceWarning } }