842 lines
33 KiB
JavaScript
842 lines
33 KiB
JavaScript
/**
|
|
* System killboard module
|
|
*/
|
|
|
|
define([
|
|
'jquery',
|
|
'app/init',
|
|
'app/util',
|
|
'module/base',
|
|
'app/lib/cache',
|
|
'app/map/util'
|
|
], ($, Init, Util, BaseModule, Cache, MapUtil) => {
|
|
'use strict';
|
|
|
|
let SystemKillboardModule = class SystemKillboardModule extends BaseModule {
|
|
constructor(config = {}) {
|
|
super(Object.assign({}, new.target.defaultConfig, config));
|
|
}
|
|
|
|
/**
|
|
* module header
|
|
* @param text
|
|
* @returns {HTMLDivElement}
|
|
*/
|
|
newHeaderElement(text){
|
|
let headEl = super.newHeaderElement(text);
|
|
|
|
// WebSocket status
|
|
let wsStatusEl = Object.assign(document.createElement('h5'), {
|
|
className: this._config.wsStatusWrapperClass
|
|
});
|
|
this._iconWsEl = this.newIconElement([
|
|
'fa-circle', 'fa-fw', 'txt-color', this._config.wsStatusClass
|
|
]);
|
|
wsStatusEl.append(this._iconWsEl);
|
|
|
|
// toolbar
|
|
let toolbarEl = this.newHeadlineToolbarElement();
|
|
this._iconFilterEl = this.newIconElement([
|
|
'fa-filter', 'fa-fw',
|
|
this._config.moduleHeadlineIconClass
|
|
]);
|
|
|
|
let iconKbEl = this.newIconElement([
|
|
'fa-external-link-alt', 'fa-fw',
|
|
this._config.moduleHeadlineIconClass
|
|
]);
|
|
iconKbEl.setAttribute('title', 'zkillboard.com');
|
|
iconKbEl.onclick = e => this.openKillboardUrl(e);
|
|
|
|
toolbarEl.append(iconKbEl, this._iconFilterEl);
|
|
headEl.append(wsStatusEl, toolbarEl);
|
|
|
|
return headEl;
|
|
}
|
|
|
|
/**
|
|
* HTTP request
|
|
* @param url
|
|
* @returns {Promise}
|
|
*/
|
|
request(url){
|
|
return new Promise((resolve, reject) => {
|
|
let handleResponse = response => {
|
|
return response.json()
|
|
.then((json) => {
|
|
if(!response.ok){
|
|
return Promise.reject(Object.assign({}, json, {
|
|
status: response.status,
|
|
statusText: response.statusText,
|
|
}));
|
|
}
|
|
return json;
|
|
});
|
|
};
|
|
|
|
fetch(url)
|
|
.then(handleResponse)
|
|
.then((result) => {
|
|
resolve(result);
|
|
}).catch((e) => {
|
|
console.error(url, e);
|
|
|
|
let title = e.status ? e.status : e;
|
|
let text = e.error ? e.error : url;
|
|
this.showNotify({title: title, text: text, type: 'error'});
|
|
|
|
reject(e);
|
|
}).finally(() => {
|
|
$(this.moduleElement).hideLoadingAnimation();
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* get zKillboard data
|
|
* @returns {Promise}
|
|
*/
|
|
getSystemKillsData(){
|
|
// check for cached responses "short term cache"
|
|
let cacheKey = SystemKillboardModule.getCacheKey('systemId', this._systemData.systemId);
|
|
let result = SystemKillboardModule.zkbCache.get(cacheKey);
|
|
if(result){
|
|
// could also be an empty array!
|
|
return Promise.resolve(result);
|
|
}else{
|
|
return new Promise(resolve => {
|
|
$(this.moduleElement).showLoadingAnimation();
|
|
|
|
// get kills within the last 24h
|
|
let timeFrameInSeconds = 60 * 60 * 24;
|
|
|
|
// if system is w-space system -> add link modifier
|
|
let wSpaceLinkModifier = '';
|
|
if(this._systemData.type.id === 1){
|
|
wSpaceLinkModifier = 'w-space/';
|
|
}
|
|
|
|
let url = `${Init.url.zKillboard}/no-items/${wSpaceLinkModifier}no-attackers/npc/0/solarSystemID/${this._systemData.systemId}/pastSeconds/${timeFrameInSeconds}/`;
|
|
|
|
this.request(url).then(result => {
|
|
if(result.error){
|
|
// successful request with error response
|
|
this.showNotify({title: 'Data fetch() from zKillboard failed', text: result.error, type: 'error'});
|
|
return Promise.reject(result);
|
|
}else{
|
|
// zkb result needs to be cached and becomes reduced on "load more"
|
|
SystemKillboardModule.zkbCache.set(cacheKey, result);
|
|
return result;
|
|
}
|
|
}).then(result => resolve(result)).catch(e => {
|
|
console.error(e);
|
|
this.showNotify({title: 'Data fetch() from zKillboard failed', text: e, type: 'error'});
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* render module
|
|
* @param mapId
|
|
* @param systemData
|
|
* @returns {HTMLElement}
|
|
*/
|
|
render(mapId, systemData){
|
|
this._mapId = mapId;
|
|
this._systemData = systemData;
|
|
|
|
// request graph data and store result promise
|
|
// -> module is not full rendered jet
|
|
this._dataPromise = this.getSystemKillsData();
|
|
|
|
this._bodyEl = Object.assign(document.createElement('div'), {
|
|
className: this._config.bodyClassName
|
|
});
|
|
this.moduleElement.append(this._bodyEl);
|
|
|
|
this.setModuleObserver();
|
|
|
|
// init webSocket connection
|
|
SystemKillboardModule.initWebSocket();
|
|
|
|
return this.moduleElement;
|
|
}
|
|
|
|
/**
|
|
* init module
|
|
*/
|
|
init(){
|
|
super.init();
|
|
|
|
// subscribe this module instance to the zKB WebSocket
|
|
SystemKillboardModule.subscribeToWS(this);
|
|
this.updateWsStatus();
|
|
|
|
// show "historic" killmails
|
|
if(this._dataPromise instanceof Promise){
|
|
this._dataPromise
|
|
.then(result => {
|
|
this._killboardLabelEl = this.newLabelElement('recent kills within the last hour', [
|
|
'label-warning', this._config.labelRecentKillsClass, 'hidden'
|
|
]);
|
|
|
|
if(result.length){
|
|
// kills found
|
|
this._killboardEl = document.createElement('ul');
|
|
this._killboardEl.classList.add(this._config.systemKillboardListClass);
|
|
|
|
let controlEl = document.createElement('div');
|
|
controlEl.classList.add(Util.config.dynamicAreaClass, this._config.controlAreaClass, this._config.moduleHeadlineIconClass);
|
|
controlEl.insertAdjacentHTML('beforeend', ' load more');
|
|
controlEl.prepend(this.newIconElement(['fa-sync']));
|
|
|
|
this._bodyEl.append(
|
|
this._killboardLabelEl,
|
|
this._killboardEl,
|
|
controlEl
|
|
);
|
|
|
|
// set a "local" copy of all indexes from cached response
|
|
// -> this "local" array gets reduces when KM gets loaded
|
|
// -> manipulation does NOT affect cached data
|
|
this._tempZkbKillmailIndexes = Object.keys(result);
|
|
|
|
this.showKills(this._config.chunkCountKills);
|
|
}else{
|
|
// no kills found
|
|
this._bodyEl.append(
|
|
this.newLabelElement('No kills found within the last 24h', ['label-success'])
|
|
);
|
|
}
|
|
})
|
|
.catch(e => {
|
|
console.error(e);
|
|
});
|
|
}
|
|
}
|
|
|
|
beforeHide(){
|
|
super.beforeHide();
|
|
SystemKillboardModule.unsubscribeFromWS(this);
|
|
}
|
|
|
|
/**
|
|
* load a chunk of killmails and render them
|
|
* @param chunkSize
|
|
*/
|
|
showKills(chunkSize){
|
|
if(chunkSize){
|
|
let cacheKey = SystemKillboardModule.getCacheKey('systemId', this._systemData.systemId);
|
|
let result = SystemKillboardModule.zkbCache.get(cacheKey);
|
|
|
|
if(
|
|
this._killboardEl.children.length < this._config.maxCountKillHistoric &&
|
|
(this._tempZkbKillmailIndexes || []).length &&
|
|
(result || []).length
|
|
){
|
|
// next killmail to load -> reduce "local" index array
|
|
let nextZkb = result[this._tempZkbKillmailIndexes.shift()];
|
|
if(nextZkb){
|
|
this.loadKillmailData({
|
|
killId: parseInt(nextZkb.killmail_id) || 0,
|
|
hash: nextZkb.zkb.hash
|
|
}, {
|
|
chunkSize: --chunkSize,
|
|
zkb: nextZkb.zkb
|
|
}, 'renderKillmail');
|
|
}else{
|
|
console.warn('Killmail not found in local zkb cache');
|
|
}
|
|
}else{
|
|
// no more kills available OR max kills reached
|
|
this.moduleElement.querySelector('.' + this._config.controlAreaClass).style.display = 'none';
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* get killmail data from ESI
|
|
* @param requestData
|
|
* @param context
|
|
* @param callback
|
|
*/
|
|
loadKillmailData(requestData, context, callback){
|
|
let cacheKey = SystemKillboardModule.getCacheKey('killmail', requestData.killId);
|
|
let cacheItem = SystemKillboardModule.killmailCache.get(cacheKey);
|
|
if(cacheItem){
|
|
// ... already cached -> show cache killmail
|
|
this[callback](cacheItem.zkb, cacheItem.killmailData, cacheItem.systemData, context.chunkSize)
|
|
.then(payload => this.showKills(payload.data.chunkSize))
|
|
.catch(e => console.error(e));
|
|
}else{
|
|
// ...not cached -> request data
|
|
let url = 'https://esi.evetech.net/latest/killmails/' + requestData.killId + '/' + requestData.hash + '/';
|
|
|
|
this.request(url).then(killmailData => {
|
|
let systemData = SystemKillboardModule.getSystemDataForCache(this._systemData);
|
|
SystemKillboardModule.killmailCache.set(cacheKey, {zkb: context.zkb, killmailData: killmailData, systemData: systemData});
|
|
|
|
this[callback](context.zkb, killmailData, systemData, context.chunkSize)
|
|
.then(payload => this.showKills(payload.data.chunkSize))
|
|
.catch(e => console.error(e));
|
|
}).catch(e => {
|
|
// request failed -> skip this and load next
|
|
console.warn(e);
|
|
this.showKills(context.chunkSize);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param zkb
|
|
* @param attackersCount
|
|
* @returns {{color: string, label: string}}
|
|
*/
|
|
getAttackerBadgeData(zkb, attackersCount){
|
|
let color, label;
|
|
if(zkb.solo){
|
|
color = '#5cb85c';
|
|
label = 'solo';
|
|
}else if(zkb.npc){
|
|
color = '#d747d6';
|
|
label = 'npc';
|
|
}else if(attackersCount){
|
|
color = '#adadad';
|
|
label = attackersCount;
|
|
}
|
|
return {color, label};
|
|
}
|
|
|
|
/**
|
|
* render a single killmail
|
|
* @param zkbData
|
|
* @param killmailData
|
|
* @param systemData
|
|
* @param chunkSize
|
|
* @param position
|
|
* @returns {Promise<any>}
|
|
*/
|
|
renderKillmail(zkbData, killmailData, systemData, chunkSize, position = 'bottom'){
|
|
return new Promise((resolve, reject) => {
|
|
if(!this._killboardEl){
|
|
// killboard element might not be rendered at this point (e.g. if new kills pushed to WS)
|
|
return reject(new ReferenceError('Could not render killmail. KB element not found.'));
|
|
}
|
|
|
|
// calculate time diff in hours
|
|
let serverDate = SystemKillboardModule.serverTime;
|
|
let serverHours = serverDate.setHours(0,0,0,0);
|
|
|
|
let killDate = Util.convertDateToUTC(new Date(killmailData.killmail_time));
|
|
|
|
// get time diff
|
|
let timeDiffMin = Math.round((serverDate - killDate) / 1000 / 60);
|
|
let timeDiffHour = Math.floor(timeDiffMin / 60);
|
|
|
|
let attackers = BaseModule.Util.getObjVal(killmailData, 'attackers') || [];
|
|
let attackersCount = attackers.length;
|
|
let attackerFinal = attackers.find(attacker => attacker.final_blow);
|
|
|
|
|
|
let data = {
|
|
zkb: zkbData,
|
|
killmail: killmailData,
|
|
system: systemData,
|
|
isPodKill: BaseModule.Util.getObjVal(killmailData, 'victim.ship_type_id') === 670, // POD shipId
|
|
attackersCount: attackersCount,
|
|
attackerFinal: attackerFinal,
|
|
attackerBadge: this.getAttackerBadgeData(zkbData, attackersCount),
|
|
config: this._config,
|
|
zKillboardUrl: 'https://zkillboard.com',
|
|
ccpImageServerUrl: Init.url.ccpImageServer,
|
|
imgUrlType: () => {
|
|
return (val, render) => this.getImageUrl('types', parseInt(render(val)) || 0, 64);
|
|
},
|
|
imgUrlChar: () => {
|
|
return (val, render) => this.getImageUrl('characters', parseInt(render(val)) || 0);
|
|
},
|
|
imgUrlCorp: () => {
|
|
return (val, render) => this.getImageUrl('corporations', parseInt(render(val)) || 0);
|
|
},
|
|
imgUrlAlly: () => {
|
|
return (val, render) => this.getImageUrl('alliances', parseInt(render(val)) || 0);
|
|
},
|
|
dateFormat: () => {
|
|
return (val, render) => {
|
|
let killDate = Util.convertDateToUTC(new Date(render(val)));
|
|
let value = Util.convertDateToString(killDate);
|
|
|
|
// check whether log is new (today) ->
|
|
if(killDate.setHours(0,0,0,0) === serverHours){
|
|
// replace dd/mm/YYYY
|
|
value = 'today' + value.substring(10);
|
|
}
|
|
|
|
return value;
|
|
};
|
|
},
|
|
iskFormat: () => {
|
|
return (val, render) => {
|
|
return Util.formatPrice(render(val));
|
|
};
|
|
},
|
|
};
|
|
|
|
requirejs(['text!templates/modules/killmail.html', 'mustache'], (template, Mustache) => {
|
|
// show hint for recent kills
|
|
this._killboardLabelEl.classList.toggle('hidden', !(timeDiffHour === 0 && this._killboardLabelEl));
|
|
|
|
// render killmail entry
|
|
let insertPos = ['append', 'beforeend'];
|
|
let animationPos = 'lastChild';
|
|
if(position === 'top'){
|
|
insertPos = ['prepend', 'afterbegin'];
|
|
animationPos = 'firstChild';
|
|
}
|
|
|
|
this._killboardEl.insertAdjacentHTML(insertPos[1], Mustache.render(template, data));
|
|
|
|
// animate kill li-element
|
|
$(this._killboardEl[animationPos]).velocity('transition.expandIn', {
|
|
display: 'flex',
|
|
complete: function(){
|
|
$(this).initTooltips();
|
|
}
|
|
}, {
|
|
display: 'flex'
|
|
});
|
|
|
|
resolve({
|
|
action: 'renderKillmail',
|
|
data: {
|
|
chunkSize: chunkSize
|
|
}
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* remove last killmail list entry
|
|
*/
|
|
removeKillmail(){
|
|
if(this._killboardEl){
|
|
let lastEl = this._nextToRemove || (this._listStreamHeadline ? this._listStreamHeadline.previousElementSibling : null) || this._killboardEl.lastChild;
|
|
if(lastEl){
|
|
this._nextToRemove = lastEl.previousElementSibling;
|
|
this._killboardEl.removeChild(lastEl);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* get image src URL
|
|
* @param resourceType
|
|
* @param resourceId
|
|
* @param size
|
|
* @returns {string}
|
|
*/
|
|
getImageUrl(resourceType, resourceId, size = 32){
|
|
let url = '#';
|
|
if(resourceId){
|
|
url = BaseModule.Util.eveImageUrl(resourceType, resourceId, size);
|
|
}
|
|
return url;
|
|
}
|
|
|
|
/**
|
|
* @param text
|
|
* @param cls
|
|
* @returns {HTMLSpanElement}
|
|
*/
|
|
newLabelElement(text, cls = []){
|
|
let labelEl = document.createElement('span');
|
|
labelEl.classList.add('label', 'center-block', ...cls);
|
|
labelEl.textContent = text || '';
|
|
return labelEl;
|
|
}
|
|
|
|
/**
|
|
* Li headline (devider)
|
|
* @param text
|
|
* @returns {HTMLLIElement}
|
|
*/
|
|
newListItemHeadElement(text){
|
|
let listHeadEl = Object.assign(document.createElement('li'), {
|
|
className: ['flex-row', 'flex-between', 'media', this._config.systemKillboardListHeadClass].join(' ')
|
|
});
|
|
|
|
let iconDownEl = this.newIconElement(['fa-angle-double-down']);
|
|
let iconUpEl = this.newIconElement(['fa-angle-double-up']);
|
|
let headlineIconLeftEl = Object.assign(this.newHeadlineElement(), {
|
|
className: 'flex-col'
|
|
});
|
|
let headlineIconRightEl = Object.assign(this.newHeadlineElement(), {
|
|
className: 'flex-col'
|
|
});
|
|
headlineIconLeftEl.append(iconDownEl);
|
|
headlineIconRightEl.append(iconUpEl);
|
|
|
|
let headlineLeftEl = this.newHeadlineElement(text);
|
|
headlineLeftEl.classList.add('flex-col', 'flex-grow', 'media-body');
|
|
let headlineRightEl = this.newHeadlineElement('Killstream');
|
|
headlineRightEl.classList.add('flex-col', 'flex-grow', 'media-body', 'text-right');
|
|
|
|
listHeadEl.append(headlineIconLeftEl, headlineLeftEl, headlineRightEl, headlineIconRightEl);
|
|
return listHeadEl;
|
|
}
|
|
|
|
/**
|
|
* set module observer
|
|
*/
|
|
setModuleObserver(){
|
|
this.setFilterIconObserver();
|
|
|
|
$(this.moduleElement).initTooltips({
|
|
placement: 'top'
|
|
});
|
|
|
|
this.moduleElement.addEventListener('click', e => {
|
|
if(e.target.closest('.' + this._config.controlAreaClass)){
|
|
e.stopPropagation();
|
|
this.showKills(this._config.chunkCountKills);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* init filter icon for WebSocket streams
|
|
*/
|
|
setFilterIconObserver(){
|
|
let cacheKey = `map_${this._mapId}.streams`;
|
|
this.getLocalStore().getItem(cacheKey).then(streams => {
|
|
if(!streams){
|
|
// not saved yet -> default streams
|
|
streams = ['system', 'map'];
|
|
this.getLocalStore().setItem(cacheKey, streams);
|
|
}
|
|
this._filterStreams = streams;
|
|
|
|
let sourceOptions = [{
|
|
value: 'system',
|
|
text: `System (${this._systemData.name})`
|
|
},{
|
|
value: 'map',
|
|
text: `Map (${BaseModule.Util.getObjVal(BaseModule.Util.getCurrentMapData(this._mapId), 'config.name')})`
|
|
},{
|
|
value: 'all',
|
|
text: `All (New Eden)`
|
|
}];
|
|
|
|
$(this._iconFilterEl).editable({
|
|
// toggle: 'manual',
|
|
mode: 'popup',
|
|
type: 'checklist',
|
|
showbuttons: false,
|
|
onblur: 'submit',
|
|
highlight: false,
|
|
title: 'Streams',
|
|
placement: 'left',
|
|
pk: this._mapId,
|
|
value: this._filterStreams,
|
|
source: sourceOptions,
|
|
emptyclass: '',
|
|
emptytext: '',
|
|
display: function(value, sourceData){
|
|
// update filter badge
|
|
if(
|
|
value && sourceData &&
|
|
value.length < sourceData.length
|
|
){
|
|
this.dataset.badge = String(value.length);
|
|
}else{
|
|
delete this.dataset.badge;
|
|
}
|
|
},
|
|
viewport: {
|
|
selector: this.moduleElement,
|
|
padding: 5
|
|
}
|
|
});
|
|
|
|
$(this._iconFilterEl).on('save', (e, params) => {
|
|
this.getLocalStore().setItem(cacheKey, params.newValue).then(streams => this._filterStreams = streams);
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* open external zKillboard URL
|
|
* @param e
|
|
*/
|
|
openKillboardUrl(e){
|
|
e.stopPropagation();
|
|
window.open(`//zkillboard.com/system/${this._systemData.systemId}`, '_blank');
|
|
}
|
|
|
|
/**
|
|
* check if killmailData matches any killStream
|
|
* @param killmailData
|
|
* @returns {boolean}
|
|
*/
|
|
filterKillmailByStreams(killmailData){
|
|
let streams = this._filterStreams || [];
|
|
return !!(streams.includes('all') ||
|
|
(streams.includes('system') && this._systemData.systemId === killmailData.solar_system_id) ||
|
|
(streams.includes('map') && MapUtil.getSystemData(this._mapId, 'systemId', killmailData.solar_system_id)));
|
|
|
|
}
|
|
|
|
/**
|
|
* callback for WebSocket responses
|
|
* @param zkbData
|
|
* @param killmailData
|
|
*/
|
|
onWsMessage(zkbData, killmailData){
|
|
// check if killmail belongs to current filtered "streams"
|
|
if(this.filterKillmailByStreams(killmailData)){
|
|
// check max limit for WS kill entries
|
|
this._countKillsWS = (this._countKillsWS || 0) + 1;
|
|
if(this._countKillsWS > this._config.maxCountKillsWS){
|
|
// remove oldest KM
|
|
this.removeKillmail();
|
|
}
|
|
|
|
// add headline before first WS killmail gets added to top
|
|
if(this._killboardEl && this._countKillsWS === 1){
|
|
this._listStreamHeadline = this.newListItemHeadElement(this._systemData.name);
|
|
this._killboardEl.prepend(this._listStreamHeadline);
|
|
}
|
|
|
|
this.renderKillmail(zkbData, killmailData, null, 0, 'top')
|
|
.catch(e => console.warn(e));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* update module with current WebSocket status
|
|
*/
|
|
updateWsStatus(){
|
|
let isSuccess = false;
|
|
let isWarning = false;
|
|
let isError = false;
|
|
let title = 'unknown';
|
|
switch(SystemKillboardModule.wsStatus){
|
|
case 1: // connecting
|
|
title = 'connecting…';
|
|
isWarning = true;
|
|
break;
|
|
case 2: // connected
|
|
title = 'connected';
|
|
isSuccess = true;
|
|
break;
|
|
case 3: // error
|
|
title = 'error';
|
|
isError = true;
|
|
break;
|
|
case 4: // close
|
|
title = 'closed';
|
|
isError = true;
|
|
break;
|
|
}
|
|
|
|
|
|
this._iconWsEl.classList.toggle('txt-color-green', isSuccess);
|
|
this._iconWsEl.classList.toggle('txt-color-orange', isWarning);
|
|
this._iconWsEl.classList.toggle('txt-color-red', isError);
|
|
this._iconWsEl.setAttribute('title', title);
|
|
|
|
$(this._iconWsEl).destroyTooltips().initTooltips({
|
|
placement: 'top'
|
|
});
|
|
}
|
|
|
|
/**
|
|
* reduce full systemData to minimal data that should be cached with a KM
|
|
* @param systemData
|
|
* @returns {*}
|
|
*/
|
|
static getSystemDataForCache(systemData){
|
|
return systemData ? {id: systemData.systemId, name: systemData.name} : null;
|
|
}
|
|
|
|
/**
|
|
* get all systems from all maps, that might be relevant for any cache stream
|
|
* -> KMs belonging to any of these systems are cached
|
|
* @returns {Object}
|
|
*/
|
|
static getWsRelevantSystemsFromMaps(){
|
|
let cacheKey = SystemKillboardModule.getCacheKey('tempSystemsData', 1);
|
|
let systemsData = SystemKillboardModule.zkbCache.get(cacheKey);
|
|
|
|
if(!systemsData){
|
|
// KB cache ist for all maps (not just the current one)
|
|
let mapsData = BaseModule.Util.getCurrentMapData() || [];
|
|
systemsData = mapsData.reduce(
|
|
(accAll, mapData) => Object.assign(
|
|
accAll,
|
|
(BaseModule.Util.getObjVal(mapData, 'data.systems') || []).reduce(
|
|
(accMap, systemData) => Object.assign(
|
|
accMap,
|
|
{[systemData.systemId]: this.getSystemDataForCache(systemData)}
|
|
), {})
|
|
), {});
|
|
|
|
SystemKillboardModule.zkbCache.set(cacheKey, systemsData);
|
|
}
|
|
return systemsData;
|
|
}
|
|
|
|
/**
|
|
* cache WebSocket response if it is relevant for us
|
|
* @param response
|
|
* @returns {*[]}
|
|
*/
|
|
static cacheWsResponse(response){
|
|
let zkbData = response.zkb;
|
|
delete response.zkb;
|
|
let killmailData = response;
|
|
let systemData = null;
|
|
|
|
// check if killmailData is relevant (belongs to any system on any map
|
|
let systemsData = this.getWsRelevantSystemsFromMaps();
|
|
if(Object.keys(systemsData).map(systemId => parseInt(systemId)).includes(killmailData.solar_system_id)){
|
|
// system is on map! -> cache
|
|
systemData = BaseModule.Util.getObjVal(systemsData, String(killmailData.solar_system_id));
|
|
let cacheKey = SystemKillboardModule.getCacheKey('killmail', killmailData.killmail_id);
|
|
SystemKillboardModule.killmailCache.set(cacheKey, {
|
|
zkb: zkbData,
|
|
killmailData: killmailData,
|
|
systemData: systemData
|
|
});
|
|
}
|
|
|
|
return [zkbData, killmailData];
|
|
}
|
|
|
|
/**
|
|
* subscribe instance of Killboard module to WebSocket
|
|
* @param module
|
|
*/
|
|
static unsubscribeFromWS(module){
|
|
SystemKillboardModule.wsSubscribtions = SystemKillboardModule.wsSubscribtions.filter(subscriber => subscriber !== module);
|
|
}
|
|
|
|
/**
|
|
* unsubscribe instance of Killboard module to WebSocket
|
|
* @param module
|
|
*/
|
|
static subscribeToWS(module){
|
|
if(
|
|
!SystemKillboardModule.wsSubscribtions.includes(module) &&
|
|
module instanceof SystemKillboardModule
|
|
){
|
|
SystemKillboardModule.wsSubscribtions.push(module);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* init/connect to WebSocket if not already done
|
|
*/
|
|
static initWebSocket(){
|
|
if(!SystemKillboardModule.ws){
|
|
SystemKillboardModule.ws = new WebSocket('wss://zkillboard.com:2096');
|
|
SystemKillboardModule.wsStatus = 1;
|
|
}
|
|
|
|
let sendMessage = req => {
|
|
SystemKillboardModule.ws.send(JSON.stringify(req));
|
|
};
|
|
|
|
SystemKillboardModule.ws.onopen = e => {
|
|
SystemKillboardModule.wsStatus = 2;
|
|
SystemKillboardModule.wsSubscribtions.forEach(subscriber => subscriber.updateWsStatus());
|
|
|
|
sendMessage({action:'sub', channel:'killstream'});
|
|
};
|
|
|
|
SystemKillboardModule.ws.onmessage = e => {
|
|
let response = JSON.parse(e.data);
|
|
|
|
let [zkbData, killmailData] = this.cacheWsResponse(response);
|
|
SystemKillboardModule.wsSubscribtions.forEach(subscriber => subscriber.onWsMessage(zkbData, killmailData));
|
|
};
|
|
|
|
SystemKillboardModule.ws.onerror = e => {
|
|
SystemKillboardModule.wsStatus = 3;
|
|
SystemKillboardModule.ws = null;
|
|
SystemKillboardModule.wsSubscribtions.forEach(subscriber => subscriber.updateWsStatus());
|
|
};
|
|
|
|
SystemKillboardModule.ws.onclose = e => {
|
|
SystemKillboardModule.wsStatus = 4;
|
|
SystemKillboardModule.ws = null;
|
|
SystemKillboardModule.wsSubscribtions.forEach(subscriber => subscriber.updateWsStatus());
|
|
};
|
|
}
|
|
|
|
/**
|
|
* get cache key
|
|
* @param type
|
|
* @param objId
|
|
* @returns {string}
|
|
*/
|
|
static getCacheKey(type, objId){
|
|
if(
|
|
typeof type === 'string' && type.length &&
|
|
parseInt(objId)
|
|
){
|
|
return `${type}_${objId}`;
|
|
}
|
|
throw new TypeError('Invalid cache key types');
|
|
}
|
|
};
|
|
|
|
SystemKillboardModule.isPlugin = false; // module is defined as 'plugin'
|
|
SystemKillboardModule.scope = 'system'; // module scope controls how module gets updated and what type of data is injected
|
|
SystemKillboardModule.sortArea = 'c'; // default sortable area
|
|
SystemKillboardModule.position = 1; // default sort/order position within sortable area
|
|
SystemKillboardModule.label = 'Killboard'; // static module label (e.g. description)
|
|
SystemKillboardModule.wsStatus = undefined;
|
|
SystemKillboardModule.serverTime = BaseModule.Util.getServerTime(); // static Date() with current EVE server time
|
|
SystemKillboardModule.zkbCache = new Cache({ // cache for "zKillboard" responses -> short term cache
|
|
name: 'zkb',
|
|
ttl: 60 * 3,
|
|
maxSize: 50,
|
|
debug: false
|
|
});
|
|
SystemKillboardModule.killmailCache = new Cache({ // cache for "Killmail" data -> long term cache
|
|
name: 'ccpKillmails',
|
|
ttl: 60 * 30,
|
|
maxSize: 500,
|
|
debug: false
|
|
});
|
|
SystemKillboardModule.wsSubscribtions = []; // static container for all KB module instances (from multiple maps) for WS responses
|
|
|
|
SystemKillboardModule.defaultConfig = {
|
|
className: 'pf-system-killboard-module', // class for module
|
|
sortTargetAreas: ['a', 'b', 'c'], // sortable areas where module can be dragged into
|
|
headline: 'Killboard',
|
|
|
|
// system killboard list
|
|
systemKillboardListClass: 'pf-system-killboard-list', // class for a list with kill entries
|
|
systemKillboardListHeadClass: 'pf-system-killboard-list-head', // class for a list entry headline
|
|
systemKillboardListImgL: 'pf-system-killboard-img-l', // class for all large centered img (ship images)
|
|
systemKillboardListImgM: 'pf-system-killboard-img-m', // class for all medium centered img (character logos)
|
|
systemKillboardListImgS: 'pf-system-killboard-img-s', // class for all small top/bottom img (alliance/corp logos)
|
|
|
|
wsStatusWrapperClass: 'pf-system-killboard-wsStatusWrapper', // class for WebSocket "status" wrapper
|
|
wsStatusClass: 'pf-system-killboard-wsStatus', // class for WebSocket "status" headline
|
|
labelRecentKillsClass: 'pf-system-killboard-label-recent', // class for "recent kills" label
|
|
controlAreaClass: 'pf-module-control-area', // class for "control" areas
|
|
|
|
minCountKills: 5,
|
|
chunkCountKills: 5,
|
|
maxCountKillHistoric: 43,
|
|
|
|
maxCountKillsWS: 150
|
|
};
|
|
|
|
return SystemKillboardModule;
|
|
}); |