Last active
June 11, 2019 17:21
-
-
Save sanchezzzhak/168180f811bc6993242f1d97f9f98d5a to your computer and use it in GitHub Desktop.
Molecularjs service device detect (es6 for nodejs 12+ private property)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const Service = require("moleculer").Service; | |
const DetectDetector = require('node-device-detector'); | |
const MemCache = require("../mixins/memcache"); | |
const crypto = require('crypto'); | |
const DEVICE_TYPE = require('node-device-detector/parser/const/device-type'); | |
/** | |
* @typedef {Object} DetectCtxParams | |
* @property {String} userAgent | |
*/ | |
class DeviceDetectorService extends Service { | |
#cache = true; | |
#detector; | |
constructor(broker) { | |
super(broker); | |
this.parseServiceSchema({ | |
name: 'device-detector', | |
mixins: [ | |
MemCache({}) | |
], | |
actions: { | |
"detect": this.detectHandler, | |
"detect-bot": this.detectBotHandler | |
}, | |
created: this.serviceCreated, | |
started: this.serviceStarted, | |
stopped: this.serviceStopped, | |
}); | |
} | |
/** | |
* @param {DetectCtxParams} ctx.params | |
* @returns {Promise<Object>} | |
*/ | |
async detectHandler(ctx) { | |
const {userAgent} = ctx.params; | |
let detectData = null; | |
let cacheData = null; | |
let keyCache = null; | |
if (this.#cache) { | |
keyCache = crypto.createHash('md5').update(userAgent).digest('hex'); | |
cacheData = await this.memcache.getCache(keyCache); | |
if (cacheData) { | |
detectData = cacheData; | |
} | |
} | |
if (!detectData) { | |
let resultOs = this.#detector.parseOs(userAgent); | |
let resultClient = this.#detector.parseClient(userAgent); | |
let resultDeviceType = this.#detector.parseDeviceType(userAgent, resultOs, resultClient, {}); | |
detectData = Object.assign({os: resultOs}, {client: resultClient}, {device: resultDeviceType}); | |
} | |
if (this.#cache && !cacheData) { | |
await this.memcache.setCache(keyCache, detectData, 3600); | |
} | |
let mixData = this.detectType(userAgent, detectData); | |
return Object.assign({}, detectData, mixData); | |
} | |
// public | |
/** | |
* @param {DetectCtxParams} ctx.params | |
* @returns {Promise<Object>} | |
*/ | |
detectBotHandler(ctx) { | |
const {userAgent} = ctx.params; | |
return this.#detector.parseBot(userAgent); | |
} | |
// private | |
detectType(userAgent, detectData) { | |
let isTabled = detectData.device && [DEVICE_TYPE.TABLET].indexOf(detectData.device.type) !== -1; | |
let isMobile = detectData.device && [DEVICE_TYPE.SMARTPHONE, DEVICE_TYPE.FEATURE_PHONE].indexOf(detectData.device.type) !== -1; | |
let isPhablet = detectData.device && [DEVICE_TYPE.PHABLET].indexOf(detectData.device.type) !== -1; | |
let isIOS = detectData.os && detectData.os.family === 'iOS'; | |
let isIPhone = ''; | |
let isAndroid = detectData.os && detectData.os.family === 'Android'; | |
let isDesktop = !isTabled && !isMobile && !isPhablet; | |
let isYaBrowser = /(Yandex.Browser|YaBrowser)/i.test(userAgent); | |
return { | |
isDesktop: isDesktop, | |
isTabled: isTabled, | |
isMobile: isMobile, | |
isPhablet: isPhablet, | |
isIOS: isIOS, | |
isIPhone: isIPhone, | |
isAndroid: isAndroid, | |
isYaBrowser: isYaBrowser | |
}; | |
} | |
serviceCreated() { | |
this.#detector = new DetectDetector(); | |
} | |
serviceStarted() { | |
} | |
serviceStopped() { | |
} | |
} | |
module.exports = DeviceDetectorService; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const Memcached = require('memcached'); | |
/** | |
* usage in service | |
* ```js | |
* let resultGet = await this.memcache.getCache(<key>) | |
* let resultSet = await this.memcache.setCache(<key>, <data>) | |
* let resultRemove = await this.memcache.removeCache(<key>) | |
* ``` | |
* */ | |
class MemCacheAdapter { | |
#cache = null; | |
constructor(config = {}) { | |
this.#cache = new Memcached(); | |
} | |
/** | |
* Запись в кеш | |
* @param {String} key | |
* @param {*} val | |
* @param {Number} expTime | |
* @returns {Promise<any>} | |
*/ | |
setCache(key, val, expTime = 3600) { | |
return new Promise((resolve, reject) => { | |
this.#cache.set(key, val, expTime, (err) => { | |
if (err) { | |
reject(err); | |
} else { | |
resolve(null); | |
} | |
}); | |
}); | |
} | |
/** | |
* Удалить из кеша | |
* @param {String} key | |
* @returns {Promise<any>} | |
*/ | |
removeCache(key) { | |
return new Promise((resolve, reject) => { | |
this.#cache.del(key, (err, result) => { | |
if (err) { | |
reject(err); | |
} else { | |
resolve(result); | |
} | |
}); | |
}); | |
} | |
/** | |
* Чтение из кеша | |
* @param {String} key | |
* @returns {Promise<any>} | |
*/ | |
getCache(key) { | |
return new Promise((resolve, reject) => { | |
this.#cache.get(key, (err, result) => { | |
if (err) { | |
reject(err); | |
} else { | |
resolve(result); | |
} | |
}); | |
}); | |
} | |
on(event, callback) { | |
this.#cache.on(event, callback); | |
} | |
} | |
/* | |
* | |
* @param componentName | |
* @param config | |
* @returns {{settings: {[p: string]: *}, stopped(), created(): void, started()}} | |
*/ | |
module.exports = ({keyComponent: componentName = 'memcache', config: config} = {}) => ({ | |
settings: { | |
[componentName]: config, | |
}, | |
created() { | |
this[componentName] = new MemCacheAdapter(this.settings[componentName]); | |
this[componentName].on('failure', (details) => { | |
this.logger.error( | |
`Server ${details.server} went down due to: ${details.messages.join('')}` | |
); | |
}); | |
this[componentName].on('reconnecting', (details) => { | |
this.logger.info( | |
`Total downtime caused by server ${details.server} : ${details.totalDownTime} ms` | |
); | |
}); | |
}, | |
started() { | |
}, | |
stopped() { | |
}, | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
async actionUserAgentInfo(ctx){ | |
const {userAgent} = ctx.params; | |
// detect device | |
let deviceInfo = await this.broker.call("device-detect.detect", { | |
userAgent: userAgent | |
}); | |
// detect bots | |
let botInfo = await this.broker.call("device-detect.detect-bot", { | |
userAgent: userAgent | |
}); | |
// parelel | |
/* | |
let result = await Promise.all([ | |
this.broker.call("device-detect.detect", {userAgent: userAgent}), | |
this.broker.call("device-detect.detect-bot", {userAgent: userAgent}) | |
]); | |
let [deviceInfo, botInfo] = result; | |
*/ | |
return deviceInfo; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment