Skip to content

Instantly share code, notes, and snippets.

@sanchezzzhak
Last active June 11, 2019 17:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sanchezzzhak/168180f811bc6993242f1d97f9f98d5a to your computer and use it in GitHub Desktop.
Save sanchezzzhak/168180f811bc6993242f1d97f9f98d5a to your computer and use it in GitHub Desktop.
Molecularjs service device detect (es6 for nodejs 12+ private property)
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;
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() {
},
});
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