duplicate saftey
[KisSync.git] / src / channel-storage / filestore.js
blob7c03dfed2d8b4bdca25ee7b34b21a371ff01d891
1 import Promise from 'bluebird';
2 import { stat } from 'fs';
3 import * as fs from 'graceful-fs';
4 import path from 'path';
5 import { ChannelStateSizeError } from '../errors';
7 const readFileAsync = Promise.promisify(fs.readFile);
8 const writeFileAsync = Promise.promisify(fs.writeFile);
9 const readdirAsync = Promise.promisify(fs.readdir);
10 const statAsync = Promise.promisify(stat);
11 const SIZE_LIMIT = 1048576;
12 const CHANDUMP_DIR = path.resolve(__dirname, '..', '..', 'chandump');
14 export class FileStore {
15     filenameForChannel(channelName) {
16         return path.join(CHANDUMP_DIR, channelName);
17     }
19     load(id, channelName) {
20         const filename = this.filenameForChannel(channelName);
21         return statAsync(filename).then(stats => {
22             if (stats.size > SIZE_LIMIT) {
23                 return Promise.reject(
24                     new ChannelStateSizeError(
25                         'Channel state file is too large',
26                         {
27                             limit: SIZE_LIMIT,
28                             actual: stats.size
29                         }
30                     )
31                 );
32             } else {
33                 return readFileAsync(filename);
34             }
35         }).then(fileContents => {
36             try {
37                 return JSON.parse(fileContents);
38             } catch (e) {
39                 return Promise.reject(new Error('Channel state file is not valid JSON: ' + e));
40             }
41         });
42     }
44     async save(id, channelName, data) {
45         let original;
46         try {
47             original = await this.load(id, channelName);
48         } catch (error) {
49             if (error.code !== 'ENOENT') {
50                 throw error;
51             } else {
52                 original = {};
53             }
54         }
56         Object.keys(data).forEach(key => {
57             original[key] = data[key];
58         });
60         const filename = this.filenameForChannel(channelName);
61         const fileContents = new Buffer(JSON.stringify(original), 'utf8');
62         if (fileContents.length > SIZE_LIMIT) {
63             throw new ChannelStateSizeError(
64                 'Channel state size is too large',
65                 {
66                     limit: SIZE_LIMIT,
67                     actual: fileContents.length
68                 }
69             );
70         }
72         return await writeFileAsync(filename, fileContents);
73     }
75     listChannels() {
76         return readdirAsync(CHANDUMP_DIR);
77     }