Skip to content
This repository has been archived by the owner on May 3, 2024. It is now read-only.

Commit

Permalink
fix(devCdn): handle different module files
Browse files Browse the repository at this point in the history
  • Loading branch information
code-forger committed Dec 8, 2023
1 parent 39318cb commit 48aa35f
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 51 deletions.
45 changes: 21 additions & 24 deletions __tests__/server/utils/cdnCache.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import {
getUserHomeDirectory,
showCacheInfo,
setupCacheFile,
getCachedModules,
getCachedModuleFiles,
writeToCache,
removeDuplicatedModules,
removeExistingEntryIfConflicting,
cacheFileName,
oneAppDirectoryName,
oneAppDirectoryPath,
Expand Down Expand Up @@ -79,8 +79,7 @@ describe('cacheUtils', () => {
await showCacheInfo();

expect(fsPromises.stat).toHaveBeenCalledWith(oneAppModuleCachePath);
expect(chalk.bold.cyanBright).toHaveBeenCalledTimes(2);
expect(chalk.bold.redBright).toHaveBeenCalledWith('CACHE INFORMATION');
expect(chalk.bold.cyanBright).toHaveBeenCalledTimes(4);
expect(chalk.bold.greenBright).toHaveBeenCalledWith('5.00', 'MB');
});

Expand Down Expand Up @@ -132,7 +131,7 @@ describe('cacheUtils', () => {
});
});

describe('getCachedModules', () => {
describe('getCachedModuleFiles', () => {
beforeAll(() => {
fsPromises.stat.mockResolvedValue('');
fsPromises.mkdir.mockResolvedValue();
Expand All @@ -141,13 +140,13 @@ describe('cacheUtils', () => {

it('should return an empty object if the cache file does not exist', () => {
fs.existsSync.mockImplementationOnce(() => false);
const result = getCachedModules();
const result = getCachedModuleFiles();
expect(result).toEqual({});
});

it('should create a new cache file and return an empty object if the cache file does not exist', () => {
fs.existsSync.mockImplementationOnce(() => false);
const result = getCachedModules();
const result = getCachedModuleFiles();
expect(result).toEqual({});
});

Expand All @@ -156,7 +155,7 @@ describe('cacheUtils', () => {
fs.existsSync.mockImplementationOnce(() => true);
fs.readFileSync.mockImplementationOnce(() => invalidJSON);

const result = getCachedModules();
const result = getCachedModuleFiles();
let error;
try {
JSON.parse(invalidJSON);
Expand All @@ -171,7 +170,7 @@ describe('cacheUtils', () => {
const validJSON = '{"module":"test"}';
fs.existsSync.mockImplementationOnce(() => true);
fs.readFileSync.mockImplementationOnce(() => validJSON);
const result = getCachedModules();
const result = getCachedModuleFiles();
expect(result).toEqual(JSON.parse(validJSON));
});
});
Expand Down Expand Up @@ -215,34 +214,32 @@ describe('cacheUtils', () => {

describe('removeDuplicatedModules', () => {
it('removes the matching modules from cachedModules', () => {
const url = '/somepath/moduleA/someotherpath';
const url = '/path/to/moduleA/2.2.3/file.js';
const cachedModules = {
'/path/to/moduleA/1': 'data',
'/path/to/moduleA/2': 'data',
'/path/to/moduleB/1': 'data',
'/path/to/moduleA/1.2.3/file.js': 'data',
'/path/to/moduleA/1.2.3/file.json': 'data',
'/path/to/moduleB/1.2.3/file.js': 'data',
};
const moduleNames = ['moduleA', 'moduleB', 'moduleC'];

const result = removeDuplicatedModules(url, cachedModules, moduleNames);
const result = removeExistingEntryIfConflicting(url, cachedModules);

expect(result).toEqual({
'/path/to/moduleB/1': 'data',
'/path/to/moduleA/1.2.3/file.json': 'data',
'/path/to/moduleB/1.2.3/file.js': 'data',
});

expect(logSpy).toHaveBeenCalledWith('Deleted /path/to/moduleA/1 from cache');
expect(logSpy).toHaveBeenCalledWith('Deleted /path/to/moduleA/2 from cache');
expect(logSpy).not.toHaveBeenCalled();
});

it('returns cachedModules unchanged if no module matches', () => {
const url = '/somepath/moduleX/someotherpath';
const url = '/path/to/moduleC/2.2.3/file.js';
const cachedModules = {
'/path/to/moduleA/1': 'data',
'/path/to/moduleA/2': 'data',
'/path/to/moduleB/1': 'data',
'/path/to/moduleA/1.2.3/file.js': 'data',
'/path/to/moduleA/1.2.3/file.json': 'data',
'/path/to/moduleB/1.2.3/file.js': 'data',
};
const moduleNames = ['moduleA', 'moduleB', 'moduleC'];

const result = removeDuplicatedModules(url, cachedModules, moduleNames);
const result = removeExistingEntryIfConflicting(url, cachedModules);

expect(result).toEqual(cachedModules);
expect(logSpy).not.toHaveBeenCalled();
Expand Down
12 changes: 8 additions & 4 deletions __tests__/server/utils/devCdnFactory.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,19 @@ import path from 'path';
import mkdirp from 'mkdirp';
import ProxyAgent from 'proxy-agent';
import oneAppDevCdn from '../../../src/server/utils/devCdnFactory';
import { removeDuplicatedModules } from '../../../src/server/utils/cdnCache';
import {
removeExistingEntryIfConflicting,
} from '../../../src/server/utils/cdnCache';

jest.mock('node-fetch');
jest.mock('pino');

jest.mock('../../../src/server/utils/cdnCache', () => ({
getCachedModules: jest.fn(() => ({
getCachedModuleFiles: jest.fn(() => ({
'/cdn/module-b/1.0.0/module-c.node.js': 'console.log("c");',
})),
writeToCache: jest.fn(() => ({})),
removeDuplicatedModules: jest.fn(() => ({})),
removeExistingEntryIfConflicting: jest.fn((_, cachedModuleFiles) => cachedModuleFiles),
}));

const pathToStubs = path.join(__dirname, 'stubs');
Expand Down Expand Up @@ -152,7 +154,9 @@ describe('one-app-dev-cdn', () => {
},
},
};
removeDuplicatedModules.mockImplementation(() => ({}));
removeExistingEntryIfConflicting.mockImplementation(
(_, cachedModuleFiles) => cachedModuleFiles
);
fetch.mockImplementation((url) => Promise.reject(new Error(`no mock for ${url} set up`)));
});

Expand Down
31 changes: 19 additions & 12 deletions src/server/utils/cdnCache.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ export const showCacheInfo = async () => {
const message = `File size of ${cacheFileName}: ${chalk.bold.greenBright(fileSizeOnMB.toFixed(2), 'MB')}`;
const separator = '*'.repeat(message.length);
console.log(chalk.bold.cyanBright(separator));
console.log(chalk.bold.redBright('CACHE INFORMATION'));
console.log(chalk.bold.cyanBright('CACHE INFORMATION'));
console.log(message);
console.log(`To delete cache, please run \n ${chalk.bold.redBright(' rm ', oneAppModuleCachePath)}`);
console.log('To delete cache, please run');
console.log(` ${chalk.bold.cyanBright(' rm ', oneAppModuleCachePath)}`);
console.log(chalk.bold.cyanBright(separator));
} catch (error) {
console.error('There was error checking file stat', error);
Expand All @@ -58,7 +59,7 @@ export const setupCacheFile = async () => {
};

// gets cached module from ~/.one-app/.one-app-module-cache
export const getCachedModules = () => {
export const getCachedModuleFiles = () => {
if (!fs.existsSync(oneAppModuleCachePath)) {
setupCacheFile();
return {};
Expand Down Expand Up @@ -89,15 +90,21 @@ export const writeToCache = (content, delay = 500) => {
}, delay);
};

export const removeDuplicatedModules = (url, cachedModules, moduleNames) => {
const matchingModule = moduleNames.find((moduleName) => url.match(new RegExp(`\\b\\/${moduleName}\\/\\b`)));
const stripVersion = (url) => {
const parts = url.split('/');
parts.splice(-2, 1);
return parts.join('/');
};

const updatedCachedModules = cachedModules;
Object.keys(updatedCachedModules).forEach((cachedModuleKey) => {
if (cachedModuleKey.match(new RegExp(`\\b\\/${matchingModule}\\/\\b`))) {
delete updatedCachedModules[cachedModuleKey];
console.log(`Deleted ${cachedModuleKey} from cache`);
}
});
export const removeExistingEntryIfConflicting = (url, cachedModuleFiles) => {
const updatedCachedModules = { ...cachedModuleFiles };
const strippedUrl = stripVersion(url);

const matchingModule = Object.keys(cachedModuleFiles)
.find((cachedUrl) => stripVersion(cachedUrl) === strippedUrl);

if (matchingModule && matchingModule !== url) {
delete updatedCachedModules[matchingModule];
}
return updatedCachedModules;
};
19 changes: 8 additions & 11 deletions src/server/utils/devCdnFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ import ProxyAgent from 'proxy-agent';
import fetch from 'node-fetch';
import logger from './logging/logger';

import { getCachedModules, writeToCache, removeDuplicatedModules } from './cdnCache';
import { getCachedModuleFiles, writeToCache, removeExistingEntryIfConflicting } from './cdnCache';

let moduleNames = [];
const cachedModules = getCachedModules();
let cachedModuleFiles = getCachedModuleFiles();

const getLocalModuleMap = ({ pathToModuleMap, oneAppDevCdnAddress }) => {
const moduleMap = JSON.parse(fs.readFileSync(pathToModuleMap, 'utf8').toString());
Expand Down Expand Up @@ -157,7 +156,6 @@ export const oneAppDevCdnFactory = ({
...localMap.modules,
},
};
moduleNames = Object.keys(map.modules);
reply
.code(200)
.send(map);
Expand All @@ -172,25 +170,24 @@ export const oneAppDevCdnFactory = ({
remoteModuleBaseUrls
);
const remoteModuleBaseUrlOrigin = new URL(knownRemoteModuleBaseUrl).origin;
if (cachedModules[incomingRequestPath]) {
if (cachedModuleFiles[incomingRequestPath]) {
return reply
.code(200)
.type('application/json')
.send(cachedModules[incomingRequestPath]);
.send(cachedModuleFiles[incomingRequestPath]);
}
const remoteModuleResponse = await fetch(`${remoteModuleBaseUrlOrigin}/${incomingRequestPath}`, {
headers: { connection: 'keep-alive' },
agent: new ProxyAgent(),
});
const { status, type } = remoteModuleResponse;
const responseText = await remoteModuleResponse.text();
const updatedCachedModules = removeDuplicatedModules(
cachedModuleFiles = removeExistingEntryIfConflicting(
incomingRequestPath,
cachedModules,
moduleNames
cachedModuleFiles
);
updatedCachedModules[incomingRequestPath] = responseText;
writeToCache(updatedCachedModules);
cachedModuleFiles[incomingRequestPath] = responseText;
writeToCache(cachedModuleFiles);
reply
.code(status)
.type(type)
Expand Down

0 comments on commit 48aa35f

Please sign in to comment.