Skip to content

Commit

Permalink
WIP Auth2 probe responses for A/V
Browse files Browse the repository at this point in the history
  • Loading branch information
barmintor committed Oct 23, 2023
1 parent 2221286 commit a6f2308
Show file tree
Hide file tree
Showing 14 changed files with 353 additions and 33 deletions.
3 changes: 2 additions & 1 deletion src/lib/getServices.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Utils } from 'manifesto.js';
import { filterByTypes } from './typeFilters';
import CanvasAttributes from './CanvasAttributes';

/**
*/
Expand All @@ -18,7 +19,7 @@ export function getProbeService(resource) {
&& (
Utils.getService(resource, 'http://iiif.io/api/auth/1/probe')
|| filterByTypes(Utils.getServices(resource), 'AuthProbeService2')[0]
);
);
}

/**
Expand Down
18 changes: 13 additions & 5 deletions src/lib/typeFilters.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,21 @@ export function audioResourcesFrom(resources) {
return filterByTypes(resources, CanvasAttributes.SOUND_TYPES);
}

/**
*/
export function anyImageServices(resource) {
const services = resource ? resource.getServices() : [];
return services.filter(s => CanvasAttributes.IMAGE_SERVICE_PROFILES.includes(s.getProfile()));
}

export function hasImageService(resource) {
const imageServices = anyImageServices(resource);
return imageServices[0] && imageServices[0].id;
}

/** */
export function iiifImageResourcesFrom(resources) {
return filterByTypes(resources, CanvasAttributes.IMAGE_TYPES).filter((r) => {
const services = r ? r.getServices() : [];
const imageServices = services.filter(s => CanvasAttributes.IMAGE_SERVICE_PROFILES.includes(s.getProfile()));
return imageServices[0] && imageServices[0].id;
});
return filterByTypes(resources, CanvasAttributes.IMAGE_TYPES).filter((r) => hasImageService(r));
}

/** */
Expand Down
6 changes: 6 additions & 0 deletions src/state/actions/action-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ const ActionTypes = {
RECEIVE_DEGRADED_INFO_RESPONSE: 'mirador/RECEIVE_DEGRADED_INFO_RESPONSE',
RECEIVE_INFO_RESPONSE_FAILURE: 'mirador/RECEIVE_INFO_RESPONSE_FAILURE',
REMOVE_INFO_RESPONSE: 'mirador/REMOVE_INFO_RESPONSE',

REQUEST_PROBE_RESPONSE: 'mirador/REQUEST_PROBE_RESPONSE',
RECEIVE_PROBE_RESPONSE: 'mirador/RECEIVE_PROBE_RESPONSE',
RECEIVE_DEGRADED_PROBE_RESPONSE: 'mirador/RECEIVE_DEGRADED_PROBE_RESPONSE',
RECEIVE_PROBE_RESPONSE_FAILURE: 'mirador/RECEIVE_PROBE_RESPONSE_FAILURE',
REMOVE_PROBE_RESPONSE: 'mirador/REMOVE_PROBE_RESPONSE',
UPDATE_WORKSPACE_MOSAIC_LAYOUT: 'mirador/UPDATE_WORKSPACE_MOSAIC_LAYOUT',
UPDATE_VIEWPORT: 'mirador/UPDATE_VIEWPORT',
UPDATE_ELASTIC_WINDOW_LAYOUT: 'mirador/UPDATE_ELASTIC_WINDOW_LAYOUT',
Expand Down
1 change: 1 addition & 0 deletions src/state/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ export * from './elasticLayout';
export * from './search';
export * from './layers';
export * from './catalog';
export * from './probeResponse';
90 changes: 90 additions & 0 deletions src/state/actions/probeResponse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import ActionTypes from './action-types';
import { getProbeService } from '../../lib/getServices';

/**
* requestProbeResponse - action creator
*
* @param {String} infoId
* @memberof ActionCreators
*/
export function requestProbeResponse(probeId, resource, windowId) {
return {
probeId,
resource,
type: ActionTypes.REQUEST_PROBE_RESPONSE,
windowId,
};
}

/**
* receiveProbeResponse - action creator
*
* @param {String} infoId
* @param {Object} manifestJson
* @memberof ActionCreators
*/
export function receiveProbeResponse(probeId, probeJson, ok, tokenServiceId) {
return {
ok,
probeId,
probeJson,
tokenServiceId,
type: ActionTypes.RECEIVE_PROBE_RESPONSE,
};
}

/**
* receiveDegradedProbeResponse - action creator
*
* @param {String} infoId
* @param {Object} manifestJson
* @memberof ActionCreators
*/
export function receiveDegradedProbeResponse(probeId, probeJson, ok, tokenServiceId, windowId) {
return {
ok,
probeId,
probeJson,
tokenServiceId,
type: ActionTypes.RECEIVE_DEGRADED_PROBE_RESPONSE,
windowId,
};
}

/**
* receiveProbeResponseFailure - action creator
*
* @param {String} infoId
* @param {String} error
* @memberof ActionCreators
*/
export function receiveProbeResponseFailure(probeId, error, tokenServiceId) {
return {
error,
probeId,
tokenServiceId,
type: ActionTypes.RECEIVE_PROBE_RESPONSE_FAILURE,
};
}

/**
* fetchProbeResponse - action creator
*
* @param {String} infoId
* @memberof ActionCreators
*/
export function fetchProbeResponse({ resourceId, resource, windowId }) {
const probeService = resource && getProbeService(resource);
const probeId = (resourceId || probeService.id);
return requestProbeResponse(probeId, resource, windowId);
}

/**
* removeProbeResponse - action creator
*
* @param {String} probeId
* @memberof ActionCreators
*/
export function removeProbeResponse(probeId) {
return { probeId, type: ActionTypes.REMOVE_PROBE_RESPONSE };
}
11 changes: 11 additions & 0 deletions src/state/reducers/accessTokens.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@ export function accessTokensReducer(state = {}, action) {
if (!action.tokenServiceId) return state;
if (state[action.tokenServiceId].success) return state;

return {
...state,
[action.tokenServiceId]: {
...state[action.tokenServiceId],
success: true,
},
};
case ActionTypes.RECEIVE_PROBE_RESPONSE:
if (!action.tokenServiceId) return state;
if (state[action.tokenServiceId].success) return state;

return {
...state,
[action.tokenServiceId]: {
Expand Down
1 change: 1 addition & 0 deletions src/state/reducers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export * from './elasticLayout';
export * from './search';
export * from './layers';
export * from './catalog';
export * from './probeResponses';
59 changes: 59 additions & 0 deletions src/state/reducers/probeResponses.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import ActionTypes from '../actions/action-types';

/**
* probeResponsesReducer
*/
export const probeResponsesReducer = (state = {}, action) => {
switch (action.type) {
case ActionTypes.REQUEST_PROBE_RESPONSE:
return {
...state,
[action.probeId]: {
id: action.probeId,
isFetching: true,
},
};
case ActionTypes.RECEIVE_PROBE_RESPONSE:
return {
...state,
[action.probeId]: {
degraded: false,
id: action.probeId,
isFetching: false,
json: action.probeJson,
tokenServiceId: action.tokenServiceId,
},
};
case ActionTypes.RECEIVE_DEGRADED_PROBE_RESPONSE:
return {
...state,
[action.probeId]: {
degraded: true,
id: action.probeId,
isFetching: false,
json: action.probeJson,
tokenServiceId: action.tokenServiceId,
},
};
case ActionTypes.RECEIVE_PROBE_RESPONSE_FAILURE:
return {
...state,
[action.probeId]: {
error: action.error,
id: action.probeId,
isFetching: false,
tokenServiceId: action.tokenServiceId,
},
};
case ActionTypes.REMOVE_PROBE_RESPONSE:
return Object.keys(state).reduce((object, key) => {
if (key !== action.probeId) {
object[key] = state[key]; // eslint-disable-line no-param-reassign
}
return object;
}, {});
case ActionTypes.IMPORT_MIRADOR_STATE:
return {};
default: return state;
}
};
2 changes: 2 additions & 0 deletions src/state/reducers/rootReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
searchesReducer,
layersReducer,
catalogReducer,
probeResponsesReducer,
} from '.';

/**
Expand All @@ -35,6 +36,7 @@ export default function createRootReducer(pluginReducers) {
infoResponses: infoResponsesReducer,
layers: layersReducer,
manifests: manifestsReducer,
probeResponses: probeResponsesReducer,
searches: searchesReducer,
viewers: viewersReducer,
windows: windowsReducer,
Expand Down
55 changes: 54 additions & 1 deletion src/state/sagas/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ import {
} from '../actions';
import {
selectInfoResponses,
selectProbeResponses,
getVisibleCanvases,
getWindows,
getConfig,
getAuth,
getAccessTokens,
} from '../selectors';
import { fetchInfoResponse } from './iiif';
import { fetchInfoResponse, fetchProbeResponse } from './iiif';

/** */
export function* refetchInfoResponsesOnLogout({ tokenServiceId }) {
Expand Down Expand Up @@ -70,6 +71,54 @@ export function* refetchInfoResponses({ serviceId }) {
}));
}

/** */
export function* refetchProbeResponsesOnLogout({ tokenServiceId }) {
// delay logout actions to give the cookie service a chance to invalidate our cookies
// before we reinitialize openseadragon and rerequest images.

yield delay(2000);
yield call(refetchProbeResponses, { serviceId: tokenServiceId });
}

/**
* Figure out what info responses could have used the access token service and:
* - refetch, if they are currently visible
* - throw them out (and lazy re-fetch) otherwise
*/
export function* refetchProbeResponses({ serviceId }) {
const windows = yield select(getWindows);

const canvases = yield all(
Object.keys(windows).map(windowId => select(getVisibleCanvases, { windowId })),
);

const visibleProbeServiceIds = flatten(flatten(canvases).map((canvas) => {
const miradorCanvas = new MiradorCanvas(canvas);
return miradorCanvas.imageResources.filter((r) => getProbeService(r)).map((r) => getProbeService(r));
}));

const probeResponses = yield select(selectProbeResponses);
/** */
const haveThisTokenService = probeResponse => {
const services = Utils.getServices(probeResponse);
return services.some(e => {
const probeTokenService = getTokenService(e);
return probeTokenService && probeTokenService.id === serviceId;
});
};

const obsoleteProbeResponses = Object.values(probeResponses).filter(
i => i.json && haveThisTokenService(i.json),
);

yield all(obsoleteProbeResponses.map(({ id: probeId }) => {
if (visibleProbeServiceIds.includes(probeId)) {
return call(fetchProbeResponse, { probeId });
}
return put({ probeId, type: ActionTypes.REMOVE_PROBE_RESPONSE });
}));
}

/** try to start any non-interactive auth flows */
export function* doAuthWorkflow({ infoJson, windowId }) {
const auths = yield select(getAuth);
Expand Down Expand Up @@ -152,9 +201,13 @@ export function* invalidateInvalidAuth({ serviceId }) {
export default function* authSaga() {
yield all([
takeEvery(ActionTypes.RECEIVE_DEGRADED_INFO_RESPONSE, rerequestOnAccessTokenFailure),
takeEvery(ActionTypes.RECEIVE_DEGRADED_PROBE_RESPONSE, rerequestOnAccessTokenFailure),
takeEvery(ActionTypes.RECEIVE_ACCESS_TOKEN_FAILURE, invalidateInvalidAuth),
takeEvery(ActionTypes.RECEIVE_DEGRADED_INFO_RESPONSE, doAuthWorkflow),
takeEvery(ActionTypes.RECEIVE_DEGRADED_PROBE_RESPONSE, doAuthWorkflow),
takeEvery(ActionTypes.RECEIVE_ACCESS_TOKEN, refetchInfoResponses),
takeEvery(ActionTypes.RECEIVE_ACCESS_TOKEN, refetchProbeResponses),
takeEvery(ActionTypes.RESET_AUTHENTICATION_STATE, refetchInfoResponsesOnLogout),
takeEvery(ActionTypes.RESET_AUTHENTICATION_STATE, refetchProbeResponsesOnLogout),
]);
}
Loading

0 comments on commit a6f2308

Please sign in to comment.