Skip to content

Commit 1ffd38b

Browse files
author
James Lees
authored
Merge pull request #85 from pusher/not-implemented-methods
Add not implemented methods to abstract base class
2 parents e7103d1 + f29633d commit 1ffd38b

File tree

3 files changed

+107
-119
lines changed

3 files changed

+107
-119
lines changed

src/base-client.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,19 @@ export const RegistrationState = Object.freeze({
1515
PERMISSION_DENIED: 'PERMISSION_DENIED',
1616
});
1717

18+
/* BaseClient is an abstract client containing functionality shared between
19+
* safari and web push clients. Platform specific classes should extend this
20+
* class. This method expects sub classes to implement the following public
21+
* methods:
22+
* async start()
23+
* async getRegistrationState() {
24+
* async stop() {
25+
* async clearAllState() {
26+
*
27+
* It also assumes that the following private methods are implemented:
28+
* async _init()
29+
* async _detectSubscriptionChange()
30+
*/
1831
export default class BaseClient {
1932
constructor(config, platform) {
2033
if (this.constructor === BaseClient) {
@@ -224,6 +237,65 @@ export default class BaseClient {
224237
const response = await doRequest(options);
225238
return response.id;
226239
}
240+
241+
async setUserId(userId, tokenProvider) {
242+
await this._resolveSDKState();
243+
244+
if (!this._isSupportedBrowser()) {
245+
return;
246+
}
247+
248+
if (this._deviceId === null) {
249+
const error = new Error('.start must be called before .setUserId');
250+
return Promise.reject(error);
251+
}
252+
if (typeof userId !== 'string') {
253+
throw new Error(`User ID must be a string (was ${userId})`);
254+
}
255+
if (userId === '') {
256+
throw new Error('User ID cannot be the empty string');
257+
}
258+
if (this._userId !== null && this._userId !== userId) {
259+
throw new Error('Changing the `userId` is not allowed.');
260+
}
261+
262+
const path = `${this._baseURL}/device_api/v1/instances/${encodeURIComponent(
263+
this.instanceId
264+
)}/devices/web/${this._deviceId}/user`;
265+
266+
const { token: beamsAuthToken } = await tokenProvider.fetchToken(userId);
267+
const options = {
268+
method: 'PUT',
269+
path,
270+
headers: {
271+
Authorization: `Bearer ${beamsAuthToken}`,
272+
},
273+
};
274+
await doRequest(options);
275+
276+
this._userId = userId;
277+
return this._deviceStateStore.setUserId(userId);
278+
}
279+
280+
async start() {
281+
throwNotImplementedError('start');
282+
}
283+
async getRegistrationState() {
284+
throwNotImplementedError('getRegistrationState');
285+
}
286+
async stop() {
287+
throwNotImplementedError('stop');
288+
}
289+
async clearAllState() {
290+
throwNotImplementedError('clearAllState');
291+
}
292+
}
293+
294+
function throwNotImplementedError(method) {
295+
throw new Error(
296+
`${method} not implemented on abstract BaseClient.` +
297+
'Instantiate either WebPushClient or SafariClient'
298+
);
227299
}
228300

229301
function validateInterestName(interest) {

src/safari-client.js

Lines changed: 6 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import doRequest from './do-request';
21
import BaseClient from './base-client';
32
import { version as sdkVersion } from '../package.json';
43
import { RegistrationState } from './base-client';
@@ -11,7 +10,7 @@ const platform = 'safari';
1110
export class SafariClient extends BaseClient {
1211
constructor(config) {
1312
super(config, platform);
14-
if (!isSupportedBrowser()) {
13+
if (!this._isSupportedBrowser()) {
1514
throw new Error(
1615
'Pusher Beams does not support this Safari version (Safari Push Notifications not supported)'
1716
);
@@ -119,61 +118,18 @@ export class SafariClient extends BaseClient {
119118
// TODO we can only call start() in a user gesture so this may not work in
120119
// safari, can't we clear the state another way
121120
throw new Error('Not implemented');
122-
// if (!isSupportedBrowser()) {
121+
// if (!this._isSupportedBrowser()) {
123122
// return;
124123
// }
125124

126125
// await this.stop();
127126
// await this.start();
128127
}
129128

130-
// TODO these seem similar enough to go in the base client but
131-
// isSupportedBrowser is going to be different for safari/web-push. It's not
132-
// clear to me at the moment why we need to check whether the browser is
133-
// supported here anyway
134-
async setUserId(userId, tokenProvider) {
135-
await this._resolveSDKState();
136-
137-
if (!isSupportedBrowser()) {
138-
return;
139-
}
140-
141-
if (this._deviceId === null) {
142-
const error = new Error('.start must be called before .setUserId');
143-
return Promise.reject(error);
144-
}
145-
if (typeof userId !== 'string') {
146-
throw new Error(`User ID must be a string (was ${userId})`);
147-
}
148-
if (userId === '') {
149-
throw new Error('User ID cannot be the empty string');
150-
}
151-
if (this._userId !== null && this._userId !== userId) {
152-
throw new Error('Changing the `userId` is not allowed.');
153-
}
154-
155-
const path = `${this._baseURL}/device_api/v1/instances/${encodeURIComponent(
156-
this.instanceId
157-
)}/devices/web/${this._deviceId}/user`;
158-
159-
const { token: beamsAuthToken } = await tokenProvider.fetchToken(userId);
160-
const options = {
161-
method: 'PUT',
162-
path,
163-
headers: {
164-
Authorization: `Bearer ${beamsAuthToken}`,
165-
},
166-
};
167-
await doRequest(options);
168-
169-
this._userId = userId;
170-
return this._deviceStateStore.setUserId(userId);
171-
}
172-
173129
async stop() {
174130
await this._resolveSDKState();
175131

176-
if (!isSupportedBrowser()) {
132+
if (!this._isSupportedBrowser()) {
177133
return;
178134
}
179135

@@ -206,10 +162,9 @@ export class SafariClient extends BaseClient {
206162
resolve(__pushId);
207163
});
208164
}
209-
}
210-
211-
function isSupportedBrowser() {
212-
return 'safari' in window && 'pushNotification' in window.safari;
165+
_isSupportedBrowser() {
166+
return 'safari' in window && 'pushNotification' in window.safari;
167+
}
213168
}
214169

215170
function getPermission(pushId) {

src/web-push-client.js

Lines changed: 29 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export class WebPushClient extends BaseClient {
8989
async start() {
9090
await this._resolveSDKState();
9191

92-
if (!isSupportedBrowser()) {
92+
if (!this._isSupportedBrowser()) {
9393
return this;
9494
}
9595

@@ -135,49 +135,10 @@ export class WebPushClient extends BaseClient {
135135
return RegistrationState.PERMISSION_PROMPT_REQUIRED;
136136
}
137137

138-
async setUserId(userId, tokenProvider) {
139-
await this._resolveSDKState();
140-
141-
if (!isSupportedBrowser()) {
142-
return;
143-
}
144-
145-
if (this._deviceId === null) {
146-
const error = new Error('.start must be called before .setUserId');
147-
return Promise.reject(error);
148-
}
149-
if (typeof userId !== 'string') {
150-
throw new Error(`User ID must be a string (was ${userId})`);
151-
}
152-
if (userId === '') {
153-
throw new Error('User ID cannot be the empty string');
154-
}
155-
if (this._userId !== null && this._userId !== userId) {
156-
throw new Error('Changing the `userId` is not allowed.');
157-
}
158-
159-
const path = `${this._baseURL}/device_api/v1/instances/${encodeURIComponent(
160-
this.instanceId
161-
)}/devices/web/${this._deviceId}/user`;
162-
163-
const { token: beamsAuthToken } = await tokenProvider.fetchToken(userId);
164-
const options = {
165-
method: 'PUT',
166-
path,
167-
headers: {
168-
Authorization: `Bearer ${beamsAuthToken}`,
169-
},
170-
};
171-
await doRequest(options);
172-
173-
this._userId = userId;
174-
return this._deviceStateStore.setUserId(userId);
175-
}
176-
177138
async stop() {
178139
await this._resolveSDKState();
179140

180-
if (!isSupportedBrowser()) {
141+
if (!this._isSupportedBrowser()) {
181142
return;
182143
}
183144

@@ -195,7 +156,7 @@ export class WebPushClient extends BaseClient {
195156
}
196157

197158
async clearAllState() {
198-
if (!isSupportedBrowser()) {
159+
if (!this._isSupportedBrowser()) {
199160
return;
200161
}
201162

@@ -243,6 +204,32 @@ export class WebPushClient extends BaseClient {
243204
},
244205
});
245206
}
207+
208+
/**
209+
* Modified from https://stackoverflow.com/questions/4565112
210+
*/
211+
_isSupportedBrowser() {
212+
const winNav = window.navigator;
213+
const vendorName = winNav.vendor;
214+
215+
const isChromium =
216+
window.chrome !== null && typeof window.chrome !== 'undefined';
217+
const isOpera = winNav.userAgent.indexOf('OPR') > -1;
218+
const isEdge = winNav.userAgent.indexOf('Edg') > -1;
219+
const isFirefox = winNav.userAgent.indexOf('Firefox') > -1;
220+
221+
const isChrome =
222+
isChromium && vendorName === 'Google Inc.' && !isEdge && !isOpera;
223+
224+
const isSupported = isChrome || isOpera || isFirefox || isEdge;
225+
226+
if (!isSupported) {
227+
console.warn(
228+
'Pusher Web Push Notifications supports Chrome, Firefox, Edge and Opera.'
229+
);
230+
}
231+
return isSupported;
232+
}
246233
}
247234

248235
async function getServiceWorkerRegistration() {
@@ -279,29 +266,3 @@ function urlBase64ToUInt8Array(base64String) {
279266
const rawData = window.atob(base64);
280267
return Uint8Array.from([...rawData].map(char => char.charCodeAt(0)));
281268
}
282-
283-
/**
284-
* Modified from https://stackoverflow.com/questions/4565112
285-
*/
286-
function isSupportedBrowser() {
287-
const winNav = window.navigator;
288-
const vendorName = winNav.vendor;
289-
290-
const isChromium =
291-
window.chrome !== null && typeof window.chrome !== 'undefined';
292-
const isOpera = winNav.userAgent.indexOf('OPR') > -1;
293-
const isEdge = winNav.userAgent.indexOf('Edg') > -1;
294-
const isFirefox = winNav.userAgent.indexOf('Firefox') > -1;
295-
296-
const isChrome =
297-
isChromium && vendorName === 'Google Inc.' && !isEdge && !isOpera;
298-
299-
const isSupported = isChrome || isOpera || isFirefox || isEdge;
300-
301-
if (!isSupported) {
302-
console.warn(
303-
'Pusher Web Push Notifications supports Chrome, Firefox, Edge and Opera.'
304-
);
305-
}
306-
return isSupported;
307-
}

0 commit comments

Comments
 (0)