Files
ZYZ/game-server/app/services/sdk/ta.ts
2022-07-19 17:14:11 +08:00

396 lines
11 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 模仿thinkingdata-node直接写一个log的写入而日志直接用pinus-logger实现
*/
import { taLogger } from "../../util/logger";
const KEY_NAME_MATCH_REGEX = /^[a-zA-Z#][a-zA-Z0-9_]+$/;
let util: any = {};
util.version = '1.2.2';
util.log = function(message: string) {
console.log(message);
}
util.each = function (obj, iterator, context) {
if (obj === null) {
return;
}
if (Array.prototype.forEach && obj.forEach === Array.prototype.forEach) {
obj.forEach(iterator, context);
} else if (obj.length === +obj.length) {
for (let i = 0, l = obj.length; i < l; i++) {
if (i in obj && iterator.call(context, obj[i], i, obj) === {}) {
return;
}
}
} else {
for (let key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
if (iterator.call(context, obj[key], key, obj) === {}) {
return;
}
}
}
}
};
util.formatDate = function (d) {
function pad(n) {
return n < 10 ? '0' + n : n;
}
function padMilliseconds(n) {
if (n < 10) {
return '00' + n;
} else if (n < 100) {
return '0' + n;
} else {
return n;
}
}
return d.getFullYear() + '-' +
pad(d.getMonth() + 1) + '-' +
pad(d.getDate()) + ' ' +
pad(d.getHours()) + ':' +
pad(d.getMinutes()) + ':' +
pad(d.getSeconds()) + '.' +
padMilliseconds(d.getMilliseconds());
};
util.searchObjDate = function (o) {
if (util.check.isObject(o) || util.check.isArray(o)) {
util.each(o, function (a, b) {
if (util.check.isObject(a) || util.check.isArray(a)) {
util.searchObjDate(o[b]);
} else {
if (util.check.isDate(a)) {
o[b] = util.formatDate(a);
}
}
});
}
};
util.check = {
isUndefined: function (obj) {
return obj === void 0;
},
isObject: function (obj) {
return (toString.call(obj) === '[object Object]') && (obj !== null);
},
isEmptyObject: function (obj) {
if (util.check.isObject(obj)) {
for (let key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
return false;
}
}
return true;
}
return false;
},
isArray: function (obj) {
return toString.call(obj) === '[object Array]';
},
isString: function (obj) {
return toString.call(obj) === '[object String]';
},
isDate: function (obj) {
return toString.call(obj) === '[object Date]';
},
isNumber: function (obj) {
return toString.call(obj) === '[object Number]';
},
isBoolean: function (obj) {
return toString.call(obj) === '[object Boolean]';
},
isJSONString: function (str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
};
util.properties = {
_strip: function (prop) {
if (!util.check.isObject(prop)) {
return prop;
}
util.each(prop, function (v, k) {
if (!(util.check.isString(v) || util.check.isNumber(v) || util.check.isDate(v) || util.check.isBoolean(v) || util.check.isArray(v))) {
util.log('您的数据-', k, v, '-格式不满足要求,我们已经将其删除. 属性值只支持 String, Number, Date, Boolean, Array');
delete prop[k];
}
});
return prop;
},
_checkPropertiesKey: function (obj) {
let flag = true;
util.each(obj, (v, k) => {
if (!KEY_NAME_MATCH_REGEX.test(k)) {
util.log('不合法的 KEY 值: ' + k);
flag = false;
}
});
return flag;
},
name: function (s) {
if (!util.check.isString(s) || !KEY_NAME_MATCH_REGEX.test(s)) {
util.log('请检查参数格式, 事件或属性名称必须是英文字母、 \'util\'或\'#\' 开头, 包含字母和数字的字符串: ' + s);
return false;
} else {
return true;
}
},
properties: function (p) {
this._strip(p);
if (p) {
if (util.check.isObject(p)) {
if (this._checkPropertiesKey(p)) {
return true;
} else {
util.log('请检查参数格式, properties 的 key 只能以字母或\'#\'开头,包含数字、字母和下划线 util');
return false;
}
} else {
util.log('properties 可以没有,但有的话必须是对象');
return false;
}
} else {
return true;
}
},
propertiesMust: function (p) {
this._strip(p);
if (p === undefined || !util.check.isObject(p) || util.check.isEmptyObject(p)) {
util.log('properties 必须是对象且有值');
return false;
} else {
if (this._checkPropertiesKey(p)) {
return true;
} else {
util.log('请检查参数格式, properties 的 key 只能以字母或\'#\'开头,包含数字、字母和下划线 util');
return false;
}
}
},
userId: function (id) {
if (util.check.isString(id) && /^.+$/.test(id)) {
return true;
} else {
util.log('用户 id 必须是不能为空');
return false;
}
}
}
const DEFAULT_PROPERTIES = {
"#lib": "node",
"#lib_version": util.version,
};
/**
* 内部函数,创建 ta 实例
*/
let _createClient = function (consumer) {
let ta: any = {};
ta.consumer = consumer;
ta.superProperties = {};
ta._basicCheck = function (params) {
if (!util.check.isObject(params)) {
return new Error("params for track must be an object");
}
if (!util.properties.userId(params.accountId) && !util.properties.userId(params.distinctId)) {
return new Error("account ID and distinct ID cannot be empty at the same time");
}
return undefined;
};
ta.track = function (params, skipLocalCheck = false) {
let callback = params.callback || function () {
};
if (!ta._trackCheck(params, skipLocalCheck, callback)) {
return;
}
ta._sendRequest("track", params, callback);
};
ta._trackCheck = function (params, skipLocalCheck, callback) {
let err = this._basicCheck(params);
if (err) {
callback(err);
return false;
}
if (!util.properties.name(params.event)) {
callback(new Error("invalid event name"));
return false;
}
if (!skipLocalCheck && !util.properties.properties(params.properties)) {
callback(new Error("invalid properties"));
return false;
}
return true;
};
ta.userSet = function (params) {
let callback = params.callback || function () {
};
let err = this._basicCheck(params);
if (err) {
callback(err);
return;
}
if (!util.properties.propertiesMust(params.properties)) {
callback(new Error("invalid properties"));
return;
}
ta._sendRequest("user_set", params, callback);
};
ta.userSetOnce = function (params) {
let callback = params.callback || function () {
};
let err = this._basicCheck(params);
if (err) {
callback(err);
return;
}
if (!util.properties.propertiesMust(params.properties)) {
callback(new Error("invalid properties"));
return;
}
ta._sendRequest("user_setOnce", params, callback);
};
ta.userAdd = function (params) {
let callback = params.callback || function () {
};
let err = this._basicCheck(params);
if (err) {
callback(err);
return;
}
if (!util.properties.propertiesMust(params.properties)) {
callback(new Error("invalid properties"));
return;
}
ta._sendRequest("user_add", params, callback);
};
ta.setDynamicSuperProperties = function (getDynamicProperties, callback) {
let err;
if (typeof getDynamicProperties === "function") {
if (util.properties.properties(getDynamicProperties())) {
ta.getDynamicProperties = getDynamicProperties;
} else {
err = new Error("Invalid return type of getDynamicProperties");
}
} else {
err = new Error("getDynamicProperties must be a funciton");
}
if (callback && err) {
callback(err);
}
};
// 内部函数,组织数据格式,并发送给对应的 consumer 去处理
ta._sendRequest = function (type, eventData, callback) {
let time = util.check.isUndefined(eventData.time) || !util.check.isDate(eventData.time)
? new Date()
: eventData.time;
let data = {
"#type": type,
"#time": util.formatDate(time),
};
if (eventData.distinctId) {
data["#distinct_id"] = eventData.distinctId;
}
if (eventData.accountId) {
data["#account_id"] = eventData.accountId;
}
if (eventData.ip) {
data["#ip"] = eventData.ip;
}
if (eventData.event) {
data["#event_name"] = eventData.event;
}
if (eventData.eventId) {
data["#event_id"] = eventData.eventId;
}
if (eventData.firstCheckId) {
data["#first_check_id"] = eventData.firstCheckId;
}
if (eventData.uuid) {
data["#uuid"] = eventData.uuid;
}
if (eventData.appId) {
data["#app_id"] = eventData.appId;
}
if (type === "track" ||
type === "track_update" ||
type === "track_overwrite") {
data["properties"] = { ...DEFAULT_PROPERTIES, ...ta.superProperties, ...(ta.getDynamicProperties ? ta.getDynamicProperties() : {}) };
} else {
data["properties"] = {};
}
if (
util.check.isObject(eventData.properties) &&
!util.check.isEmptyObject(eventData.properties)
) {
data['properties'] = { ...data['properties'], ...eventData.properties || {} }
}
util.searchObjDate(data);
this.consumer.add(data, callback);
};
return ta;
};
export function initTaLoggingMode() {
return _createClient({
add: (msg: string) => {
taLogger.info(JSON.stringify(msg));
}
})
}