molly-db 1.2.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
package/main.js CHANGED
@@ -1,8 +1,10 @@
1
- const worker = require('worker_threads');
2
- const url = require('url');
1
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
2
+
3
+ const path = require('path');
4
+ const url = require('url');
3
5
  const fs = require('fs');
4
6
 
5
- /* --------------------------------------------------------------------------------------- */
7
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
6
8
 
7
9
  function config( _config ) {
8
10
  const _default = { offset:0, length:100 };
@@ -12,19 +14,26 @@ function config( _config ) {
12
14
  });
13
15
  }
14
16
 
15
- /* --------------------------------------------------------------------------------------- */
17
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
16
18
 
17
19
  class molly_db{
18
- constructor( opt ){ if( opt.pass )
19
- this.pass = opt.pass; this.port = opt.port || 27017;
20
- this.path = opt.path.replace( /^\./,process.cwd() );
21
- this.threads = opt.threads || 1;
22
- this.import = opt.import || '';
20
+ constructor( opt ){
21
+ if(opt.pass) this.pass = opt.pass; this.port = opt.port || 27017;
22
+ const dir = path.join(__dirname,'/module/worker_handler.js');
23
+
24
+ if( !(new RegExp(process.cwd())).test(opt.path) )
25
+ this.path = path.join(process.cwd(),opt.path);
26
+ else this.path = opt.path;
27
+
28
+ this.protocol = opt.protocol || 'http';
23
29
  this.time = opt.saveTime || .1;
24
- return require(`${__dirname}/module/_worker_.js`)(this);
30
+ this.import = opt.import || '';
31
+ this.threads = opt.thread|| 1;
32
+
33
+ return require(dir)(this);
25
34
  }
26
35
  }
27
36
 
28
- /* --------------------------------------------------------------------------------------- */
37
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
29
38
 
30
39
  module.exports = molly_db;
@@ -0,0 +1,45 @@
1
+ const cluster = require('cluster');
2
+ const {Buffer} = require('buffer');
3
+ const output = new Object();
4
+
5
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
6
+
7
+ output.http = function(req,res){
8
+
9
+ if( req.method != 'POST' ){
10
+ res.writeHead(200,{'content-type': 'text/plain'});
11
+ return res.end('Only Post Method Avalilable');
12
+ } const raw = new Array();
13
+
14
+ req.on('close',()=>{ process.send(Buffer.concat(raw)) });
15
+ req.on('data',(chunk)=>{ raw.push(chunk) });
16
+
17
+ cluster.worker.once('message',(msg)=>{
18
+ const status = msg.match(/\d+/i)[0];
19
+ res.writeHead(status,{'content-type': 'text/plain'});
20
+ res.write(msg); res.end();
21
+ })
22
+
23
+ }
24
+
25
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
26
+
27
+ output.WebSocket = function( message,client ){
28
+ cluster.worker.once('message',(msg)=>{
29
+ client.send(msg);
30
+ }); process.send(message);
31
+ }
32
+
33
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
34
+
35
+ output.Socket = function( message,client ){
36
+ cluster.worker.once('message',(msg)=>{
37
+ client.write(msg);
38
+ }); process.send(message);
39
+ }
40
+
41
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
42
+
43
+ module.exports = output;
44
+
45
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
@@ -0,0 +1,63 @@
1
+ const crypto = require('crypto-js');
2
+ const {Buffer} = require('buffer');
3
+ const output = new Object();
4
+
5
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
6
+
7
+ const JsonFormatter = {
8
+
9
+ 'stringify': function(cipherParams) {
10
+ var jsonObj = { ct: cipherParams.ciphertext.toString(crypto.enc.Base64) };
11
+ if (cipherParams.salt) jsonObj.s = cipherParams.salt.toString();
12
+ if (cipherParams.iv) jsonObj.iv = cipherParams.iv.toString();
13
+ return new Buffer.from(JSON.stringify(jsonObj)).toString('base64');
14
+ },
15
+
16
+ 'parse': function(jsonStr) {
17
+ var jsonObj = JSON.parse( new Buffer.from(jsonStr,'base64').toString());
18
+ var cipherParams = crypto.lib.CipherParams.create({
19
+ ciphertext: crypto.enc.Base64.parse(jsonObj.ct)
20
+ });
21
+ if (jsonObj.iv) cipherParams.iv = crypto.enc.Hex.parse(jsonObj.iv);
22
+ if (jsonObj.s) cipherParams.salt = crypto.enc.Hex.parse(jsonObj.s);
23
+ return cipherParams;
24
+ }
25
+
26
+ };
27
+
28
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
29
+
30
+ output.slugify = (str)=>{
31
+ [
32
+ ['e','é|è|ê|ë'],
33
+ ['i','í|ì|î|ï'],
34
+ ['u','ú|ù|û|ü'],
35
+ ['o','ó|ò|ô|õ|ö'],
36
+ ['a','á|à|ã|â|ä'],
37
+ ['c','ç'],['n','ñ'],
38
+ ['' ,/\s+|\W+|\n| /],
39
+ ].map(x=>{
40
+ const regex = new RegExp(x[1],'gi');
41
+ str = str.replace( regex,x[0] );
42
+ }); return str.toLowerCase();
43
+ }
44
+
45
+ output.hash = (data,nonce)=>{ return crypto.SHA256(Math.random+data+nonce).toString(); }
46
+
47
+ output.encrypt = ( _message,_password )=>{
48
+ try{ if( _password )
49
+ return crypto.AES.encrypt( _message,_password,{ format: JsonFormatter })
50
+ .toString(); return _message;
51
+ } catch(e) { return _message; }
52
+ }
53
+
54
+ output.decrypt = ( _message,_password )=>{
55
+ try{ if( _password )
56
+ return crypto.AES.decrypt( _message,_password,{ format: JsonFormatter })
57
+ .toString( crypto.enc.Utf8 ); return _message;
58
+ } catch(e) { return _message; }
59
+ }
60
+
61
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
62
+
63
+ module.exports = output;
@@ -0,0 +1,66 @@
1
+ const crypto = require('./crypto_handler')
2
+ const fetch = require('molly-fetch');
3
+ const readline = require('readline');
4
+ const path = require('path');
5
+ const fs = require('fs');
6
+ const db = new Object();
7
+
8
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
9
+
10
+ function fillDB( _db, _table, _path, _pass ){
11
+ return new Promise(async(response,reject)=>{
12
+
13
+ let _itr = undefined;
14
+
15
+ if( (/^http/).test(_path) ){ try{
16
+ const stream = await fetch(_path,{responseType:'stream'});
17
+ _itr = readline.createInterface({ input: stream.data });
18
+ } catch(e) { return response(`error reading ${_path}`); }}
19
+
20
+ else if( fs.existsSync(_path) )
21
+ _itr = readline.createInterface({
22
+ input: fs.createReadStream(_path)
23
+ });
24
+
25
+ else { return response(`error reading ${_path}`); }
26
+
27
+ _itr.on('line',(line)=>{
28
+ db[_db][_table].push(crypto.decrypt( line,_pass ));
29
+ }); _itr.on('close',()=>{ response() });
30
+
31
+ });
32
+ }
33
+
34
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
35
+
36
+ module.exports = function(args){
37
+ return new Promise(async(response,reject)=>{
38
+ try {
39
+
40
+ const dir = path.join(args.path,'_init_.json');
41
+
42
+ db._buff_ = fs.readFileSync( dir );
43
+ db._init_ = JSON.parse( db._buff_ );
44
+ db._path_ = args.path; delete db._buff_;
45
+
46
+ for( var i in db._init_.DB ){
47
+
48
+ const DB = db._init_.DB[i]; const name = DB.name;
49
+ delete db[name]; db[name] = new Object();
50
+
51
+ for( var j in DB.tables ){
52
+ const table = DB.tables[j]; const dir = path.join(db._path_,`${table}.json`);
53
+ db[name][table] = new Array(); await fillDB( name,table,dir,args.pass );
54
+ }
55
+
56
+ }
57
+
58
+ } catch(e) {
59
+ db._init_ = {DB:[]}; db._path_ = args.path;
60
+ const dir = path.join(args.path,'_init_.json');
61
+ fs.writeFileSync( dir,JSON.stringify(db._init_) );
62
+ } response(db);
63
+ });
64
+ }
65
+
66
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
@@ -0,0 +1,18 @@
1
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
2
+
3
+ const utils = require('./utils.js');
4
+ const output = new Object();
5
+
6
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
7
+
8
+ module.exports = function( data,db ){
9
+ return new Promise((response,reject)=>{
10
+ utils.validator( db,data ).then(()=>{
11
+ try { response(Array.isArray(data) ? data.map(x=>utils[x.type](x,db)) :
12
+ utils[data.type](data,db))
13
+ } catch(e) { response(JSON.stringify({ status:404, message:`error: ${e.message}` })) }
14
+ }).catch(e=>{ reject(JSON.stringify(e)) });
15
+ })
16
+ };
17
+
18
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
@@ -0,0 +1,68 @@
1
+ const worker = require('worker_threads');
2
+ const app = require('./api_handler');
3
+ const cluster = require('cluster');
4
+ const http = require('http');
5
+ const net = require('net');
6
+ const ws = require('ws');
7
+
8
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
9
+
10
+ function createHTTPServer(){
11
+ http.createServer( app.http ).listen( process.env.port,()=>{
12
+ console.log({
13
+ protocol: 'HTTP', status: 'started',
14
+ wrkID: process.pid, port: process.env.port,
15
+ });
16
+ });
17
+ }
18
+
19
+ function createWebSocketServer(){
20
+ const srv = new ws.WebSocketServer({ port: process.env.port });
21
+ srv.on('connection',(client)=>{
22
+ client.on('message',(msg)=>app.WebSocket(msg,client));
23
+ }); console.log ({
24
+ protocol: 'WebSocket', status: 'started',
25
+ wrkID: process.pid, port: process.env.port,
26
+ });
27
+ }
28
+
29
+ function createSocketServer(){
30
+ const srv = net.createServer({ port: process.env.port });
31
+ srv.on('connection',(client)=>{
32
+ client.on('message',(msg)=>app.Socket(msg,client));
33
+ }); console.log ({
34
+ protocol: 'Socket', status: 'started',
35
+ wrkID: process.pid, port: process.env.port,
36
+ });
37
+ }
38
+
39
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
40
+
41
+ (()=>{
42
+
43
+ if( cluster.isPrimary ) {
44
+ const env = worker.workerData;
45
+ const data = worker.workerData;
46
+ for ( let i=data.threads; i--; ){
47
+
48
+ const wrk = cluster.fork(data,env);
49
+
50
+ cluster.on('exit', (wrk, code, signal) => { cluster.fork(data,env);
51
+ console.log(`wrk ${wrk.process.pid} died`);
52
+ }); wrk.on('exit', (msg)=>{ console.log(msg); });
53
+
54
+ wrk.on('message', (msg)=>{ worker.parentPort.postMessage(msg) });
55
+ worker.parentPort.on('message',(msg)=>{ wrk.send(msg) });
56
+
57
+ }
58
+ } else {
59
+ switch( process.env.protocol ){
60
+ case 'WebSocket': createWebSocketServer(); break;
61
+ case 'Socket': createSocketServer(); break;
62
+ default: createHTTPServer(); break;
63
+ }
64
+ }
65
+
66
+ })();
67
+
68
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
@@ -0,0 +1,321 @@
1
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
2
+
3
+ const crypto = require('./crypto_handler');
4
+ const path = require('path');
5
+ const output = new Object();
6
+ const fs = require('fs');
7
+
8
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
9
+
10
+ output.validator = function( db, params ){
11
+ return new Promise((response,reject)=>{
12
+
13
+ let validator = false; output.bodyParser( params );
14
+ const vdb = (key)=>{ return db._init_.DB.some(x=>{ return x.name == key; }) }
15
+ const vtb = (key)=>{ return db._init_.DB.some(x=>{ return x.tables.join().match(key); }) }
16
+
17
+ validator = [
18
+ [ !params?.offset, 'params.offset = 0' ],
19
+ [ !params?.target, 'params.target = ""' ],
20
+ [ !params?.length, 'params.length = 100' ],
21
+ ].every(x=>{ if(x[0]) eval(x[1]); return true; });
22
+
23
+ validator = [
24
+ [!params?.db, {status:404,message:'error: no db name added'}],
25
+ [!params?.table, {status:404,message:'error: no table name added'}]
26
+ ].some(x=>{ if(x[0]) reject(x[1]); return x[0];}); if(validator) return 0;
27
+
28
+ if( !(/table|db|all/gi).test(params.type) ){
29
+ validator = [
30
+ [!vdb(params?.db), {status:404,message:`erorr: no db called ${params.db} exist`}],
31
+ [!vtb(params?.table), {status:404,message:`error: no table called ${params.table} exist`}]
32
+ ].some(x=>{ if(x[0]) reject(x[1]); return x[0];}); if(validator) return 0;
33
+ }
34
+
35
+ response();
36
+ });
37
+ }
38
+
39
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
40
+
41
+ const encryptDB = function( param, db, _db, _table, _path ){
42
+ return new Promise((response,reject)=>{
43
+ const writable = fs.createWriteStream( _path+'_tmp' );
44
+ for( var i in db[_db][_table] ){
45
+
46
+ const data = db[_db][_table][i];
47
+ const ecrp = crypto.encrypt( data,param.pass );
48
+
49
+ writable.write(`${ecrp}\n`);
50
+ } writable.end();
51
+
52
+ writable.on('error',(e)=>reject(e));
53
+ writable.on('close',()=>{
54
+ fs.renameSync( _path+'_tmp', _path );
55
+ response('done');
56
+ });
57
+
58
+ });
59
+ }
60
+
61
+ const modifyDB = async function( data, db, _name, _table ){
62
+ try{
63
+
64
+ const dir = path.join(db._path_,`${_table}.json`);
65
+ const init = path.join(db._path_,'_init_.json');
66
+
67
+ fs.writeFileSync( init,JSON.stringify(db._init_) );
68
+
69
+ try{const length = db[_name][_table].length;
70
+ if( !(length>0) ) fs.writeFileSync(dir,'');
71
+ else await encryptDB( data, db, _name, _table, dir );
72
+ } catch(e) { console.log(e); fs.unlinkSync( dir ); }
73
+
74
+ } catch(e) { console.log(e); return parseError(db,data,e) }
75
+ }
76
+
77
+ const parseData = function( db,params,_data, _length ){
78
+ const length = _length||db[params.db][params.table].length;
79
+ const pagination = Math.ceil(length/_data.length)||1;
80
+ return {
81
+ status: 200, data: _data,
82
+ length: length, table: params.table,
83
+ pagination: pagination, database: params.db,
84
+ }
85
+ }
86
+
87
+ output.bodyParser = function( data ){
88
+ try{const date = Date.now(); const {body} = data;
89
+ const result = Array.isArray(body) ? body : [body];
90
+ data.body = result.map(x=>{ if( !x?.hash )
91
+ x.hash = crypto.hash( date,Math.random() );
92
+ return JSON.stringify(x);
93
+ });
94
+ } catch(e) { }
95
+ }
96
+
97
+ const parseError = function( db,params,_e ){
98
+ return {
99
+ status: 404,
100
+ table: params.table,
101
+ database: params.db,
102
+ data: _e.message||_e,
103
+ }
104
+ }
105
+
106
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
107
+
108
+ output.pop = function(data,db){ db._update_ = true;
109
+ const result = db[data.db][data.table].pop();
110
+ return parseData( db,data,result );
111
+ }
112
+ output.shift = function(data,db){ db._update_ = true;
113
+ const result = db[data.db][data.table].shift();
114
+ return parseData( db,data,result );
115
+ }
116
+ output.slice = function(data,db){
117
+ const result = db[data.db][data.table].slice(...data.args);
118
+ return parseData( db,data,result );
119
+ }
120
+
121
+ /*-- ── --*/
122
+
123
+ output.push = function( data,db ){ db._update_ = true;
124
+ const result = db[data.db][data.table].push(...data.body);
125
+ return parseData( db,data,result );
126
+ }
127
+
128
+ output.unshift = function( data,db ){ db._update_ = true;
129
+ const result = db[data.db][data.table].unshift(...data.body);
130
+ return parseData( db,data,result );
131
+ }
132
+
133
+ /*-- ── --*/
134
+
135
+ output.list = function(data,db){
136
+ try{return parseData( db,data,
137
+ db[data.db][data.table].slice(
138
+ data.offset, Number(data.offset) + Number(data.length)
139
+ ).map(x=> JSON.parse(x) )
140
+ );
141
+ } catch(e) { return parseError(db,data,e) }
142
+ }
143
+
144
+ output.hash = function(data,db){
145
+ try{const result = new Array();
146
+ db[data.db][data.table].map((x)=>{
147
+ const regex = new RegExp(data.target,'gi');
148
+ if( regex.test(x) ) result.push(x);
149
+ });
150
+ return parseData( db,data,
151
+ result.map(x=>JSON.parse(x)).slice(
152
+ data.offset, Number(data.offset) + Number(data.length)
153
+ ), result.length);
154
+ } catch(e) { return parseError(db,data,e) }
155
+ }
156
+
157
+ output.match = function(data,db){
158
+ try{const result = new Array();
159
+ db[data.db][data.table].map((x)=>{
160
+ const reg = crypto.slugify(data.target);
161
+ const regex = new RegExp(reg,'gi');
162
+ const target = crypto.slugify(x);
163
+ if( regex.test(target) ) result.push(x);
164
+ });
165
+ return parseData( db,data,
166
+ result.map(x=>JSON.parse(x)).slice(
167
+ data.offset, Number(data.offset) + Number(data.length)
168
+ ), result.length);
169
+ } catch(e) { return parseError(db,data,e) }
170
+ }
171
+
172
+ /*-- ── --*/
173
+
174
+ output.update = function(data,db){
175
+ try { db._update_ = true;
176
+ for( var i in db[data.db][data.table] ){
177
+ const regex = new RegExp(data.target,'gi');
178
+ if( regex.test(db[data.db][data.table][i]) )
179
+ return db[data.db][data.table].splice(i,1,...data.body);
180
+ }
181
+ } catch(e) { return parseError(db,data,e) }
182
+ }
183
+
184
+ output.remove = function(data,db){
185
+ try{ db._update_ = true;
186
+ for( var i in db[data.db][data.table] ){
187
+ const regex = new RegExp(data.target,'gi');
188
+ if( regex.test(db[data.db][data.table][i]) )
189
+ return db[data.db][data.table].splice(i,0);
190
+ }
191
+ } catch(e) { return parseError(db,data,e) }
192
+ }
193
+
194
+ /*-- ── --*/
195
+
196
+ output.addDB = function(data,db){
197
+ try{db._update_ = true;
198
+
199
+ if( db[data.db] ) return {
200
+ status: 404,
201
+ database: data.db,
202
+ table: data.table,
203
+ message: 'DB already exist'
204
+ };
205
+
206
+ db._init_.DB.push({
207
+ tables: [], name: data.db,
208
+ }); db[data.db] = new Array();
209
+
210
+ return {
211
+ status: 200,
212
+ message: 'DB added',
213
+ database: data.db,
214
+ };
215
+
216
+ } catch(e) { return parseError(db,data,e) }
217
+ }
218
+
219
+ output.removeDB = function(data,db){
220
+ try{
221
+
222
+ if( !db[data.db] ) return {
223
+ status: 404,
224
+ database: data.db,
225
+ table: data.table,
226
+ message: 'DB does not exist',
227
+ };
228
+
229
+ for( var i in db._init_.DB ){
230
+ if( db._init_.DB.name == data.db ){
231
+ db._init_.DB[i].tables.map(x=>{
232
+ fs.unlinkSync(path.join(data.path,`${x}.json`));
233
+ }); db._init_.DB.splice(i,1);
234
+ delete db[data.db];
235
+ break;
236
+ }
237
+ }
238
+
239
+ return {
240
+ status: 200,
241
+ database: data.db,
242
+ table: data.table,
243
+ message: 'DB deleted'
244
+ };
245
+
246
+ } catch(e) { return parseError(db,data,e) }
247
+ }
248
+
249
+ output.addTable = function(data,db){
250
+ try{db._update_ = true;
251
+
252
+ if( db[data.db][data.table] ) return {
253
+ status: 404,
254
+ database: data.db,
255
+ table: data.table,
256
+ message: 'table already exist',
257
+ };
258
+
259
+ for( var i in db._init_.DB ){
260
+ if( db._init_.DB[i].name == data.db ){
261
+ db[data.db][data.table] = new Array();
262
+ db._init_.DB[i].tables.push(data.table);
263
+ break;
264
+ }
265
+ }
266
+
267
+ return {
268
+ status: 200,
269
+ database: data.db,
270
+ table: data.table,
271
+ message: 'table added'
272
+ };
273
+
274
+ } catch(e) { return parseError(db,data,e) }
275
+ }
276
+
277
+ output.removeTable = function(data,db){
278
+ try{db._update_ = true;
279
+
280
+ if( !db[data.db][data.table] ) return {
281
+ status: 404,
282
+ database: data.db,
283
+ table: data.table,
284
+ message: 'table does not exist'
285
+ };
286
+
287
+ for( var i in db._init_.DB ){
288
+ if( db._init_.DB[i].name == data.db ){
289
+ const j = db._init_.DB[i].tables.indexOf(x=>x==data.table);
290
+ delete db[data.db][data.table]; db._init_.DB[i].tables.splice(j,1);
291
+ break;
292
+ }
293
+ }
294
+
295
+ return {
296
+ status: 200,
297
+ database: data.db,
298
+ table: data.table,
299
+ message: 'table removed'
300
+ };
301
+
302
+ } catch(e) { return parseError(db,data,e) }
303
+ }
304
+
305
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
306
+
307
+ output.saveAll = async function(data,db){
308
+ try { for( var i in db['_init_'] ){ for( var j in db['_init_'][i] ){
309
+ const {name,tables} = db['_init_'][i][j];
310
+ for( var k in tables ) await modifyDB(data,db,name,tables[k])
311
+ }} return {
312
+ status: 200,
313
+ database: data.db,
314
+ table: data.table,
315
+ message: 'DB Saved'
316
+ }} catch(e) { console.log(e); return parseError(db,data,e) }
317
+ }
318
+
319
+ /*--────────────────────────────────────────────────────────────────────────────────────────────--*/
320
+
321
+ module.exports = output;