forked from LaKing/ep_codepad
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhandleButtonMessage.js
More file actions
288 lines (246 loc) · 12.1 KB
/
Copy pathhandleButtonMessage.js
File metadata and controls
288 lines (246 loc) · 12.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
var crypto = require('crypto');
var padManager = require("ep_etherpad-lite/node/db/PadManager");
var fs = require('fs');
var settings = require('ep_etherpad-lite/node/utils/Settings');
var authorManager = require('ep_etherpad-lite/node/db/AuthorManager');
var sessionManager = require('ep_etherpad-lite/node/db/SessionManager');
// this should be overridden in codepad conf
var project_path = '/tmp/';
if (!settings.ep_codepad) {
console.log(" Codepad needs ep_codepad parameters in settings.json.");
} else {
if (!settings.ep_codepad.project_path) {
console.log(" No ep_codepad.project_path set in settings.json.");
} else project_path = settings.ep_codepad.project_path + "/";
}
// messages constants
var msg_push = 'PUSH_TO_FILESYSTEM';
var msg_write = 'WRITE_TO_FILESYSTEM';
var msg_read = 'READ_FROM_FILESYSTEM';
// code beutifier
var beautify = require('js-beautify').js_beautify;
var beautify_css = require('js-beautify').css;
var beautify_html = require('js-beautify').html;
var exec = require("child_process").exec;
var getBrush = require('./extensions.js').getBrush;
// code syntax checker
var jshint = require('jshint').JSHINT;
var cb = function() {};
var padMessageHandler = require("ep_etherpad-lite/node/handler/PadMessageHandler");
var send_ok = function(padid)
{
var ok_msg = {
type: 'COLLABROOM',
data: {
type: "CUSTOM",
payload: {
padId: padid,
from: "codepad",
errors: null
}
}
};
padMessageHandler.handleCustomObjectMessage(ok_msg, undefined, cb);
};
exports.handleMessage = function(hook_name, context, callback) {
if (context.message && context.message.data) {
var msg = context.message.data.type;
console.log("MSG: " + msg);
if (msg == msg_read) {
padManager.getPad(context.message.data.padId, null, function(err, value) {
var padid = context.message.data.padId;
var path = project_path + padid;
// remove newline character from the end of the string.
var text = value.atext.text.slice(0, -1);
fs.readFile(path, function(err, data) {
if (err) {
// notify user about the read error
console.log("codepad-read-error " + path);
var err_msg = {
type: 'COLLABROOM',
data: {
type: "CUSTOM",
payload: {
padId: padid,
from: "fs",
errors: err
}
}
};
padMessageHandler.handleCustomObjectMessage(err_msg, undefined, cb);
callback(null);
} else {
var adat = data.toString();
if (adat !== text) {
value.setText(adat);
padMessageHandler.updatePadClients(value, cb);
}
send_ok(padid);
}
});
});
callback(null);
}
if (msg == msg_write || msg == msg_push) {
padManager.getPad(context.message.data.padId, null, function(err, value) {
var padid = context.message.data.padId;
var padsi = padid.indexOf('/');
var folder = '';
// since EEXISTS is an error, we skip that error
// there will be a message if the write failes anyway
mkdir_err = function(err) {};
// create subfolders
while (padsi > 0) {
folder = padid.substring(0, padsi);
fs.mkdir(project_path + folder, mkdir_err);
padsi = padid.indexOf('/', 1 + folder.length);
}
// full path to write the file to
var path = project_path + padid;
// get the file extension/brush
var ext = getBrush(padid);
// if all ok, send only one OK message.
var all_is_ok = true;
// the beutified or the raw text of the pad
// remove newline character from the end of the string.
var text = value.atext.text.slice(0, -1);
var beat = text;
// if .js file beautify
if (ext == 'js') {
//check for missing semiciolons forst
if (msg == msg_push && !jshint(text)) {
// determine if semicolons should be added at the end of line
var check = function(errors, line, length) {
var count = 0;
var chpos = 0;
errors.forEach(function(err) {
if (err) {
// err.line range is 1..n while line is 1..m
if (err.line == line + 1) {
count++;
if (err.code == 'W033') chpos = err.character;
// TODO ... maybe it should abort the whole process if there was another error
}
}
});
if (count === 1 && chpos !== 0 && length < chpos) return true;
else return false;
};
// Add the semicolons
var lines = text.split('\n');
beat = '';
for (var i = 0; i < lines.length; i++) {
//code here using lines[i] which will give you each line
if (check(jshint.errors, i, lines[i].length))
beat += lines[i] + ';' + '\n';
else beat += lines[i] + '\n';
}
}
// if push and jshint said ok, then beautify text for real
if (msg == msg_push && jshint(text)) beat = beautify(text, {
indent_size: 4
});
// re-check the new beautified code
if (!jshint(beat)) {
// still has errors, we put them to the console log on the server
jshint.errors.forEach(function(err) {
if (err) {
console.info(" ! " + padid + ":" + err.line + ":" + err.character + " " + err.reason + "|" + err.evidence);
// more detailed if you wish
//console.info(" ! " + padid + ":" + err.line + ":" + err.character + " " + err.reason + " !" + err.scope + "|" + err.evidence + "|" + err.id + "|" + err.code + "|" + err.raw);
}
});
all_is_ok = false;
var err_msg = {
type: 'COLLABROOM',
data: {
type: "CUSTOM",
payload: {
padId: padid,
from: "jshint",
errors: jshint.errors
}
}
};
padMessageHandler.handleCustomObjectMessage(err_msg, undefined, cb);
}
}
// if .css file beautify
if (ext == 'css' && msg == msg_push) {
beat = beautify_css(text, {
indent_size: 4
});
}
// if .html file beautify
if (ext == 'xml' && msg == msg_push) {
beat = beautify_html(text, {
indent_size: 4
});
}
// text and beat may be different, depending on jsHint and the beutifier
if (text !== beat) {
value.setText(beat);
padMessageHandler.updatePadClients(value, cb);
}
// WRITE to the FILE
fs.writeFile(path, beat, function(err) {
if (err) {
all_is_ok = false;
console.log("Failed to write text to " + path);
var err_msg = {
type: 'COLLABROOM',
data: {
type: "CUSTOM",
payload: {
padId: padid,
from: "fs",
errors: err
}
}
};
padMessageHandler.handleCustomObjectMessage(err_msg, undefined, cb);
} else {
console.log("Wrote pad contents to " + path);
// if push_action is defined in settings.json, it will run here, use it for git/svn/hg ... or whatever.
if (settings.ep_codepad && msg == msg_push) {
if (settings.ep_codepad.push_action) {
exec(settings.ep_codepad.push_action, function(exec_err, stdout, stderr) {
if (stdout) console.log("[codepad] push_action stdout: " + stdout);
if (stderr) console.log("[codepad] push_action stderr: " + stderr);
if (exec_err) {
console.log('[codepad] push_action !error: ', exec_err);
var err_msg = {
type: 'COLLABROOM',
data: {
type: "CUSTOM",
payload: {
padId: padid,
from: "exec",
errors: exec_err
}
}
};
padMessageHandler.handleCustomObjectMessage(err_msg, undefined, cb);
} else if (all_is_ok) send_ok(padid);
});
} else if (all_is_ok) send_ok(padid);
} else if (all_is_ok) send_ok(padid);
}
});
});
callback(null);
} //END if (msg == msg_write || msg == msg_push)
} //END if (context.message && context.message.data)
callback();
}; //END exports.handleMessage
/// jshint - quickhelp
/* An example from err.
"id": "(error)",
"raw": "Missing semicolon.",
"code": "W033",
"evidence": " };",
"line": 6,
"character": 5,
"scope": "(main)",
"reason": "Missing semicolon."
*****/