Merged PR 259: ルーティング通知登録API実装

## 概要
[Task2218: ルーティング通知登録API実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2218)

- NotificationHubへの通知登録を実装しました。

## レビューポイント
- UUIDを使ったインストールIDの組み立てに問題はないか

- 対象外
  - account関連はフォーマット修正によるものなので対象外です。

## UIの変更
- なし

## 動作確認状況
- ローカルで確認
This commit is contained in:
makabe.t 2023-07-26 00:40:06 +00:00
parent e9ab7cc10b
commit 54db2e8ab5
10 changed files with 305 additions and 100 deletions

View File

@ -11,7 +11,7 @@
"dependencies": {
"@azure/identity": "^3.1.3",
"@azure/keyvault-secrets": "^4.6.0",
"@azure/notification-hubs": "^1.0.1",
"@azure/notification-hubs": "^1.0.2",
"@azure/storage-blob": "^12.14.0",
"@microsoft/microsoft-graph-client": "^3.0.5",
"@nestjs/axios": "^0.1.0",
@ -494,9 +494,9 @@
}
},
"node_modules/@azure/core-util": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.2.0.tgz",
"integrity": "sha512-ffGIw+Qs8bNKNLxz5UPkz4/VBM/EZY07mPve1ZYFqYUdPwFqRj0RPk0U7LZMOfT7GCck9YjuT1Rfp1PApNl1ng==",
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.3.2.tgz",
"integrity": "sha512-2bECOUh88RvL1pMZTcc6OzfobBeWDBf5oBbhjIhT1MV9otMVWCzpOJkkiKtrnO88y5GGBelgY8At73KGAdbkeQ==",
"dependencies": {
"@azure/abort-controller": "^1.0.0",
"tslib": "^2.2.0"
@ -624,9 +624,9 @@
}
},
"node_modules/@azure/notification-hubs": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@azure/notification-hubs/-/notification-hubs-1.0.1.tgz",
"integrity": "sha512-bYgWZNr9LjeSBTstuDRW2FFlZWHjnW09c4YLsB81dsaxMFWGN5mAnE5/+r/omEVqztoP5ClQ3j69ZUoZiJLUsQ==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@azure/notification-hubs/-/notification-hubs-1.0.2.tgz",
"integrity": "sha512-INtgq8uFQpncwbKm4It8M0GkKIePNDNybhuXs4cQPf5H0i9CbfFEt2c6LtT1AdEzbWfUhjsmU5y0p3YDmecwwg==",
"dependencies": {
"@azure/abort-controller": "^1.1.0",
"@azure/core-client": "^1.6.1",
@ -634,24 +634,15 @@
"@azure/core-paging": "^1.3.0",
"@azure/core-rest-pipeline": "^1.8.1",
"@azure/core-tracing": "^1.0.1",
"@azure/core-util": "^1.1.0",
"@azure/core-util": "^1.3.0",
"@azure/core-xml": "^1.3.1",
"@azure/logger": "^1.0.3",
"tslib": "^2.4.0",
"uuid": "^9.0.0"
"tslib": "^2.4.0"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@azure/notification-hubs/node_modules/uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/@azure/storage-blob": {
"version": "12.14.0",
"resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.14.0.tgz",
@ -734,9 +725,9 @@
}
},
"node_modules/@babel/core/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@ -791,9 +782,9 @@
}
},
"node_modules/@babel/helper-compilation-targets/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@ -5753,9 +5744,9 @@
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="
},
"node_modules/fast-xml-parser": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.4.tgz",
"integrity": "sha512-fbfMDvgBNIdDJLdLOwacjFAPYt67tr31H9ZhWSm45CDAxvd0I6WTlSOUo7K2P/K5sA5JgMKG64PI3DMcaFdWpQ==",
"version": "4.2.6",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.6.tgz",
"integrity": "sha512-Xo1qV++h/Y3Ng8dphjahnYe+rGHaaNdsYOBWL9Y9GCPKpNKilJtilvWkLcI9f9X2DoKTLsZsGYAls5+JL5jfLA==",
"funding": [
{
"type": "paypal",
@ -6773,9 +6764,9 @@
}
},
"node_modules/istanbul-lib-instrument/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"bin": {
"semver": "bin/semver.js"
@ -8084,9 +8075,9 @@
}
},
"node_modules/license-checker/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"bin": {
"semver": "bin/semver"
@ -8218,9 +8209,9 @@
}
},
"node_modules/make-dir/node_modules/semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"devOptional": true,
"bin": {
"semver": "bin/semver.js"
@ -8986,9 +8977,9 @@
}
},
"node_modules/normalize-package-data/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"bin": {
"semver": "bin/semver"
@ -9722,9 +9713,9 @@
}
},
"node_modules/read-installed/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"bin": {
"semver": "bin/semver"
@ -10066,9 +10057,9 @@
"dev": true
},
"node_modules/semver": {
"version": "7.3.8",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"dependencies": {
"lru-cache": "^6.0.0"
},
@ -11882,9 +11873,9 @@
}
},
"node_modules/word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
"dev": true,
"engines": {
"node": ">=0.10.0"

View File

@ -30,7 +30,7 @@
"dependencies": {
"@azure/identity": "^3.1.3",
"@azure/keyvault-secrets": "^4.6.0",
"@azure/notification-hubs": "^1.0.1",
"@azure/notification-hubs": "^1.0.2",
"@azure/storage-blob": "^12.14.0",
"@microsoft/microsoft-graph-client": "^3.0.5",
"@nestjs/axios": "^0.1.0",

View File

@ -173,3 +173,12 @@ export const TASK_LIST_SORTABLE_ATTRIBUTES = [
*
*/
export const SORT_DIRECTIONS = ['ASC', 'DESC'] as const;
/**
*
*/
export const PNS = {
WNS: 'wns',
APNS: 'apns',
FCM: 'fcm',
};

View File

@ -1,14 +1,25 @@
import { Body, Controller, HttpStatus, Post, UseGuards } from '@nestjs/common';
import {
Body,
Controller,
HttpStatus,
Post,
Req,
UseGuards,
} from '@nestjs/common';
import {
ApiResponse,
ApiOperation,
ApiBearerAuth,
ApiTags,
} from '@nestjs/swagger';
import { Request } from 'express';
import { ErrorResponse } from '../../common/error/types/types';
import { RegisterRequest, RegisterResponse } from './types/types';
import { NotificationService } from './notification.service';
import { AuthGuard } from '../../common/guards/auth/authguards';
import { retrieveAuthorizationToken } from '../../common/http/helper';
import { AccessToken } from '../../common/token';
import jwt from 'jsonwebtoken';
@ApiTags('notification')
@Controller('notification')
@ -37,10 +48,18 @@ export class NotificationController {
type: ErrorResponse,
})
@ApiOperation({ operationId: 'register' })
@ApiBearerAuth()
@UseGuards(AuthGuard)
async register(@Body() body: RegisterRequest): Promise<RegisterResponse> {
async register(
@Req() req: Request,
@Body() body: RegisterRequest,
): Promise<RegisterResponse> {
const { handler, pns } = body;
await this.notificationService.register(pns, handler);
const accessToken = retrieveAuthorizationToken(req);
const { userId } = jwt.decode(accessToken, { json: true }) as AccessToken;
await this.notificationService.register(userId, pns, handler);
return {};
}
}

View File

@ -2,9 +2,10 @@ import { Module } from '@nestjs/common';
import { NotificationService } from './notification.service';
import { NotificationController } from './notification.controller';
import { NotificationhubModule } from '../../gateways/notificationhub/notificationhub.module';
import { UsersRepositoryModule } from '../../repositories/users/users.repository.module';
@Module({
imports: [NotificationhubModule],
imports: [UsersRepositoryModule, NotificationhubModule],
providers: [NotificationService],
controllers: [NotificationController],
})

View File

@ -1,21 +1,57 @@
import { Test, TestingModule } from '@nestjs/testing';
import { NotificationService } from './notification.service';
import { HttpException, HttpStatus } from '@nestjs/common';
import {
makeNotificationServiceMock,
makeDefaultNotificationHubMockValue,
makeDefaultUsersRepositoryMockValue,
} from './test/notification.service.mock';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
describe('NotificationService', () => {
let service: NotificationService;
const mockNotificationService = {};
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [NotificationService],
})
.overrideProvider(NotificationService)
.useValue(mockNotificationService)
.compile();
describe('NotificationService.register', () => {
it('ユーザーから渡されたPNSハンドルをNotificationHubに登録できる', async () => {
const notificationHubMockValue = makeDefaultNotificationHubMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
service = module.get<NotificationService>(NotificationService);
const service = await makeNotificationServiceMock(
usersRepositoryMockValue,
notificationHubMockValue,
);
expect(await service.register('external_id', 'apns', 'handler')).toEqual(
undefined,
);
});
it('DBからのユーザー取得に失敗した場合、エラーとなる', async () => {
const notificationHubMockValue = makeDefaultNotificationHubMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
usersRepositoryMockValue.findUserByExternalId= new Error("DB failed.")
const service = await makeNotificationServiceMock(
usersRepositoryMockValue,
notificationHubMockValue,
);
await expect(service.register('external_id', 'apns', 'handler')).rejects.toEqual(
new HttpException(makeErrorResponse("E009999"), HttpStatus.INTERNAL_SERVER_ERROR)
);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
it('NotificationHubへの登録に失敗した場合、エラーとなる', async () => {
const notificationHubMockValue = makeDefaultNotificationHubMockValue();
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
notificationHubMockValue.register = new Error("register failed.");
const service = await makeNotificationServiceMock(
usersRepositoryMockValue,
notificationHubMockValue,
);
await expect(
service.register('external_id', 'apns', 'handler'),
).rejects.toEqual(
new HttpException(
makeErrorResponse('E009999'),
HttpStatus.INTERNAL_SERVER_ERROR,
),
);
});
});

View File

@ -1,11 +1,15 @@
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
import { NotificationhubService } from '../../gateways/notificationhub/notificationhub.service';
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
import { UserNotFoundError } from '../../repositories/users/errors/types';
import { v4 as uuidv4 } from 'uuid';
@Injectable()
export class NotificationService {
private readonly logger = new Logger(NotificationService.name);
constructor(
private readonly usersRepository: UsersRepositoryService,
private readonly notificationhubService: NotificationhubService,
) {}
/**
@ -14,10 +18,45 @@ export class NotificationService {
* @param pnsHandler
* @returns register
*/
async register(pns: string, pnsHandler: string): Promise<void> {
async register(
externalId: string,
pns: string,
pnsHandler: string,
): Promise<void> {
this.logger.log(`[IN] ${this.register.name}`);
// ユーザIDからアカウントIDを取得する
let userId: number;
try {
await this.notificationhubService.register(pns, pnsHandler);
userId = (await this.usersRepository.findUserByExternalId(externalId)).id;
} catch (e) {
this.logger.error(`error=${e}`);
switch (e.constructor) {
case UserNotFoundError:
throw new HttpException(
makeErrorResponse('E010204'),
HttpStatus.BAD_REQUEST,
);
default:
throw new HttpException(
makeErrorResponse('E009999'),
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
try {
// TODO: 登録毎に新規登録する想定でUUIDを付与している
// もしデバイスごとに登録を上書きするようであればUUID部分にデバイス識別子を設定
const installationId = `${pns}_${userId}_${uuidv4()}`;
this.logger.log(installationId);
await this.notificationhubService.register(
userId,
pns,
pnsHandler,
installationId,
);
} catch (e) {
this.logger.error(`error=${e}`);
throw new HttpException(

View File

@ -0,0 +1,95 @@
import { ConfigModule } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
import { NotificationhubService } from '../../../gateways/notificationhub/notificationhub.service';
import { User } from '../../../repositories/users/entity/user.entity';
import { NotificationService } from '../notification.service';
import { UsersRepositoryService } from '../../../repositories/users/users.repository.service';
export type UsersRepositoryMockValue = {
findUserByExternalId: User | Error;
};
export type NotificationHubMockValue = {
register: undefined | Error;
};
export const makeNotificationServiceMock = async (
usersRepositoryMockValue: UsersRepositoryMockValue,
notificationHubMockValue: NotificationHubMockValue,
): Promise<NotificationService> => {
const module: TestingModule = await Test.createTestingModule({
providers: [NotificationService],
imports: [
ConfigModule.forRoot({
envFilePath: ['.env.local', '.env'],
}),
],
})
.useMocker((token) => {
switch (token) {
case UsersRepositoryService:
return makeUsersRepositoryMock(usersRepositoryMockValue);
case NotificationhubService:
return makeNotificationHubMock(notificationHubMockValue);
}
})
.compile();
return module.get<NotificationService>(NotificationService);
};
export const makeNotificationHubMock = (value: NotificationHubMockValue) => {
const { register } = value;
return {
register:
register instanceof Error
? jest
.fn<Promise<void>, [number, string, string, string]>()
.mockRejectedValue(register)
: jest
.fn<Promise<void>, [number, string, string, string]>()
.mockResolvedValue(register),
};
};
export const makeUsersRepositoryMock = (value: UsersRepositoryMockValue) => {
const { findUserByExternalId } = value;
return {
findUserByExternalId:
findUserByExternalId instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(findUserByExternalId)
: jest.fn<Promise<User>, []>().mockResolvedValue(findUserByExternalId),
};
};
export const makeDefaultNotificationHubMockValue =
(): NotificationHubMockValue => {
return { register: undefined };
};
// 個別のテストケースに対応してそれぞれのMockを用意するのは無駄が多いのでテストケース内で個別の値を設定する
export const makeDefaultUsersRepositoryMockValue =
(): UsersRepositoryMockValue => {
const user = new User();
user.id = 2;
user.external_id = 'external_id';
user.account_id = 123;
user.role = 'none';
user.author_id = undefined;
user.accepted_terms_version = '1.0';
user.email_verified = true;
user.auto_renew = false;
user.license_alert = false;
user.notification = false;
user.deleted_at = undefined;
user.created_by = 'test';
user.created_at = new Date();
user.updated_by = 'test';
user.updated_at = new Date();
return {
findUserByExternalId: user,
};
};

View File

@ -1,7 +1,12 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsIn } from 'class-validator';
import { PNS } from '../../../constants';
export class RegisterRequest {
@ApiProperty({ description: 'wns or apns' })
@IsIn(Object.values(PNS), {
message: 'invalid pns',
})
pns: string;
@ApiProperty({ description: 'wnsのチャネルURI or apnsのデバイストークン' })
handler: string;

View File

@ -2,10 +2,11 @@ import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import {
NotificationHubsClient,
createWindowsRegistrationDescription,
RegistrationDescription,
createAppleRegistrationDescription,
createAppleInstallation,
createFcmLegacyInstallation,
createWindowsInstallation,
} from '@azure/notification-hubs';
import { PNS } from '../../constants';
@Injectable()
export class NotificationhubService {
private readonly logger = new Logger(NotificationhubService.name);
@ -23,25 +24,44 @@ export class NotificationhubService {
* @param pnsHandler
* @returns register
*/
async register(pns: string, pnsHandler: string): Promise<void> {
async register(
userId: number,
pns: string,
pnsHandler: string,
installationId: string,
): Promise<void> {
this.logger.log(`[IN] ${this.register.name}`);
let reg: RegistrationDescription;
const tag = `user_${userId}`;
//登録情報作成
const installation = {
// XXX 登録の有効期限を設定したい場合
//expirationTime: '',
installationId: installationId,
pushChannel: pnsHandler,
tags: [tag],
};
try {
if (pns === 'wns') {
reg = createWindowsRegistrationDescription({
channelUri: pnsHandler,
tags: [],
// XXX [Task2218] 登録の有効期限を設定したい場合等、本実装を別途Taskで行う
//expirationTime: '',
});
} else if (pns === 'apns') {
reg = createAppleRegistrationDescription({
deviceToken: pnsHandler,
tags: [],
});
} else {
throw new Error('invalid pns');
switch (pns) {
case PNS.WNS:
await this.client.createOrUpdateInstallation(
createWindowsInstallation(installation),
);
break;
case PNS.APNS:
await this.client.createOrUpdateInstallation(
createAppleInstallation(installation),
);
break;
case PNS.FCM:
await this.client.createOrUpdateInstallation(
createFcmLegacyInstallation(installation),
);
break;
default:
throw new Error('invalid pns');
}
} catch (e) {
this.logger.error(`error=${e.message}`);
@ -49,15 +69,5 @@ export class NotificationhubService {
} finally {
this.logger.log(`[OUT] ${this.register.name}`);
}
try {
//登録
await this.client.createOrUpdateRegistration(reg);
} catch (e) {
this.logger.error(`error=${e}`);
throw e;
} finally {
this.logger.log(`[OUT] ${this.register.name}`);
}
}
}