UNPKG

31.7 kBJavaScriptView Raw
1/*
2HOTELPARTNER
3Autor: HotelPartner WDS
4Author's note: “Clean code always looks like it was written by someone who cares.” ― Robert C. Martin,
5
6Date: 16.08.2017
7Version: 2.0
8Notes: Make sure that the hostname is set correct!
9===============================
10
11 */
12
13
14//HP LIBARIES
15const _HP = require("./classHotels.js");
16const _CONTROLLER = require("./bot_controller.js");
17
18const slave = _CONTROLLER.os.hostname().replace('slave','');
19const socket = _CONTROLLER.io.connect('http://192.168.254.89:88/', {
20 query:'slave='+slave,
21 reconnect: true
22});
23
24//Global Variables
25let currentip = '0.0.0.0';
26let errjobcounter = 0;
27let ipischanging = false;
28let client;
29let mobile;
30let api;
31let hostip;
32let hostport;
33
34
35// ##ENUMS
36const ADULT = {
37 ERROR: 0,
38 ONE : 1,
39 TWO : 2
40};
41const JOB = {
42 ERROR: 0,
43 DONE:1,
44 CITY_ID_LEFT:0
45};
46
47// ## PROTOTYPING
48Number.prototype.isActive = function () {
49 return(this!=-1)
50};
51Object.prototype.prepareNextRequest = function (callback) {
52
53 const arg = this;
54
55 //check if job is valid
56 if(arg.cityid[0]=='' || !arg.cityid[0] || !arg.dates[0]){
57 hp_bot.job.getNewJob(true)
58 // _CONTROLLER.reboot();
59 return null;
60 }
61
62 //repace all spaces with +
63 let city = arg.name.split(' ').join('+');
64 let countcity = arg.cityid.length-1;
65 let countdate = arg.dates.length-1;
66
67
68 callback(arg.dates[countdate], city ,arg.cityid[countcity]);
69};
70
71
72const hp_bot = {
73 "constructor": function JOB(_api=-1,_mobile=-1,_client='WDS',_host='192.168.56.1',_port='88') {
74
75 //Set Variables
76 api = _api;
77 mobile = _mobile;
78 client = _client;
79 hostip = _host;
80 hostport = _port;
81
82
83 //START SERVER
84 _CONTROLLER.start();
85 //Tell Host we are online
86 socket.emit('slaves',slave +" "+ _CONTROLLER.time().format('HH:mm'))
87
88
89
90 },
91 "init": function init() {
92 setTimeout( async function start(){
93
94 //get job
95 let job = await hp_bot.job.searchJob()
96 currentip = await _CONTROLLER.showExternalIP(true);
97 // here we should do a foreach to get each cityid and each Date
98 async function startForeach()
99 {
100 job.prepareNextRequest(async function (startdate,cityname,cityid) {
101
102 var bot = -5;
103
104 if(mobile.isActive())
105 bot = await hp_bot.bot.mobile(job,startdate,cityname,cityid);
106
107 else if(api.isActive())
108 bot = await hp_bot.bot.api(job,startdate,cityname,cityid)
109
110 else
111 bot = await hp_bot.bot.standart(job,startdate,cityname,cityid);
112
113 //get next job
114
115 if( bot == JOB.DONE )
116 {
117
118 console.log("=> JOB done <=")
119 _HP.hotels.Booking = []
120
121 hp_bot.job.saveJob([])
122 hp_bot.job.nextJob(hp_bot.init)
123 }
124
125 else if( bot == JOB.CITY_ID_LEFT)
126 {
127 setTimeout(async function(){
128 console.log("== next => ")
129 job = await hp_bot.job.getOldJob();
130 console.log(job)
131 startForeach();
132 },1000)
133
134 }
135
136 })
137 }
138
139 startForeach();
140
141 },1800)
142 },
143 job: {
144 'getNewJob' : function getNewJob(rebootOnError=true) {
145 console.log("");
146 console.log("GETTING NEW JOB FROM DB... CLIENT:" +client );
147
148 let data = "";
149 let clientVersion = '2217'
150
151 return new Promise(resolve=>{
152
153 //check clientverison and callback to _clientVersionCallB
154 // with the correct clientVersion
155 function makeRequest(clientversion){
156 console.log('clientversion '+clientversion)
157
158 _CONTROLLER.http.get('http://www.yieldagent.ch/relay/cityov/requestJobV8.php?version='+clientVersion+'&client='+client, function(res) {
159 if (res.statusCode >= 200 && res.statusCode < 400)
160 {
161 res.on('data', function(data_) { data += data_.toString(); });
162 res.on('end', function() {
163 _CONTROLLER.parseXML(data, function (err, result) {
164
165 try
166 {
167 if (result)
168 {
169 //set newclient version
170 clientVersion = result.Request.$.clientVersion;
171
172 //save client version
173 _CONTROLLER.fs.writeFile('./clientVersion.txt', clientVersion, 'utf8', function readFileCallback(err, data) {
174 if (err)
175 console.log(err);
176
177 else
178 console.log("new Client Version "+clientVersion)
179
180 });
181
182 //Parse XML
183 let ids = [];
184 let city = result.Request.CityConfig[0].URLArguments[0];
185 city = city.split(';city=');
186 //remove unnecessary elements
187 city.shift();
188 city.forEach(t => {
189 t = t.substr(0, t.indexOf(';'))
190 ids.push(t)
191 });
192
193 //build json
194 let job = {
195 "id": result.Request.CityConfig[0].CityID[0],
196 "cityid": ids,
197 "name": result.Request.CityConfig[0].CityName[0],
198 "dates": result.Request.Dates[0].Date,
199 "backup": result.Request.Dates[0].Date,
200 "job": result.Request.JobID[0],
201 "los": result.Request.$.los
202 };
203
204 //save job
205 hp_bot.job.saveJob(job);
206
207 //check for errors in JOB
208 if(!result.Request.Dates[0].Date){
209 hp_bot.general.errorHandler(job,1,_CONTROLLER.time().format('YYYY-MM-DD'),job.name,job.cityid,'{"error":"no date"}')
210 hp_bot.job.saveJob([]);
211 }
212 if(!result.Request.CityConfig[0].CityName[0]){
213 hp_bot.general.errorHandler(job,1,moment().format('YYYY-MM-DD'),'null',0,'{"error":"city"}')
214 hp_bot.job.saveJob([]);
215 }
216
217 resolve(job)
218 }
219 if(err)
220 {
221 console.log(err)
222 setTimeout(()=>{
223 _CONTROLLER.reboot();
224 },680000)
225 }
226 }
227 catch (TypeError)
228 {
229 //make request with the new clienversion
230 setTimeout( makeRequest(clientversion),8000);
231
232 //LOG
233 console.log("JOB parsing error")
234 console.log(result.Request)
235 console.log(" ")
236 console.log("getting new jeb with new clientVersion:" +clientVersion)
237
238
239 }
240
241 });
242 });
243 }
244 }).on('error',
245 async function(err) {
246
247 //Get current bot version
248 let version = await _CONTROLLER.version(false);
249
250 //Handle error
251 console.log("Error while fetching new Job");
252 console.log(err);
253
254 //request new ip
255 let hosturl = 'http://'+hostip+':'+hostport;
256 _CONTROLLER.fetch(hosturl+'/newip?gateway='+slave+'&client='+client+'&job=-1&version='+version);
257
258 // reboot if needed
259 setTimeout(()=>
260 {
261 if(errjobcounter >=3 && rebootOnError == true)
262 _CONTROLLER.fetch(hosturl+'/reboot?gateway='+slave+'&client='+client+'&job=error&version='+version);
263
264 else
265 _CONTROLLER.fetch(hosturl+'/newip?gateway='+slave+'&client='+client+'&version='+version).then(newIP=>{
266 hp_bot.job.getNewJob();
267 })
268
269 errjobcounter++;
270 },30000)
271 }
272 );
273 }
274
275 //Read clientsversion
276 _CONTROLLER.fs.readFile('./clientVersion.txt','utf8', function read(err, data)
277 {
278 if (err)
279 {
280 console.log('no file: clientVersion.txt')
281 makeRequest(clientVersion);
282 return;
283 }
284 else
285 {
286 clientVersion = data;
287 makeRequest(data)
288 }
289
290 });
291 })
292
293 },
294 'getOldJob' : function getOldJob() {
295 console.log("searching for old job");
296 try{
297 //Look for a backup file
298 const backup = JSON.parse(_CONTROLLER.fs.readFileSync('./backup.json', 'utf8'));
299
300 //Check if the file contains valid data
301 const checkforid = backup.cityid[0];
302 const checkfordate = backup.dates[0];
303 return backup;
304 }
305 catch (TypeError)
306 {
307 console.log("no Job found..")
308 return null
309 }
310 },
311 'searchJob' : async function () {
312 var job = hp_bot.job.getOldJob();
313
314 if(!job)
315 job = await hp_bot.job.getNewJob();
316 else
317 console.log("BACKUP JOB FOUND");
318
319 return job;
320 },
321 'updateOldJob' : function (date,cityid,resetdate=false) {
322 return new Promise(resolve=>{
323
324 try{
325
326 let backup = JSON.parse(_CONTROLLER.fs.readFileSync('./backup.json', 'utf8'));
327 const indx = backup.dates.indexOf(date);
328
329 //Update dates
330 if (indx > -1 && backup.dates.length>=1)
331 {
332 console.log("removing date")
333 backup.dates.splice(indx, 1);
334 console.log( " ")
335 console.log("****dates left: "+ backup.dates.length)
336 console.log( " ")
337 }
338
339 //Update cityid
340 if( backup.dates.length==0)
341 {
342 console.log("removing city id")
343 const indx2= backup.cityid.indexOf(cityid)
344 if (indx2 > -1){
345 backup.cityid.splice(indx2, 1);
346 backup.dates = backup.backup;
347 }
348
349 if(backup.cityid.length==0){
350 console.log("Clearing JOB")
351 hp_bot.job.saveJob([]).then(r=>{
352 resolve(JOB.DONE)
353 });
354
355 }
356
357
358 }
359
360 //Save the new Backup
361 hp_bot.job.saveJob(backup).then(r=>{
362 resolve(JOB.CITY_ID_LEFT)
363 });
364
365 }
366 catch (TypeError)
367 {
368 console.log('!!! JOB NOT SAVED !!!')
369 console.log(TypeError)
370 resolve(false)
371 }
372 })
373 },
374 'nextJob' : async function nextJob(callback) {
375 console.log("get new Job")
376 const newjob = await hp_bot.job.getNewJob();
377 callback(newjob);
378 },
379 'saveJob' : function (json) {
380 if(!json)return;
381 return new Promise(resolve=>{
382
383
384 console.log(" ")
385 console.log("Saving Job | backup.json");
386 _CONTROLLER.fs.writeFile('./backup.json', JSON.stringify(json), 'utf8', function readFileCallback(err, data) {
387 if (err)
388 console.log(err);
389 else
390 console.log("JOB is SAVED")
391
392 console.log(" ")
393 resolve(true)
394 })
395 });
396 },
397 'sendJobToHost': function (json_job,httpOrSocket='socket') {
398 return new Promise(resolve => {
399 if (httpOrSocket == 'socket') {
400 socket.emit('jobdone', JSON.stringify(json_job), function (response) {
401 console.log(response);
402 resolve(response)
403 });
404 }
405 })
406 },
407 },
408 bot: {
409 "mobile" : async function startMobileJob (arg,startdate,cityname,cityid,API=null) {
410
411 console.log("->Fetching Mobile Version");
412 const end = _CONTROLLER.time(startdate,'YYYY-MM-DD').add(1, 'day').format('YYYY-MM-DD');
413 let counterror = 0;
414 return new Promise(resolve=>{
415 let adult =1;
416
417 async function startFetch(adult) {
418 console.log(startdate,cityname,cityid,adult);
419
420 const xmlresult = await hp_bot.general.getXMLData(adult,startdate,end,cityname,cityid);
421
422 const isvalid = hp_bot.general.validateXmlResult(xmlresult,arg,adult,startdate,cityname,cityid);
423 if(!isvalid)return;
424
425 //Parse Data
426 const parsed = await _HP.methods.Booking.parsemobile(xmlresult.result,adult,startdate,end,cityname,cityid);
427
428 if(parsed==ADULT.ONE) {
429 startFetch(2)
430 }
431 if(parsed==ADULT.TWO) {
432 counterror = 0;
433 const json = await _HP.methods.general.generateJson(_HP.hotels.Booking, arg.job, arg.id, startdate, slave);
434
435 if(API)
436 {
437 API(json)
438 resolve(json)
439 }
440 else
441 {
442 const answer = await hp_bot.job.sendJobToHost(json, 'socket');
443 if (answer == 'OK')
444 {
445 console.log("SENDED: OK")
446 let _status = await hp_bot.job.updateOldJob(startdate, cityid);
447 resolve(_status)
448 }
449 else {
450 startFetch(adult);
451 }
452 }
453
454 }
455 if(parsed==JOB.ERROR) {
456
457 console.log("ip got blocked")
458
459 //check if there is a error with the url
460 if(4<counterror)
461 {
462 let message;
463 try{
464 message = allresult.errors[0].message;
465 hp_bot.general.errorHandler(arg,adult,startdate,cityname,cityid,message,'Mobile Parser',true)
466 }catch (TypeError)
467 {
468
469 if(JSON.stringify(allresult).indexOf('in_city_translation')>=0)
470 {
471 message = {'error':'in_city_translation no results found'}
472 hp_bot.general.errorHandler(arg,adult,startdate,cityname,cityid,message,'Mobile Parser',true)
473 }
474 else
475 {
476 message = {'info':'no results found'}
477 hp_bot.general.errorHandler(arg,adult,startdate,cityname,cityid,message,'Mobile Parser',false)
478 }
479 }
480
481 counterror = 0;
482 }
483
484 //standart IP: 192.168.56.1
485 setTimeout(()=>{
486 hp_bot.general.getNewIP(ipischanging).then(gotNewIP=>
487 {
488 counterror++
489 console.log('IP changes counter : '+counterror)
490 ipischanging=false;
491 startFetch(adult);
492
493 })
494 },1000)
495 ipischanging =true;
496
497 }
498
499 console.log("PARSED RESULT "+ parsed)
500
501
502 }
503 startFetch(adult);
504
505 })
506 },
507 "standart" : async function startSeleniumJOB(arg) {
508 let isfetching = true;
509 console.log("->Fetching Selenium Version");
510 console.log("Selenium is still in testing mode.. ");
511
512 //IF NO CITY ID go to NEXT JOB
513 if(arg.cityid[0]=='' || !arg.cityid[0])
514 {
515 hp_bot.job.nextJob(startSeleniumJOB);
516 return
517 }
518
519 console.log("JOB FOUND:");
520 console.log(arg);
521 console.log("=====================");
522 currentip = await _CONTROLLER.showExternalIP(true)
523
524 let city = arg.name.replace(" ", '+');
525 let icity = 0;
526 let countcity = arg.cityid.length;
527
528 let idate = 0;
529 let countdate = arg.dates.length;
530
531
532 nextCityId();
533 function nextCityId() {
534 //Check if we have made all CityID
535 if(icity==countcity && isfetching){
536 console.log("Job Done");
537 console.log(JSON.stringify(_HP.hotels.Booking));
538 hp_bot.job.nextJob(startSeleniumJOB);
539 }
540 //Start fetching next CityID
541 if(icity<countcity)
542 {
543 idate=0;
544 nextDate(arg.cityid[icity])
545 icity++;
546 }
547
548 }
549 function nextDate(cityid) {
550 //Clear after new date
551 _HP.hotels.Booking = [];
552 const start = arg.dates[idate];
553 fetchData(1,start,city,cityid);
554 idate++;
555 }
556 function fetchData(adult,start,city,cityid) {
557
558 const end = _CONTROLLER.time(start,'YYYY-MM-DD').add(1, 'day').format('YYYY-MM-DD');
559 let room = 1;
560 let child = 1;
561
562 _HP.methods.Booking.get(cityid,city,start,end,room,adult,child,false,arg.job,arg.id).then(result=>{
563
564 let isok = -1;
565
566 //go to next adult
567 if(isok==1||isok=='1'){
568 fetchData(2,start,city,cityid);
569 }
570
571 //got to next date
572 //send result to server
573 if(isok==2||isok=='2')
574 {
575 //send job
576 _HP.methods.general.generateJson(_HP.hotels.Booking,arg.job,arg.id,start,slave).then(answer=>{
577
578 //next cityid
579 if(idate==countdate){
580 hp_bot.job.updateOldJob(start,cityid,arg.dates);
581 nextCityId()
582 }
583
584 //next cityid
585 if(idate<countdate){
586 //Go to Nekt Date
587 console.log("=> going to next date: "+idate);
588 hp_bot.job.updateOldJob(start,null,null);
589 nextDate(cityid)
590 }
591
592 })
593 }
594
595 //Get new IP Address
596 if(isok==0||isok=='0'){
597 //standart IP: 192.168.56.1
598 hp_bot.general.getNewIP().then(gotNewIP=>{
599 fetchData(adult,start,city,cityid);
600 })
601 }
602
603 })
604
605 }
606
607 },
608 "api" : async function startApiJob() {}
609 },
610 general:{
611 "generateDeviceID": function generateDeviceID(show = false) {
612 //
613
614 let nr1 = Math.floor((Math.random() * 9999) + 1000);
615 let nr2 = Math.floor((Math.random() * 9999) + 1000);
616 let nr3 = Math.floor((Math.random() * 1) + 10);
617 if(show)
618 console.log('generateDeviceID: '+ `72331403-${nr1}-${nr2}-${nr3}`)
619
620 return `72331403-${nr1}-${nr2}-${nr3}`
621 },
622 "getNewIP": function getNewIP(ischanging=false) {
623
624 return new Promise(resolve=>{
625
626 console.log('old ip: ' + currentip);
627
628 hp_bot.general.generateDeviceID(true);
629
630 _CONTROLLER.tor.newTorSession(async function(err){
631 if(err)console.log(err)
632 currentip = await _CONTROLLER.showExternalIP(false);
633 console.log("new ip:"+currentip);
634 setTimeout(()=>{
635 resolve(currentip)
636 },5000)
637
638 })
639
640 /*
641 if(ischanging)
642 socket.emit('newip',slave, async function(status) {
643 console.log("callback")
644 currentip = await _CONTROLLER.showExternalIP(false)
645
646 if(!currentip)
647 setTimeout(()=>{getNewIP();},1000);
648 else
649 {
650 console.log("new ip:"+currentip)
651 resolve(currentip)
652 }
653 });
654
655 else{
656 setTimeout(()=>{
657 resolve(currentip)
658 },40000)
659 }
660 */
661 })
662 },
663 "getXMLData": function fetchIphoneXMLData(adult,start,end,city,cityid) {
664 return new Promise(resolve=>{
665 const devid = hp_bot.general.generateDeviceID();
666 const _url = `https://iphone-xml.booking.com/json/bookings.getHotelAvailabilityMobile?detail_level=1&genius_freebies=2&show_distance_cc=1&request_less_fields=2&show_facilities_review_score=1&show_last_minute_saving=1&include_translations=2&add_bh_info=1&languagecode=de&urgency=1&include_taxes=1&include_count=1&location_source=autocomplete&show_price_trend=1&show_deals=flash%2Clastm%2Csmart%2Cgenius&children_qty=0&low_av_alternatives=0&&&order_by=popularity&show_if_class_is_estimated=1&show_categories=v3&show_location_score=1&show_last_reservation_text=1&show_reinforcement_text=v2&show_filtered_facilities=1&show_if_no_cc_allowed=2&show_soldout=1&show_is_personalized_result=0&show_flash_saving=1&max_persons=-2&use_direct_payment=1&add_ctrip_info=1&include_rack_rate_savings=1&&include_url=1&bh_alt_urgency_msg=1&show_refundable=1&check_price_is_final=1&show_extra_charges=1&room_qty=1&show_if_city_center=1&available_rooms=0&price_buckets=100&flash_deals_amount_if_unsigned=2&show_low_availability=2&show_business_badge=1&autoextend=1&user_os=6.0.1&user_version=11.3.1-android&network_type=wifi&bt=1&arrival_date=${start}&departure_date=${end}&city_ids=${cityid.replace('city=', '').replace('|si=ai%2Cco%2Cci%2Cre%2Cdi', '')}&rows=5000&device_id=${devid}da-ef8edab1ad7f&guest_qty=${adult}`;
667 const options = {
668 headers: {
669 'Content-Type' : 'application/x-www-form-urlencoded',
670 'Authorization': 'Basic dGhlc2FpbnRzYnY6ZGdDVnlhcXZCeGdN'
671 },
672 url: _url,
673 timeout: 900000
674 };
675
676 //Send request
677 _CONTROLLER.tor.request(options, function (err, resp, body) {
678 if(body)
679 resolve(JSON.parse(body));
680 else
681 console.log('no data')
682 })
683 })
684 },
685 "validateXmlResult": function (xml,arg,adult,start,_city,cityid) {
686
687 console.log("check validate");
688
689 let xmlcity = null;
690
691 //remove space and + at start and at the end
692 const cityname = arg.name.trim().replace('/+/g','');
693 const listcity = [];
694
695 try
696 {
697
698 let found = false;
699 xmlcity = xml.filter;
700
701 if(xmlcity)
702 xmlcity.forEach(fitler=>
703 {
704 if(fitler.id == 'city')
705 {
706 if(fitler.categories)
707 fitler.categories.forEach(categorycity=>{
708 listcity.push(categorycity.name);
709 if(categorycity.name.toUpperCase().indexOf(cityname.toUpperCase())>=0)
710 found = categorycity;
711 })
712 }
713 });
714
715 if(found==false && listcity.length>1)
716 {
717 let message = {'warrning':'city_ids did not match cityname '+cityname,
718 'list':listcity}
719
720 hp_bot.general.errorHandler(arg,adult,start,cityname,cityid,message,'Mobile Parser',true);
721 return null;
722 }
723 else
724 {
725 console.log("Data is valid")
726 return true;
727 }
728
729 }
730 catch (TypeError)
731 {
732 console.log(" error validate date ");
733 console.log(xmlcity);
734 console.log(TypeError);
735 return true;
736 }
737
738 },
739 "errorHandler": function (arg,adult,start,city,cityid,message,type='mobile',rebootanddelete=false) {
740
741 console.log( "errorHandler " + type)
742 city = city.replace('/+/g','');
743
744 let log = {
745 "job" : JSON.stringify(arg),
746 "jobid" : arg.job,
747 "message": JSON.stringify(message) + ',{ "cityid":'+cityid+',"city":"'+city+'" }',
748 "cityid" : cityid,
749 "city" : city,
750 "slave" : slave,
751 "client" : client,
752 };
753
754 socket.emit('joberror',JSON.stringify(log),function (data) {
755 if(rebootanddelete)
756 {
757
758 _CONTROLLER.exec(' rm /var/node/backup.json');
759 _CONTROLLER.exec('echo 123 | sudo -S rm /var/node/backup.json');
760 hp_bot.job.saveJob([])
761 _CONTROLLER.reboot();
762 }
763 else
764 {
765
766 _CONTROLLER.exec('rm /var/node/backup.json');
767 _CONTROLLER.exec('echo 123 | sudo -S rm /var/node/backup.json');
768 hp_bot.job.saveJob([])
769 _CONTROLLER.version();
770 _CONTROLLER.restart();
771
772 setTimeout(()=>{
773 _CONTROLLER.reboot();
774 },5000)
775
776 }
777 })
778
779 }
780 },
781};
782
783//EXPORT Functions
784hp_bot.constructor.prototype.start = hp_bot.init;
785hp_bot.constructor.prototype.getNewJob = hp_bot.job.getNewJob;
786module.exports = hp_bot.constructor;
787
788
789//###Error Output
790process.on('uncaughtException', function (error) {
791 console.log(error.stack);
792});
793
794// Add a connect listener
795socket.on('connect', function (socket) {
796 console.log('Connected!');
797});
798socket.on('disconnect', function(){
799 console.log("lost connection to server")
800 socket.connect()
801 socket.emit('slaves',slave)
802 hp_bot.init();
803 // reconnect
804});