@chevre/domain 21.1.0-alpha.0 → 21.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/example/src/chevre/aggregateAllEvents2.ts +10 -7
- package/example/src/chevre/aggregateEventReservation.ts +7 -4
- package/example/src/chevre/processPay.ts +7 -4
- package/example/src/chevre/processRegisterMembership.ts +0 -5
- package/example/src/chevre/processRegisterPaymentCard.ts +0 -5
- package/example/src/chevre/processReserve.ts +7 -4
- package/example/src/chevre/redisConfig.ts +24 -0
- package/example/src/chevre/searchEventTicketOffers.ts +9 -6
- package/example/src/chevre/transaction/callOrderMembershipServiceTask.ts +7 -4
- package/example/src/chevre/transaction/orderMembershipService.ts +7 -4
- package/lib/chevre/repo/action/registerServiceInProgress.d.ts +2 -2
- package/lib/chevre/repo/action/registerServiceInProgress.js +19 -53
- package/lib/chevre/repo/confirmationNumber.d.ts +2 -2
- package/lib/chevre/repo/confirmationNumber.js +40 -53
- package/lib/chevre/repo/itemAvailability/screeningEvent.d.ts +3 -3
- package/lib/chevre/repo/itemAvailability/screeningEvent.js +53 -138
- package/lib/chevre/repo/orderNumber.d.ts +2 -2
- package/lib/chevre/repo/orderNumber.js +44 -55
- package/lib/chevre/repo/rateLimit/offer.d.ts +2 -2
- package/lib/chevre/repo/rateLimit/offer.js +6 -45
- package/lib/chevre/repo/serviceOutputIdentifier.d.ts +2 -2
- package/lib/chevre/repo/serviceOutputIdentifier.js +32 -46
- package/lib/chevre/repo/transactionNumber.d.ts +2 -2
- package/lib/chevre/repo/transactionNumber.js +41 -52
- package/lib/chevre/service/task.d.ts +4 -4
- package/package.json +3 -6
- package/example/src/chevre/copyRedisKeys.ts +0 -102
|
@@ -36,34 +36,15 @@ class RedisRepository {
|
|
|
36
36
|
lockIfNotLimitExceeded(lockKey, maximum) {
|
|
37
37
|
return __awaiter(this, void 0, void 0, function* () {
|
|
38
38
|
const key = `${RedisRepository.KEY_PREFIX}:${lockKey.eventId}`;
|
|
39
|
-
yield
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
// Process result
|
|
51
|
-
// Heavy and time consuming operation here
|
|
52
|
-
debug('checking hash count...hashCount:', hashCount);
|
|
53
|
-
if (hashCount + lockKey.offers.length > maximum) {
|
|
54
|
-
reject(new factory.errors.Argument('Event', 'maximumAttendeeCapacity exceeded'));
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
try {
|
|
58
|
-
yield this.lock(lockKey);
|
|
59
|
-
resolve();
|
|
60
|
-
}
|
|
61
|
-
catch (error) {
|
|
62
|
-
reject(error);
|
|
63
|
-
}
|
|
64
|
-
}));
|
|
65
|
-
});
|
|
66
|
-
}));
|
|
39
|
+
yield this.redisClient.watch(key);
|
|
40
|
+
const hashCount = yield this.redisClient.hLen(key);
|
|
41
|
+
// Process result
|
|
42
|
+
// Heavy and time consuming operation here
|
|
43
|
+
debug('checking hash count...hashCount:', hashCount);
|
|
44
|
+
if (hashCount + lockKey.offers.length > maximum) {
|
|
45
|
+
throw new factory.errors.Argument('Event', 'maximumAttendeeCapacity exceeded');
|
|
46
|
+
}
|
|
47
|
+
yield this.lock(lockKey);
|
|
67
48
|
});
|
|
68
49
|
}
|
|
69
50
|
/**
|
|
@@ -77,21 +58,12 @@ class RedisRepository {
|
|
|
77
58
|
const multi = this.redisClient.multi();
|
|
78
59
|
const fields = lockKey.offers.map((offer) => RedisRepository.OFFER2FIELD(offer));
|
|
79
60
|
fields.forEach((field) => {
|
|
80
|
-
multi.
|
|
81
|
-
});
|
|
82
|
-
const results = yield new Promise((resolve, reject) => {
|
|
83
|
-
multi.expireat(key, moment(lockKey.expires)
|
|
84
|
-
.unix())
|
|
85
|
-
.exec((err, reply) => {
|
|
86
|
-
debug('reply:', reply);
|
|
87
|
-
if (err !== null) {
|
|
88
|
-
reject(err);
|
|
89
|
-
}
|
|
90
|
-
else {
|
|
91
|
-
resolve(reply);
|
|
92
|
-
}
|
|
93
|
-
});
|
|
61
|
+
multi.hSetNX(key, field, value);
|
|
94
62
|
});
|
|
63
|
+
const results = yield multi.expireAt(key, moment(lockKey.expires)
|
|
64
|
+
.unix())
|
|
65
|
+
.exec();
|
|
66
|
+
debug('results:', results);
|
|
95
67
|
const lockedFields = [];
|
|
96
68
|
if (Array.isArray(results)) {
|
|
97
69
|
results.slice(0, fields.length)
|
|
@@ -107,19 +79,9 @@ class RedisRepository {
|
|
|
107
79
|
if (!lockedAll) {
|
|
108
80
|
if (lockedFields.length > 0) {
|
|
109
81
|
// 全て仮押さえできなければ仮押さえできたものは解除
|
|
110
|
-
yield
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
.exec((err, reply) => {
|
|
114
|
-
debug('reply:', reply);
|
|
115
|
-
if (err !== null) {
|
|
116
|
-
reject(err);
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
resolve();
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
});
|
|
82
|
+
yield this.redisClient.multi()
|
|
83
|
+
.hDel(key, lockedFields)
|
|
84
|
+
.exec();
|
|
123
85
|
}
|
|
124
86
|
throw new factory.errors.AlreadyInUse('', [], 'Seat number already hold');
|
|
125
87
|
}
|
|
@@ -132,19 +94,10 @@ class RedisRepository {
|
|
|
132
94
|
return __awaiter(this, void 0, void 0, function* () {
|
|
133
95
|
const key = `${RedisRepository.KEY_PREFIX}:${params.eventId}`;
|
|
134
96
|
const field = RedisRepository.OFFER2FIELD(params.offer);
|
|
135
|
-
yield
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
debug('reply:', reply);
|
|
140
|
-
if (err !== null) {
|
|
141
|
-
reject(err);
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
resolve();
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
});
|
|
97
|
+
const reply = yield this.redisClient.multi()
|
|
98
|
+
.hDel(key, field)
|
|
99
|
+
.exec();
|
|
100
|
+
debug('reply:', reply);
|
|
148
101
|
});
|
|
149
102
|
}
|
|
150
103
|
/**
|
|
@@ -153,26 +106,17 @@ class RedisRepository {
|
|
|
153
106
|
findUnavailableOffersByEventId(params) {
|
|
154
107
|
return __awaiter(this, void 0, void 0, function* () {
|
|
155
108
|
const key = `${RedisRepository.KEY_PREFIX}:${params.eventId}`;
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (reply !== null) {
|
|
165
|
-
offers = Object.keys(reply)
|
|
166
|
-
.map((field) => {
|
|
167
|
-
const seatSection = field.split(':')[0];
|
|
168
|
-
const seatNumber = field.split(':')[1];
|
|
169
|
-
return { seatSection, seatNumber };
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
resolve(offers);
|
|
173
|
-
}
|
|
109
|
+
const reply = yield this.redisClient.hGetAll(key);
|
|
110
|
+
let offers = [];
|
|
111
|
+
if (reply !== null) {
|
|
112
|
+
offers = Object.keys(reply)
|
|
113
|
+
.map((field) => {
|
|
114
|
+
const seatSection = field.split(':')[0];
|
|
115
|
+
const seatNumber = field.split(':')[1];
|
|
116
|
+
return { seatSection, seatNumber };
|
|
174
117
|
});
|
|
175
|
-
}
|
|
118
|
+
}
|
|
119
|
+
return offers;
|
|
176
120
|
});
|
|
177
121
|
}
|
|
178
122
|
/**
|
|
@@ -181,20 +125,12 @@ class RedisRepository {
|
|
|
181
125
|
countUnavailableOffers(params) {
|
|
182
126
|
return __awaiter(this, void 0, void 0, function* () {
|
|
183
127
|
const key = `${RedisRepository.KEY_PREFIX}:${params.event.id}`;
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
let fieldCount = 0;
|
|
191
|
-
if (typeof reply === 'number') {
|
|
192
|
-
fieldCount = Number(reply);
|
|
193
|
-
}
|
|
194
|
-
resolve(fieldCount);
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
});
|
|
128
|
+
const reply = yield this.redisClient.hLen(key);
|
|
129
|
+
let fieldCount = 0;
|
|
130
|
+
if (typeof reply === 'number') {
|
|
131
|
+
fieldCount = Number(reply);
|
|
132
|
+
}
|
|
133
|
+
return fieldCount;
|
|
198
134
|
});
|
|
199
135
|
}
|
|
200
136
|
/**
|
|
@@ -202,20 +138,9 @@ class RedisRepository {
|
|
|
202
138
|
*/
|
|
203
139
|
getHolder(params) {
|
|
204
140
|
return __awaiter(this, void 0, void 0, function* () {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
this.redisClient.hget(key, field, (err, result) => {
|
|
209
|
-
debug('result:', err, result);
|
|
210
|
-
if (err !== null) {
|
|
211
|
-
reject(err);
|
|
212
|
-
}
|
|
213
|
-
else {
|
|
214
|
-
// tslint:disable-next-line:no-magic-numbers
|
|
215
|
-
resolve(result);
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
});
|
|
141
|
+
const key = `${RedisRepository.KEY_PREFIX}:${params.eventId}`;
|
|
142
|
+
const field = RedisRepository.OFFER2FIELD(params.offer);
|
|
143
|
+
return this.redisClient.hGet(key, field);
|
|
219
144
|
});
|
|
220
145
|
}
|
|
221
146
|
/**
|
|
@@ -224,29 +149,19 @@ class RedisRepository {
|
|
|
224
149
|
*/
|
|
225
150
|
searchAvailability(params) {
|
|
226
151
|
return __awaiter(this, void 0, void 0, function* () {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
// tslint:disable-next-line:no-magic-numbers
|
|
242
|
-
resolve(params.offers.map((o, index) => {
|
|
243
|
-
const value4offer = result[index];
|
|
244
|
-
return Object.assign(Object.assign({}, o), { availability: (typeof value4offer === 'string')
|
|
245
|
-
? factory.itemAvailability.OutOfStock
|
|
246
|
-
: factory.itemAvailability.InStock });
|
|
247
|
-
}));
|
|
248
|
-
}
|
|
249
|
-
});
|
|
152
|
+
const key = `${RedisRepository.KEY_PREFIX}:${params.eventId}`;
|
|
153
|
+
const fields = params.offers.map((o) => {
|
|
154
|
+
return RedisRepository.OFFER2FIELD(o);
|
|
155
|
+
});
|
|
156
|
+
const result = yield this.redisClient.hmGet(key, fields);
|
|
157
|
+
if (!Array.isArray(result)) {
|
|
158
|
+
throw new factory.errors.ServiceUnavailable(`searchAvailability got non-array: ${typeof result}`);
|
|
159
|
+
}
|
|
160
|
+
return params.offers.map((o, index) => {
|
|
161
|
+
const value4offer = result[index];
|
|
162
|
+
return Object.assign(Object.assign({}, o), { availability: (typeof value4offer === 'string')
|
|
163
|
+
? factory.itemAvailability.OutOfStock
|
|
164
|
+
: factory.itemAvailability.InStock });
|
|
250
165
|
});
|
|
251
166
|
});
|
|
252
167
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RedisClientType } from 'redis';
|
|
2
2
|
/**
|
|
3
3
|
* 注文番号リポジトリ
|
|
4
4
|
*/
|
|
5
5
|
export declare class RedisRepository {
|
|
6
6
|
static REDIS_KEY_PREFIX: string;
|
|
7
7
|
private readonly redisClient;
|
|
8
|
-
constructor(redisClient:
|
|
8
|
+
constructor(redisClient: RedisClientType);
|
|
9
9
|
/**
|
|
10
10
|
* タイムスタンプから発行する
|
|
11
11
|
*/
|
|
@@ -28,61 +28,50 @@ class RedisRepository {
|
|
|
28
28
|
*/
|
|
29
29
|
publishByTimestamp(params) {
|
|
30
30
|
return __awaiter(this, void 0, void 0, function* () {
|
|
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
|
-
orderNumber.slice(11)
|
|
76
|
-
].join('-')}`;
|
|
77
|
-
resolve(orderNumber);
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
// 基本的にありえないフロー
|
|
81
|
-
reject(new factory.errors.ServiceUnavailable('Order number not published'));
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
});
|
|
31
|
+
const projectPrefix = params.project.alternateName
|
|
32
|
+
.toUpperCase();
|
|
33
|
+
const timestamp = moment(params.orderDate)
|
|
34
|
+
.valueOf()
|
|
35
|
+
.toString();
|
|
36
|
+
const now = moment();
|
|
37
|
+
const TTL = moment(params.orderDate)
|
|
38
|
+
.add(1, 'minute') // ミリ秒でカウントしていくので、注文日時後1分で十分
|
|
39
|
+
.diff(now, 'seconds');
|
|
40
|
+
const key = util.format('%s:%s:%s', RedisRepository.REDIS_KEY_PREFIX, projectPrefix, timestamp);
|
|
41
|
+
const results = yield this.redisClient.multi()
|
|
42
|
+
.incr(key)
|
|
43
|
+
.expire(key, TTL)
|
|
44
|
+
.exec();
|
|
45
|
+
if (!Array.isArray(results)) {
|
|
46
|
+
// なぜかresults: nullのことがあるのでハンドリング
|
|
47
|
+
throw new factory.errors.ServiceUnavailable('incr orderNumber result not array');
|
|
48
|
+
}
|
|
49
|
+
// tslint:disable-next-line:no-single-line-block-comment
|
|
50
|
+
/* istanbul ignore else: please write tests */
|
|
51
|
+
if (typeof results[0] === 'number') {
|
|
52
|
+
let orderNumber = timestamp;
|
|
53
|
+
const no = results[0];
|
|
54
|
+
// orderNumber = `${orderNumber}${(`${no}`).slice(-1)}`; // ミリ秒あたり10件以内の注文想定
|
|
55
|
+
orderNumber = `${orderNumber}${no}`;
|
|
56
|
+
// checkdigit
|
|
57
|
+
const cd = cdigit.luhn.compute(orderNumber);
|
|
58
|
+
const cipher = fpe({ password: cd });
|
|
59
|
+
orderNumber = cipher.encrypt(orderNumber);
|
|
60
|
+
orderNumber = `${projectPrefix}${cd}${orderNumber}`;
|
|
61
|
+
orderNumber = `${[
|
|
62
|
+
// tslint:disable-next-line:no-magic-numbers
|
|
63
|
+
orderNumber.slice(0, 4),
|
|
64
|
+
// tslint:disable-next-line:no-magic-numbers
|
|
65
|
+
orderNumber.slice(4, 11),
|
|
66
|
+
// tslint:disable-next-line:no-magic-numbers
|
|
67
|
+
orderNumber.slice(11)
|
|
68
|
+
].join('-')}`;
|
|
69
|
+
return orderNumber;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// 基本的にありえないフロー
|
|
73
|
+
throw new factory.errors.ServiceUnavailable('Order number not published');
|
|
74
|
+
}
|
|
86
75
|
});
|
|
87
76
|
}
|
|
88
77
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { RedisClientType } from 'redis';
|
|
2
2
|
import * as factory from '../../factory';
|
|
3
3
|
/**
|
|
4
4
|
* レート制限キーインターフェース
|
|
@@ -20,7 +20,7 @@ export interface IRateLimitKey {
|
|
|
20
20
|
export declare class RedisRepository {
|
|
21
21
|
static KEY_PREFIX: string;
|
|
22
22
|
private readonly redisClient;
|
|
23
|
-
constructor(redisClient:
|
|
23
|
+
constructor(redisClient: RedisClientType);
|
|
24
24
|
static CREATE_REDIS_KEY(ratelimitKey: IRateLimitKey): string;
|
|
25
25
|
/**
|
|
26
26
|
* ロックする
|
|
@@ -44,20 +44,10 @@ class RedisRepository {
|
|
|
44
44
|
let multi = this.redisClient.multi();
|
|
45
45
|
datasets.forEach((dataset) => {
|
|
46
46
|
debug('setting if not exist...', dataset.key);
|
|
47
|
-
multi.
|
|
47
|
+
multi.setNX(dataset.key, dataset.value)
|
|
48
48
|
.expire(dataset.key, dataset.ttl);
|
|
49
49
|
});
|
|
50
|
-
const results = yield
|
|
51
|
-
multi.exec((err, reply) => {
|
|
52
|
-
debug('reply:', reply);
|
|
53
|
-
if (err !== null) {
|
|
54
|
-
reject(err);
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
resolve(reply);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
});
|
|
50
|
+
const results = yield multi.exec();
|
|
61
51
|
const lockedFields = [];
|
|
62
52
|
results.forEach((r, index) => {
|
|
63
53
|
debug('r, index:', r, index);
|
|
@@ -78,17 +68,7 @@ class RedisRepository {
|
|
|
78
68
|
debug('deleting...', key);
|
|
79
69
|
multi.del(key);
|
|
80
70
|
});
|
|
81
|
-
yield
|
|
82
|
-
multi.exec((err, reply) => {
|
|
83
|
-
debug('reply:', reply);
|
|
84
|
-
if (err !== null) {
|
|
85
|
-
reject(err);
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
resolve();
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
});
|
|
71
|
+
yield multi.exec();
|
|
92
72
|
}
|
|
93
73
|
throw new factory.errors.RateLimitExceeded('Offer');
|
|
94
74
|
}
|
|
@@ -102,32 +82,13 @@ class RedisRepository {
|
|
|
102
82
|
debug('deleting...', key);
|
|
103
83
|
multi.del(key);
|
|
104
84
|
});
|
|
105
|
-
yield
|
|
106
|
-
multi.exec((err, reply) => {
|
|
107
|
-
debug('reply:', reply);
|
|
108
|
-
if (err !== null) {
|
|
109
|
-
reject(err);
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
resolve();
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
});
|
|
85
|
+
yield multi.exec();
|
|
116
86
|
});
|
|
117
87
|
}
|
|
118
88
|
getHolder(ratelimitKey) {
|
|
119
89
|
return __awaiter(this, void 0, void 0, function* () {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
this.redisClient.get(key, (err, result) => {
|
|
123
|
-
if (err !== null) {
|
|
124
|
-
reject(err);
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
resolve(result);
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
});
|
|
90
|
+
const key = RedisRepository.CREATE_REDIS_KEY(ratelimitKey);
|
|
91
|
+
return this.redisClient.get(key);
|
|
131
92
|
});
|
|
132
93
|
}
|
|
133
94
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { RedisClientType } from 'redis';
|
|
2
2
|
/**
|
|
3
3
|
* サービスアウトプット識別子リポジトリ
|
|
4
4
|
*/
|
|
5
5
|
export declare class RedisRepository {
|
|
6
6
|
static REDIS_KEY_PREFIX: string;
|
|
7
7
|
private readonly redisClient;
|
|
8
|
-
constructor(redisClient:
|
|
8
|
+
constructor(redisClient: RedisClientType);
|
|
9
9
|
/**
|
|
10
10
|
* タイムスタンプから発行する
|
|
11
11
|
*/
|
|
@@ -30,52 +30,38 @@ class RedisRepository {
|
|
|
30
30
|
*/
|
|
31
31
|
publishByTimestamp(params) {
|
|
32
32
|
return __awaiter(this, void 0, void 0, function* () {
|
|
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
|
-
const cd = cdigit.luhn.compute(identifier);
|
|
66
|
-
const cipher = fpe({ password: cd });
|
|
67
|
-
identifier = cipher.encrypt(identifier);
|
|
68
|
-
debug('publishing serviceOutputIdentifier from', timestamp, no, cd);
|
|
69
|
-
identifier = `${cd}${identifier}`;
|
|
70
|
-
resolve(identifier);
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
// 基本的にありえないフロー
|
|
74
|
-
reject(new factory.errors.ServiceUnavailable('ServiceOutput identifier not published'));
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
});
|
|
33
|
+
const timestamp = moment(params.startDate)
|
|
34
|
+
.valueOf()
|
|
35
|
+
.toString();
|
|
36
|
+
const now = moment();
|
|
37
|
+
const TTL = moment(params.startDate)
|
|
38
|
+
.add(1, 'minute') // ミリ秒でカウントしていくので、予約日時後1分で十分
|
|
39
|
+
.diff(now, 'seconds');
|
|
40
|
+
debug(`TTL:${TTL} seconds`);
|
|
41
|
+
const key = util.format('%s:%s', RedisRepository.REDIS_KEY_PREFIX, timestamp);
|
|
42
|
+
const results = yield this.redisClient.multi()
|
|
43
|
+
.incr(key)
|
|
44
|
+
.expire(key, TTL)
|
|
45
|
+
.exec();
|
|
46
|
+
// tslint:disable-next-line:no-single-line-block-comment
|
|
47
|
+
/* istanbul ignore else: please write tests */
|
|
48
|
+
if (Array.isArray(results) && typeof results[0] === 'number') {
|
|
49
|
+
let identifier = timestamp;
|
|
50
|
+
const no = results[0];
|
|
51
|
+
debug('no incremented.', no);
|
|
52
|
+
identifier = `${identifier}${no}`;
|
|
53
|
+
// checkdigit
|
|
54
|
+
const cd = cdigit.luhn.compute(identifier);
|
|
55
|
+
const cipher = fpe({ password: cd });
|
|
56
|
+
identifier = cipher.encrypt(identifier);
|
|
57
|
+
debug('publishing serviceOutputIdentifier from', timestamp, no, cd);
|
|
58
|
+
identifier = `${cd}${identifier}`;
|
|
59
|
+
return identifier;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// 基本的にありえないフロー
|
|
63
|
+
throw new factory.errors.ServiceUnavailable('ServiceOutput identifier not published');
|
|
64
|
+
}
|
|
79
65
|
});
|
|
80
66
|
}
|
|
81
67
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { RedisClientType } from 'redis';
|
|
2
2
|
interface IPublishResult {
|
|
3
3
|
transactionNumber: string;
|
|
4
4
|
}
|
|
@@ -8,7 +8,7 @@ interface IPublishResult {
|
|
|
8
8
|
export declare class RedisRepository {
|
|
9
9
|
static REDIS_KEY_PREFIX: string;
|
|
10
10
|
private readonly redisClient;
|
|
11
|
-
constructor(redisClient:
|
|
11
|
+
constructor(redisClient: RedisClientType);
|
|
12
12
|
/**
|
|
13
13
|
* タイムスタンプから発行する
|
|
14
14
|
*/
|