Skip to content

Commit c161a7b

Browse files
authored
feat(Activities): Merges xapi-activities service. (#468)
1 parent 75f6263 commit c161a7b

File tree

262 files changed

+5547
-18
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

262 files changed

+5547
-18
lines changed

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
"npm": ">3.0.0"
3939
},
4040
"dependencies": {
41-
"@learninglocker/xapi-activities": "4.4.4",
4241
"@learninglocker/xapi-agents": "4.4.3",
4342
"accept-language-parser": "^1.5.0",
4443
"boolean": "^0.2.0",
@@ -95,4 +94,4 @@
9594
"publishConfig": {
9695
"access": "public"
9796
}
98-
}
97+
}

src/apps/activities/app.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/* tslint:disable:max-file-line-count */
2-
import presenterFactory from '@learninglocker/xapi-activities/dist/expressPresenter';
3-
import serviceFactory from '@learninglocker/xapi-activities/dist/service';
4-
import enTranslator from '@learninglocker/xapi-activities/dist/translatorFactory/en';
52
import { Router } from 'express';
63
import AppConfig from './AppConfig';
4+
import presenterFactory from './expressPresenter';
75
import repoFactory from './repo/factory';
6+
import serviceFactory from './service';
7+
import enTranslator from './translatorFactory/en';
88

99
export default (appConfig: AppConfig): Router => {
1010
const translator = enTranslator;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { ContainerURL } from '@azure/storage-blob';
2+
3+
export default interface Config {
4+
readonly containerUrl: ContainerURL;
5+
readonly subFolder: string;
6+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import {
2+
Aborter,
3+
BlobURL,
4+
Models,
5+
} from '@azure/storage-blob';
6+
import Config from './Config';
7+
8+
export default (config: Config) => {
9+
return async (): Promise<void> => {
10+
// tslint:disable-next-line:no-let
11+
let marker;
12+
do {
13+
const listBlobsResponse: Models.ContainerListBlobFlatSegmentResponse =
14+
await config.containerUrl.listBlobFlatSegment(Aborter.none, marker);
15+
marker = listBlobsResponse.nextMarker;
16+
const deletePromises = listBlobsResponse.segment.blobItems.map(
17+
async (blobItem: Models.BlobItem) => {
18+
const blobUrl = BlobURL.fromContainerURL(config.containerUrl, blobItem.name);
19+
if (blobItem.name.startsWith(config.subFolder)) {
20+
await blobUrl.delete(Aborter.none);
21+
}
22+
},
23+
);
24+
await Promise.all(deletePromises);
25+
} while (marker !== '');
26+
};
27+
};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import {
2+
Aborter,
3+
BlobURL,
4+
} from '@azure/storage-blob';
5+
import DeleteProfileContentOptions from '../repoFactory/options/DeleteProfileContentOptions';
6+
import getStorageDir from '../utils/getStorageDir';
7+
import Config from './Config';
8+
9+
export default (config: Config) => {
10+
return async (opts: DeleteProfileContentOptions): Promise<void> => {
11+
const profileDir = getStorageDir({ subfolder: config.subFolder, lrs_id: opts.lrs_id });
12+
const filePath = `${profileDir}/${opts.key}`;
13+
14+
const blobUrl = BlobURL.fromContainerURL(config.containerUrl, filePath);
15+
16+
await blobUrl.delete(Aborter.none);
17+
};
18+
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Aborter, BlobURL } from '@azure/storage-blob';
2+
import GetProfileContentOptions from '../repoFactory/options/GetProfileContentOptions';
3+
import GetProfileContentResult from '../repoFactory/results/GetProfileContentResult';
4+
import getStorageDir from '../utils/getStorageDir';
5+
import Config from './Config';
6+
7+
export default (config: Config) => {
8+
return async (opts: GetProfileContentOptions): Promise<GetProfileContentResult> => {
9+
const profileDir = getStorageDir({ subfolder: config.subFolder, lrs_id: opts.lrs_id });
10+
const filePath = `${profileDir}/${opts.key}`;
11+
12+
const blobUrl = BlobURL.fromContainerURL(config.containerUrl, filePath);
13+
const content = (await blobUrl.download(Aborter.none, 0)).readableStreamBody;
14+
if (content === undefined) {
15+
throw new Error('Blob not found');
16+
}
17+
18+
return { content };
19+
};
20+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import StorageRepo from '../repoFactory/StorageRepo';
2+
import clearRepo from './clearRepo';
3+
import Config from './Config';
4+
import deleteProfileContent from './deleteProfileContent';
5+
import getProfileContent from './getProfileContent';
6+
import storeProfileContent from './storeProfileContent';
7+
8+
export default (config: Config): StorageRepo => {
9+
return {
10+
clearRepo: clearRepo(config),
11+
deleteProfileContent: deleteProfileContent(config),
12+
getProfileContent: getProfileContent(config),
13+
migrate: async () => Promise.resolve(),
14+
rollback: async () => Promise.resolve(),
15+
storeProfileContent: storeProfileContent(config),
16+
};
17+
};
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import {
2+
Aborter,
3+
BlobURL,
4+
BlockBlobURL,
5+
uploadStreamToBlockBlob,
6+
} from '@azure/storage-blob';
7+
import { Readable } from 'stream';
8+
import StoreProfileContentOptions from '../repoFactory/options/StoreProfileContentOptions';
9+
import getStorageDir from '../utils/getStorageDir';
10+
import Config from './Config';
11+
12+
const BYTES_IN_KILOBYTES = 1024;
13+
const KILOBYTES_IN_MEGABYTES = 1024;
14+
const FOUR = 4;
15+
16+
// https://github.com/Azure/azure-storage-js/blob/master/blob/samples/highlevel.sample.js
17+
const BUFFER_SIZE = FOUR * KILOBYTES_IN_MEGABYTES * BYTES_IN_KILOBYTES; // 4MB
18+
const MAX_BUFFERS = 20;
19+
20+
export default (config: Config) => {
21+
return async (opts: StoreProfileContentOptions): Promise<void> => {
22+
return new Promise<void>(async (resolve, reject) => {
23+
const profileDir = getStorageDir({
24+
subfolder: config.subFolder,
25+
lrs_id: opts.lrs_id,
26+
});
27+
const filePath = `${profileDir}/${opts.key}`;
28+
29+
const blobUrl = BlobURL.fromContainerURL(config.containerUrl, filePath);
30+
const blockBlobUrl = BlockBlobURL.fromBlobURL(blobUrl);
31+
32+
opts.content.on('error', reject);
33+
34+
try {
35+
await uploadStreamToBlockBlob(
36+
Aborter.none,
37+
opts.content as Readable,
38+
blockBlobUrl,
39+
BUFFER_SIZE,
40+
MAX_BUFFERS,
41+
);
42+
} catch (err) {
43+
reject(err);
44+
}
45+
resolve();
46+
});
47+
};
48+
};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/* tslint:disable:no-class */
2+
import BaseError from 'jscommons/dist/errors/BaseError';
3+
4+
export default class extends BaseError {}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import BaseError from 'jscommons/dist/errors/BaseError';
2+
3+
// tslint:disable-next-line:no-class
4+
export default class extends BaseError {
5+
constructor() {
6+
super();
7+
}
8+
}

0 commit comments

Comments
 (0)