import {Caps} from './Caps'; import * as LLSD from 'llsd'; import * as request from 'request'; import * as Long from 'long'; import {IPAddress} from './IPAddress'; import {TeleportEvent} from '../events/TeleportEvent'; import {ClientEvents} from './ClientEvents'; import {TeleportEventType} from '../enums/TeleportEventType'; export class EventQueueClient { caps: Caps; ack?: number; done = false; currentRequest: request.Request | null = null; private clientEvents: ClientEvents; constructor(caps: Caps, clientEvents: ClientEvents) { this.clientEvents = clientEvents; this.caps = caps; this.Get(); } shutdown() { if (this.currentRequest !== null) { this.currentRequest.abort(); } this.done = true; } Get() { const req = { 'ack': this.ack, 'done': this.done }; this.capsRequestXML('EventQueueGet', req).then((data) => { if (data['events']) { data['events'].forEach((event: any) => { try { if (event['message']) { // noinspection TsLint switch (event['message']) { case 'EnableSimulator': /* { "body": { "SimulatorInfo": [ { "Handle": "AALoAAAECwA=", "IP": "2FIqRA==", "Port": 13029 } ] }, "message": "EnableSimulator" } */ break; case 'ParcelProperties': /* { "body": { "AgeVerificationBlock": [ { "RegionDenyAgeUnverified": true } ], "MediaData": [ { "MediaDesc": "", "MediaHeight": 0, "MediaLoop": 0, "MediaType": "text/html", "MediaWidth": 0, "ObscureMedia": 0, "ObscureMusic": 0 } ], "ParcelData": [ { "AABBMax": [ 256, 256, 50 ], "AABBMin": [ 0, 0, 0 ], "AnyAVSounds": true, "Area": 65536, "AuctionID": "AAAAAA==", "AuthBuyerID": "00000000-0000-0000-0000-000000000000", "Bitmap": "///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8=", "Category": 0, "ClaimDate": 1333505995, "ClaimPrice": 0, "Desc": "adoption parent furry parent teen twin cub neko pets adult elf vamp toddleedoo baby child panel brother sister numbers meshmerized gacha adoptions adopt family mesh skin shape camp ngi youthspot foster kids mall zoo train kid primbay\ndupli city onlinker", "GroupAVSounds": true, "GroupID": "f2b75b49-8ebc-2a9c-f345-aa2f91adc908", "GroupPrims": 18677, "IsGroupOwned": true, "LandingType": 2, "LocalID": 15, "MaxPrims": 30000, "MediaAutoScale": 1, "MediaID": "6bd35c06-2b24-a83e-03f6-f547c65c8556", "MediaURL": "", "MusicURL": "http://142.4.209.63:8071", "Name": "Next Gen Inc. Adoption Agency on the :::: KiD GRiD :::", "OtherCleanTime": 0, "OtherCount": 4096, "OtherPrims": 312, "OwnerID": "f2b75b49-8ebc-2a9c-f345-aa2f91adc908", "OwnerPrims": 3, "ParcelFlags": "NiAUSw==", "ParcelPrimBonus": 1, "PassHours": 10, "PassPrice": 10, "PublicCount": 0, "RegionDenyAnonymous": true, "RegionDenyIdentified": true, "RegionDenyTransacted": true, "RegionPushOverride": true, "RentPrice": 0, "RequestResult": 0, "SalePrice": 1, "SeeAVs": true, "SelectedPrims": 1, "SelfCount": 0, "SequenceID": 0, "SimWideMaxPrims": 30000, "SimWideTotalPrims": 18993, "SnapSelection": true, "SnapshotID": "09c4101a-9406-2501-b9b7-dbb60260fd7a", "Status": 0, "TotalPrims": 18993, "UserLocation": [ 131.48399353027344, 171.41600036621094, 21.544700622558594 ], "UserLookAt": [ 0.0325143001973629, -0.9994710087776184, 0 ] } ], "RegionAllowAccessBlock": [ { "RegionAllowAccessOverride": true } ] }, "message": "ParcelProperties" } */ break; case 'AgentGroupDataUpdate': /* { "body": { "AgentData": [ { "AgentID": "49cc9041-5c53-4c1c-8490-e6bb84cdbacd" } ], "GroupData": [ { "AcceptNotices": true, "Contribution": 0, "GroupID": "06459c46-069f-4de1-c297-c966bd55ab91", "GroupInsigniaID": "8dacb5c9-80bc-aae4-6a12-d792b6eb7dc4", "GroupName": "Jez Ember Estates", "GroupPowers": "AAAgAAQAAAA=" }, { "AcceptNotices": true, "Contribution": 0, "GroupID": "539b5be0-bb18-d0ef-6c07-3326e0130aaf", "GroupInsigniaID": "7d7d0b4a-bf5b-dc51-3869-5e0eaa6ad41d", "GroupName": "**BOY BEARS MALL**", "GroupPowers": "AAAIABgBAAA=" } ], "NewGroupData": [ { "ListInProfile": true }, { "ListInProfile": true } ] }, "message": "AgentGroupDataUpdate" } */ break; case 'AgentStateUpdate': /* { "body": { "can_modify_navmesh": true, "has_modified_navmesh": true, "preferences": { "access_prefs": { "max": "PG" }, "default_object_perm_masks": { "Everyone": 0, "Group": 0, "NextOwner": 532480 }, "god_level": 0, "hover_height": 0, "language": "", "language_is_public": true } }, "message": "AgentStateUpdate" } */ break; case 'TeleportFailed': { const tpEvent = new TeleportEvent(); tpEvent.message = event['body']['Info'][0]['Reason']; tpEvent.eventType = TeleportEventType.TeleportFailed; tpEvent.simIP = ''; tpEvent.simPort = 0; tpEvent.seedCapability = ''; this.clientEvents.onTeleportEvent.next(tpEvent); break; } case 'TeleportFinish': { const info = event['body']['Info'][0]; if (info['LocationID']) { info['LocationID'] = Buffer.from(info['LocationID'].toArray()).readUInt32LE(0); const regionHandleBuf = Buffer.from(info['RegionHandle'].toArray()); info['RegionHandle'] = new Long(regionHandleBuf.readUInt32LE(0), regionHandleBuf.readUInt32LE(4), true); info['SimIP'] = new IPAddress(Buffer.from(info['SimIP'].toArray()), 0).toString(); info['TeleportFlags'] = Buffer.from(info['TeleportFlags'].toArray()).readUInt32LE(0); const tpEvent = new TeleportEvent(); tpEvent.message = ''; tpEvent.eventType = TeleportEventType.TeleportCompleted; tpEvent.simIP = info['SimIP']; tpEvent.simPort = info['SimPort']; tpEvent.seedCapability = info['SeedCapability']; this.clientEvents.onTeleportEvent.next(tpEvent); } break; } default: console.log('Unhandled event:'); console.log(JSON.stringify(event, null, 4)); } } } catch (erro) { console.error('Error handling cap'); console.error(erro); } }); } if (data['id']) { this.ack = data['id']; } else { this.ack = undefined; } if (!this.done) { this.Get(); } }).catch((err) => { // Wait 5 seconds before retrying setTimeout(() => { if (!this.done) { this.Get(); } }, 5000); }); } request(url: string, data: string, contentType: string): Promise { return new Promise((resolve, reject) => { this.currentRequest = request({ 'headers': { 'Content-Length': data.length, 'Content-Type': contentType }, 'uri': url, 'body': data, 'rejectUnauthorized': false, 'method': 'POST', 'timeout': 1800000 // Super long timeout }, (err, res, body) => { this.currentRequest = null; if (err) { reject(err); } else { resolve(body); } }); }); } capsRequestXML(capability: string, data: any): Promise { return new Promise((resolve, reject) => { this.caps.getCapability(capability).then((url) => { const serializedData = LLSD.LLSD.formatXML(data); this.request(url, serializedData, 'application/llsd+xml').then((body: string) => { try { if (body.indexOf('') !== -1) { const parsed = LLSD.LLSD.parseXML(body); resolve(parsed); } else { throw new Error('Not an LLSD response'); } } catch (error) { reject(error); } }).catch((err) => { reject(err); }); }).catch((err) => { reject(err); }); }); } }