UNPKG

5.99 kBJavaScriptView Raw
1var utils = require('../utils')
2var isbinaryfile = require('isbinaryfile')
3var fs = require('fs-extra')
4var chokidar = require('chokidar')
5
6module.exports = {
7 trackDownStreamUpdate: {},
8 websocket: null,
9 alreadyNotified: {},
10
11 setWebSocket: function (websocket) {
12 this.websocket = websocket
13 },
14
15 sharedFolder: function (currentSharedFolder, readOnly) {
16 this.currentSharedFolder = currentSharedFolder
17 this.readOnly = readOnly
18 if (this.websocket.connection) this.websocket.send(message('rootFolderChanged', {}))
19 },
20
21 list: function (args, cb) {
22 try {
23 cb(null, utils.walkSync(this.currentSharedFolder, {}, this.currentSharedFolder))
24 } catch (e) {
25 cb(e.message)
26 }
27 },
28
29 resolveDirectory: function (args, cb) {
30 try {
31 var path = utils.absolutePath(args.path, this.currentSharedFolder)
32 if (this.websocket && !this.alreadyNotified[path]) {
33 this.alreadyNotified[path] = 1
34 this.setupNotifications(path)
35 }
36 cb(null, utils.resolveDirectory(path, this.currentSharedFolder))
37 } catch (e) {
38 cb(e.message)
39 }
40 },
41
42 folderIsReadOnly: function (args, cb) {
43 return cb(null, this.readOnly)
44 },
45
46 get: function (args, cb) {
47 var path = utils.absolutePath(args.path, this.currentSharedFolder)
48 if (!fs.existsSync(path)) {
49 return cb('File not found ' + path)
50 }
51 if (!isRealPath(path, cb)) return
52 isbinaryfile(path, (error, isBinary) => {
53 if (error) console.log(error)
54 if (isBinary) {
55 cb(null, { content: '<binary content not displayed>', readonly: true })
56 } else {
57 fs.readFile(path, 'utf8', (error, data) => {
58 if (error) console.log(error)
59 cb(error, { content: data, readonly: false })
60 })
61 }
62 })
63 },
64
65 exists: function (args, cb) {
66 const path = utils.absolutePath(args.path, this.currentSharedFolder)
67
68 cb(null, fs.existsSync(path))
69 },
70
71 set: function (args, cb) {
72 if (this.readOnly) return cb('Cannot write file: read-only mode selected')
73 const isFolder = args.path.endsWith('/')
74 var path = utils.absolutePath(args.path, this.currentSharedFolder)
75 if (fs.existsSync(path) && !isRealPath(path, cb)) return
76 if (args.content === 'undefined') { // no !!!!!
77 console.log('trying to write "undefined" ! stopping.')
78 return
79 }
80 this.trackDownStreamUpdate[path] = path
81 if (isFolder) {
82 fs.mkdirp(path).then(_ => cb()).catch(e => cb(e))
83 } else {
84 fs.ensureFile(path).then(() => {
85 fs.writeFile(path, args.content, 'utf8', (error, data) => {
86 if (error) console.log(error)
87 cb(error, data)
88 })
89 }).catch(e => cb(e))
90 }
91 },
92
93 rename: function (args, cb) {
94 if (this.readOnly) return cb('Cannot rename file: read-only mode selected')
95 var oldpath = utils.absolutePath(args.oldPath, this.currentSharedFolder)
96 if (!fs.existsSync(oldpath)) {
97 return cb('File not found ' + oldpath)
98 }
99 var newpath = utils.absolutePath(args.newPath, this.currentSharedFolder)
100 if (!isRealPath(oldpath, cb)) return
101 fs.move(oldpath, newpath, (error, data) => {
102 if (error) console.log(error)
103 cb(error, data)
104 })
105 },
106
107 remove: function (args, cb) {
108 if (this.readOnly) return cb('Cannot remove file: read-only mode selected')
109 var path = utils.absolutePath(args.path, this.currentSharedFolder)
110 if (!fs.existsSync(path)) {
111 return cb('File not found ' + path)
112 }
113 if (!isRealPath(path, cb)) return
114 fs.remove(path, (error) => {
115 if (error) {
116 console.log(error)
117 return cb('Failed to remove file/directory: ' + error)
118 }
119 cb(error, true)
120 })
121 },
122
123 isDirectory: function (args, cb) {
124 const path = utils.absolutePath(args.path, this.currentSharedFolder)
125
126 cb(null, fs.statSync(path).isDirectory())
127 },
128
129 isFile: function (args, cb) {
130 const path = utils.absolutePath(args.path, this.currentSharedFolder)
131
132 cb(null, fs.statSync(path).isFile())
133 },
134
135 setupNotifications: function (path) {
136 if (!isRealPath(path)) return
137 var watcher = chokidar.watch(path, { depth: 0, ignorePermissionErrors: true })
138 console.log('setup notifications for ' + path)
139 /* we can't listen on created file / folder
140 watcher.on('add', (f, stat) => {
141 isbinaryfile(f, (error, isBinary) => {
142 if (error) console.log(error)
143 console.log('add', f)
144 if (this.websocket.connection) this.websocket.send(message('created', { path: utils.relativePath(f, this.currentSharedFolder), isReadOnly: isBinary, isFolder: false }))
145 })
146 })
147 watcher.on('addDir', (f, stat) => {
148 if (this.websocket.connection) this.websocket.send(message('created', { path: utils.relativePath(f, this.currentSharedFolder), isReadOnly: false, isFolder: true }))
149 })
150 */
151 watcher.on('change', (f, curr, prev) => {
152 if (this.trackDownStreamUpdate[f]) {
153 delete this.trackDownStreamUpdate[f]
154 return
155 }
156 if (this.websocket.connection) this.websocket.send(message('changed', utils.relativePath(f, this.currentSharedFolder)))
157 })
158 watcher.on('unlink', (f) => {
159 if (this.websocket.connection) this.websocket.send(message('removed', { path: utils.relativePath(f, this.currentSharedFolder), isFolder: false }))
160 })
161 watcher.on('unlinkDir', (f) => {
162 if (this.websocket.connection) this.websocket.send(message('removed', { path: utils.relativePath(f, this.currentSharedFolder), isFolder: true }))
163 })
164 }
165}
166
167function isRealPath (path, cb) {
168 var realPath = fs.realpathSync(path)
169 var isRealPath = path === realPath
170 var mes = '[WARN] Symbolic link modification not allowed : ' + path + ' | ' + realPath
171 if (!isRealPath) {
172 console.log('\x1b[33m%s\x1b[0m', mes)
173 }
174 if (cb && !isRealPath) cb(mes)
175 return isRealPath
176}
177
178function message (name, value) {
179 return JSON.stringify({ type: 'notification', scope: 'sharedfolder', name: name, value: value })
180}