Skip to content

Commit

Permalink
Merge pull request #38 from sladkoff/master
Browse files Browse the repository at this point in the history
Allow changing the cache root directory
  • Loading branch information
kfiroo committed Jul 19, 2017
2 parents c984ff6 + 50fbb5b commit 6aac317
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 17 deletions.
9 changes: 6 additions & 3 deletions CachedImage.js
Expand Up @@ -47,15 +47,17 @@ const CachedImage = React.createClass({
React.PropTypes.bool,
React.PropTypes.array
]).isRequired,
resolveHeaders: React.PropTypes.func
resolveHeaders: React.PropTypes.func,
cacheLocation: React.PropTypes.string
},

getDefaultProps() {
return {
renderImage: props => (<Image ref={CACHED_IMAGE_REF} {...props}/>),
activityIndicatorProps: {},
useQueryParamsInCacheKey: false,
resolveHeaders: () => Promise.resolve({})
resolveHeaders: () => Promise.resolve({}),
cacheLocation: ImageCacheProvider.LOCATION.CACHE
};
},

Expand Down Expand Up @@ -117,7 +119,8 @@ const CachedImage = React.createClass({
processSource(source) {
const url = _.get(source, ['uri'], null);
if (ImageCacheProvider.isCacheable(url)) {
const options = _.pick(this.props, ['useQueryParamsInCacheKey', 'cacheGroup']);
const options = _.pick(this.props, ['useQueryParamsInCacheKey', 'cacheGroup', 'cacheLocation']);

// try to get the image path from cache
ImageCacheProvider.getCachedImagePath(url, options)
// try to put the image in cache if
Expand Down
44 changes: 31 additions & 13 deletions ImageCacheProvider.js
Expand Up @@ -8,7 +8,10 @@ const {
fs
} = RNFetchBlob;

const baseCacheDir = fs.dirs.CacheDir + '/imagesCacheDir';
const LOCATION = {
CACHE: fs.dirs.CacheDir + '/imagesCacheDir',
BUNDLE: fs.dirs.MainBundleDir + '/imagesCacheDir'
};

const SHA1 = require("crypto-js/sha1");
const URL = require('url-parse');
Expand All @@ -18,7 +21,8 @@ const defaultImageTypes = ['png', 'jpeg', 'jpg', 'gif', 'bmp', 'tiff', 'tif'];
const defaultResolveHeaders = _.constant(defaultHeaders);

const defaultOptions = {
useQueryParamsInCacheKey: false
useQueryParamsInCacheKey: false,
cacheLocation: LOCATION.CACHE
};

const activeDownloads = {};
Expand Down Expand Up @@ -58,6 +62,10 @@ function generateCacheKey(url, options) {
return SHA1(cacheable) + '.' + type;
}

function getBaseDir(cacheLocation) {
return cacheLocation || LOCATION.CACHE;
}

function getCachePath(url, options) {
if (options.cacheGroup) {
return options.cacheGroup;
Expand All @@ -72,7 +80,7 @@ function getCachedImageFilePath(url, options) {
const cachePath = getCachePath(url, options);
const cacheKey = generateCacheKey(url, options);

return `${baseCacheDir}/${cachePath}/${cacheKey}`;
return `${getBaseDir(options.cacheLocation)}/${cachePath}/${cacheKey}`;
}

function deleteFile(filePath) {
Expand All @@ -90,9 +98,16 @@ function getDirPath(filePath) {

function ensurePath(dirPath) {
return fs.isDir(dirPath)
.then(exists =>
!exists && fs.mkdir(dirPath)
)
.then(isDir => {
if (!isDir) {
return fs.mkdir(dirPath)
.then(() => fs.exists(dirPath).then(exists => {
// Check if dir has indeed been created because
// there's no exception on incorrect user-defined paths (?)...
if (!exists) throw new Error('Invalid cacheLocation');
}))
}
})
.catch(err => {
// swallow folder already exists errors
if (err.message.includes('folder already exists')) {
Expand Down Expand Up @@ -304,23 +319,25 @@ function seedCache(local, url, options = defaultOptions) {

/**
* Clear the entire cache.
* @param cacheLocation
* @returns {Promise}
*/
function clearCache() {
return fs.unlink(baseCacheDir)
function clearCache(cacheLocation) {
return fs.unlink(getBaseDir(cacheLocation))
.catch(() => {
// swallow exceptions if path doesn't exist
})
.then(() => ensurePath(baseCacheDir));
.then(() => ensurePath(getBaseDir(cacheLocation)));
}

/**
* Return info about the cache, list of files and the total size of the cache.
* @param cacheLocation
* @returns {Promise.<{size}>}
*/
function getCacheInfo() {
return ensurePath(baseCacheDir)
.then(() => collectFilesInfo(baseCacheDir))
function getCacheInfo(cacheLocation) {
return ensurePath(getBaseDir(cacheLocation))
.then(() => collectFilesInfo(getBaseDir(cacheLocation)))
.then(cache => {
const files = _.flattenDeep(cache);
const size = _.sumBy(files, 'size');
Expand All @@ -341,5 +358,6 @@ module.exports = {
deleteMultipleCachedImages,
clearCache,
seedCache,
getCacheInfo
getCacheInfo,
LOCATION
};
5 changes: 4 additions & 1 deletion README.md
Expand Up @@ -50,9 +50,11 @@ When providing `source={{uri: 'https://example.com/path/to/remote/image.jpg'}}`
* `useQueryParamsInCacheKey` - _array|bool_ an array of keys to use from the `source.uri` query string or a bool value stating whether to use the entire query string or not. **(default: false)**
* `defaultSource` - prop to display a background image while the source image is downloaded. This will work even in android, but will not display background image if there you set borderRadius on this component style prop
* `resolveHeaders` - _function_ when provided, the returned object will be used as the headers object when sending the request to download the image. **(default: () => Promise.resolve({}))**
* `cacheLocation` - _string_ allows changing the root directory to use for caching. The default directory is sufficient for most use-cases. Images in this directory may be purged by Android automatically to free up space. Use `ImageCacheProvider.LOCATION.BUNDLE` if the cached images are critical (you will have to manage cleanup manually). **(default: ImageCacheProvider.LOCATION.CACHE)**
* `loadingIndicator` - _component_ prop to set custom `ActivityIndicator`.
* `fallbackSource` - prop to set placeholder image. when `source.uri` is null or cached failed, the `fallbackSource` will be display.


### ImageCacheProvider
`ImageCacheProvider` exposes interaction with the cache layer that is used by `CachedImage` so you can use it to prefetch some urls in the background while you app is starting,
or remove some outdated images from the cache to free some space up if needed.
Expand Down Expand Up @@ -80,9 +82,10 @@ ImageCacheProvider.deleteMultipleCachedImages([

#### `type: CacheOptions`
```
type ReadDirItem = {
type CacheOptions = {
useQueryParamsInCacheKey: string[]|bool; // same as the CachedImage props
cacheGroup: string; // the directory to save cached images in, defaults to the url hostname
cacheLocation: string; // the root directory to use for caching, corresponds to CachedImage prop of same name, defaults to system cache directory
};
```

Expand Down

0 comments on commit 6aac317

Please sign in to comment.