Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions app/desktop/scripts/fetchMediaLibraryAssets.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const async = require('async');
const libraries = require('./lib/libraries');

const NO_CACHE = process.argv.includes('--no-cache');
const ASSET_HOST = 'cdn.assets.scratch.mit.edu';
const ASSET_HOST = 'static.codingclip.com';
const NUM_SIMULTANEOUS_DOWNLOADS = 5;
const OUT_PATH = path.resolve('static', 'assets');

Expand Down Expand Up @@ -66,10 +66,17 @@ const fetchAsset = function (md5, callback) {
return;
}

// The codingclip CDN serves assets by md5ext; skip values without an extension.
if (!md5.includes('.')) {
console.warn(`Skipped (no file extension): ${md5}`);
callback();
return;
}

const myAgent = connectionPool.pop() || new https.Agent({keepAlive: true});
const getOptions = {
host: ASSET_HOST,
path: `/internalapi/asset/${md5}/get/`,
path: `/v1/project/asset/${md5}`,
agent: myAgent
};
const urlHuman = `//${getOptions.host}${getOptions.path}`;
Expand Down
2 changes: 2 additions & 0 deletions packages/gui/src/containers/gui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ interface StorageWithOfficialStores {

interface OwnProps extends ComponentProps {
assetHost?: string;
cdnHost?: string;
cloudHost?: string;
fetchingProject?: boolean;
isLoading?: boolean;
Expand Down Expand Up @@ -137,6 +138,7 @@ class GUI extends React.Component<GUIProps> {
const {
/* eslint-disable @typescript-eslint/no-unused-vars */
assetHost,
cdnHost,
cloudHost,
error,
isError,
Expand Down
3 changes: 2 additions & 1 deletion packages/gui/src/containers/library-item.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React from 'react';
import {injectIntl} from 'react-intl';

import LibraryItemComponent from '../components/library-item/library-item.jsx';
import storage from '../lib/storage';

class LibraryItem extends React.PureComponent {
constructor (props) {
Expand Down Expand Up @@ -106,7 +107,7 @@ class LibraryItem extends React.PureComponent {
render () {
const iconMd5 = this.curIconMd5();
const iconURL = iconMd5 ?
`https://cdn.assets.scratch.mit.edu/internalapi/asset/${iconMd5}/get/` :
`${storage.cdnHost}project/asset/${iconMd5}` :
this.props.iconRawURL;
return (
<LibraryItemComponent
Expand Down
11 changes: 9 additions & 2 deletions packages/gui/src/lib/project-fetcher-hoc.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const ProjectFetcherHOC = function (WrappedComponent) {
storage.setProjectHost(props.projectHost);
storage.setProjectToken(props.projectToken);
storage.setAssetHost(props.assetHost);
storage.setCdnHost(props.cdnHost);
storage.setTranslatorFunction(props.intl.formatMessage);
// props.projectId might be unset, in which case we use our default;
// or it may be set by an even higher HOC, and passed to us.
Expand All @@ -62,6 +63,9 @@ const ProjectFetcherHOC = function (WrappedComponent) {
if (prevProps.assetHost !== this.props.assetHost) {
storage.setAssetHost(this.props.assetHost);
}
if (prevProps.cdnHost !== this.props.cdnHost) {
storage.setCdnHost(this.props.cdnHost);
}
if (this.props.isFetchingWithId && !prevProps.isFetchingWithId) {
this.fetchProject(this.props.reduxProjectId, this.props.loadingState);
}
Expand Down Expand Up @@ -93,6 +97,7 @@ const ProjectFetcherHOC = function (WrappedComponent) {
const {
/* eslint-disable no-unused-vars */
assetHost,
cdnHost,
intl,
isLoadingProject: isLoadingProjectProp,
loadingState,
Expand All @@ -119,6 +124,7 @@ const ProjectFetcherHOC = function (WrappedComponent) {
ProjectFetcherComponent.propTypes = {
assetHost: PropTypes.string,
canSave: PropTypes.bool,
cdnHost: PropTypes.string,
intl: intlShape.isRequired,
isCreatingNew: PropTypes.bool,
isFetchingWithId: PropTypes.bool,
Expand All @@ -136,8 +142,9 @@ const ProjectFetcherHOC = function (WrappedComponent) {
setProjectId: PropTypes.func
};
ProjectFetcherComponent.defaultProps = {
assetHost: 'https://assets.scratch.mit.edu',
projectHost: 'https://projects.scratch.mit.edu'
assetHost: 'https://api.codingclip.com/v1/',
cdnHost: 'https://static.codingclip.com/v1/',
projectHost: 'https://api.codingclip.com/v1'
};

const mapStateToProps = state => ({
Expand Down
26 changes: 21 additions & 5 deletions packages/gui/src/lib/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ type Translator = ((messageId: string, defaultMessage?: string, description?: st

type ConfigResponse = string | {
url: string;
withCredentials: boolean;
withCredentials?: boolean;
headers?: Record<string, string>;
method?: 'post';
};

Expand Down Expand Up @@ -41,6 +42,8 @@ class Storage extends ScratchStorage {
private projectHost = '';
private projectToken = '';
private assetHost = '';
private cdnHost = '';
private authorizationToken = '';
private translator: Translator;

constructor () {
Expand Down Expand Up @@ -79,7 +82,7 @@ class Storage extends ScratchStorage {
}

getProjectGetConfig (projectAsset: Asset): ConfigResponse {
const path = `${this.projectHost}/${projectAsset.assetId}`;
const path = `${this.projectHost}project/json/${projectAsset.assetId}`;
const qs = this.projectToken ? `?token=${this.projectToken}` : '';
return path + qs;
}
Expand All @@ -102,19 +105,32 @@ class Storage extends ScratchStorage {
this.assetHost = assetHost;
}

setCdnHost (cdnHost: string): void {
this.cdnHost = cdnHost;
}

setAuthorizationToken (token: string): void {
this.authorizationToken = `Bearer ${token}`;
}

getAssetGetConfig (asset: Asset): ConfigResponse {
return `${this.assetHost}/internalapi/asset/${asset.assetId}.${asset.dataFormat}/get/`;
return {
url: `${this.cdnHost}project/asset/${asset.assetId}.${asset.dataFormat}`,
headers: {referer: location.host}
};
}

getAssetCreateConfig (asset: Asset): ConfigResponse {
const headers = this.authorizationToken ? {authorization: this.authorizationToken} : undefined;
return {
// There is no such thing as updating assets, but storage assumes it
// should update if there is an assetId, and the asset store uses the
// assetId as part of the create URI. So, force the method to POST.
// Then when storage finds this config to use for the "update", still POSTs
method: 'post',
url: `${this.assetHost}/${asset.assetId}.${asset.dataFormat}`,
withCredentials: true
url: `${this.assetHost}project/uploadAsset/${asset.assetId}.${asset.dataFormat}`,
withCredentials: true,
headers
};
}

Expand Down
4 changes: 3 additions & 1 deletion packages/gui/test/integration/costumes.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ const {
// The costumes library is slow to load. Increase the timeout for these tests.
jest.setTimeout(60_000);

const abbyCostumeURL = 'https://static.codingclip.com/v1/project/asset/45de34b47a2ce22f6f5d28bb35a44ff5.svg';

const uri = path.resolve(__dirname, '../../build/index.html');

let driver;
Expand Down Expand Up @@ -211,7 +213,7 @@ describe('Working with costumes', () => {
.mouseMove(abbyElement)
.perform();
// wait for one of Abby's alternate costumes to appear
await findByXpath('//img[@src="https://cdn.assets.scratch.mit.edu/internalapi/asset/45de34b47a2ce22f6f5d28bb35a44ff5.svg/get/"]');
await findByXpath(`//img[@src="${abbyCostumeURL}"]`);
const logs = await getLogs();
await expect(logs).toEqual([]);
});
Expand Down
4 changes: 3 additions & 1 deletion packages/storage/test/integration/download-known-assets.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ const test = require('tap').test;

const ScratchStorage = require('../../dist/node/scratch-storage');

const ASSET_SERVER = 'https://static.codingclip.com/v1/';

let storage;
test('constructor', t => {
storage = new ScratchStorage();
Expand Down Expand Up @@ -79,7 +81,7 @@ test('addWebSource', t => {
t.doesNotThrow(() => {
storage.addWebSource(
[storage.AssetType.ImageVector, storage.AssetType.ImageBitmap, storage.AssetType.Sound],
asset => `https://cdn.assets.scratch.mit.edu/internalapi/asset/${asset.assetId}.${asset.dataFormat}/get/`
asset => `${ASSET_SERVER}project/asset/${asset.assetId}.${asset.dataFormat}`
);
});
t.end();
Expand Down
12 changes: 2 additions & 10 deletions packages/vm/test/fixtures/make-test-storage.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {ScratchStorage} from 'clipcc-storage';

const ASSET_SERVER = 'https://cdn.assets.scratch.mit.edu/';
const ASSET_SERVER = 'https://static.codingclip.com/v1/';
const PROJECT_SERVER = 'https://cdn.projects.scratch.mit.edu/';

/**
Expand All @@ -21,15 +21,7 @@ const getProjectUrl = function (asset) {
* @returns {string} a URL to download a project asset (PNG, WAV, etc.)
*/
const getAssetUrl = function (asset) {
const assetUrlParts = [
ASSET_SERVER,
'internalapi/asset/',
asset.assetId,
'.',
asset.dataFormat,
'/get/'
];
return assetUrlParts.join('');
return `${ASSET_SERVER}project/asset/${asset.assetId}.${asset.dataFormat}`;
};

/**
Expand Down
Loading