forked from open-telemetry/opentelemetry-demo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcharge.js
103 lines (79 loc) · 3.34 KB
/
charge.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
const { context, propagation, trace, metrics } = require('@opentelemetry/api');
const cardValidator = require('simple-card-validator');
const { v4: uuidv4 } = require('uuid');
const { OpenFeature } = require('@openfeature/server-sdk');
const { FlagdProvider } = require('@openfeature/flagd-provider');
const flagProvider = new FlagdProvider();
const logger = require('./logger');
const chargeHooks = require("./charge-hooks");
const tracer = trace.getTracer('payment');
const meter = metrics.getMeter('payment');
const transactionsCounter = meter.createCounter('app.payment.transactions');
const LOYALTY_LEVEL = ['platinum', 'gold', 'silver', 'bronze'];
/** Return random element from given array */
function random(arr) {
const index = Math.floor(Math.random() * arr.length);
return arr[index];
}
module.exports.charge = async request => {
const ch = new chargeHooks(request);
// call any fork hooks before starting span
ch.preHook();
const span = tracer.startSpan('charge');
// call any fork hooks after starting span
ch.startHook();
await OpenFeature.setProviderAndWait(flagProvider);
const numberVariant = await OpenFeature.getClient().getNumberValue("paymentFailure", 0);
if (numberVariant > 0) {
// n% chance to fail with app.loyalty.level=gold
if (Math.random() < numberVariant) {
span.setAttributes({'app.loyalty.level': 'gold' });
span.end();
throw new Error('Payment request failed. Invalid token. app.loyalty.level=gold');
}
}
const {
creditCardNumber: number,
creditCardExpirationYear: year,
creditCardExpirationMonth: month
} = request.creditCard;
const currentMonth = new Date().getMonth() + 1;
const currentYear = new Date().getFullYear();
const lastFourDigits = number.substr(-4);
const transactionId = uuidv4();
const card = cardValidator(number);
const { card_type: cardType, valid } = card.getCardDetails();
const loyalty_level = random(LOYALTY_LEVEL);
span.setAttributes({
'app.payment.card_type': cardType,
'app.payment.card_valid': valid,
'app.loyalty.level': loyalty_level
});
if (!valid) {
throw new Error('Credit card info is invalid.');
}
if (!['visa', 'mastercard'].includes(cardType)) {
throw new Error(`Sorry, we cannot process ${cardType} credit cards. Only VISA or MasterCard is accepted.`);
}
if ((currentYear * 12 + currentMonth) > (year * 12 + month)) {
throw new Error(`The credit card (ending ${lastFourDigits}) expired on ${month}/${year}.`);
}
// Check baggage for synthetic_request=true, and add charged attribute accordingly
const baggage = propagation.getBaggage(context.active());
if (baggage && baggage.getEntry('synthetic_request') && baggage.getEntry('synthetic_request').value === 'true') {
span.setAttribute('app.payment.charged', false);
} else {
span.setAttribute('app.payment.charged', true);
}
const { units, nanos, currencyCode } = request.amount;
logger.info({ transactionId, cardType, lastFourDigits, amount: { units, nanos, currencyCode }, loyalty_level }, 'Transaction complete.');
transactionsCounter.add(1, { 'app.payment.currency': currencyCode });
// call any fork hooks before ending span
ch.endHook();
span.end();
// call any fork hooks after ending span
ch.postHook();
return { transactionId };
};