import { _decorator, Component, CCString, Enum, game } from 'cc'; import { Log } from '../utils/Log'; import { Random } from '../utils/Random'; import { RC4 } from '../utils/RC4'; import { HttpMethod, HttpResponseCode } from './Http'; import { HttpRequest } from './HttpRequest'; const { ccclass, property, executionOrder } = _decorator; @ccclass("HostData") export class HostData { @property({ tooltip: "别名" }) public alias: string = "袁浩"; @property({ tooltip: "地址" }) public host: string = "172.16.15.214"; @property({ tooltip: "端口", min: 0, step: 1 }) public port: number = 80; @property({ tooltip: "SSL" }) public SSL: boolean = false; } /** * 当请求出错时,抛出错误还是返回对象 */ export enum ErrorDataType { /** * 返回空对象 */ Null, /** * 抛出异常 */ Throw, /** * 返回无key对象:{} */ Object } /** * Http配置组件 * @description 用于配置HTTP * @author 袁浩 */ @ccclass('HttpSystem') export class HttpSystem extends Component { @property({ tooltip: "默认主机", step: 1, min: 0 }) public hostIndex: number = 0; @property({ type: [HostData], tooltip: "主机列表" }) public hosts = []; @property({ tooltip: "请求带的公共的参数,xxx=xxx", type: [CCString] }) public tails: string[] = []; @property({ tooltip: "当请求出错时,抛出错误还是返回对象", type: Enum(ErrorDataType) }) public errorDataType: ErrorDataType = ErrorDataType.Null; @property({ tooltip: "消息日志" }) public useDebugLog: boolean = true; @property({ tooltip: "加密密钥" }) public key = '🧧🎁🎉💰🤩😍💯🉐📦💥'; private encryptionKey: number; private randomList: string[]; private static thisObject: HttpSystem; private defaultTails: string[]; start() { game.addPersistRootNode(this.node); HttpSystem.thisObject = this; this.randomList = Array.from(this.key); this.defaultTails = this.tails.concat(); } private random: Random; private _publicKey: string; /** * 公钥 */ private get publicKey() { return this._publicKey; } private set publicKey(value: string) { this._publicKey = value; let values = Array.from(value); let seed = ''; for (let i = 0; i < values.length; i++) { seed += this.randomList.indexOf(values[i]); } this.random = new Random(parseInt(seed)); Log.trace(`随机密钥:${value} 随机值:${seed}`); } private resetPublicKey() { let randomValue = Math.floor(this.random.range(0, 10000000000)) + ''; let randomStr = ""; for (let i = 0; i < randomValue.length; i++) { randomStr += this.randomList[randomValue.charAt(i)]; } this._publicKey = randomStr; this.random.seed = parseInt(randomValue); Log.trace(`随机密钥:${randomStr} 随机值:${randomValue}`); } private getErrorDataType() { return this.errorDataType; } public getConfig(hostAlias?: string): HostData { if (!hostAlias) { return this.hosts[this.hostIndex]; } for (let i = 0; i < this.hosts.length; i++) { const host = this.hosts[i]; if (host.alias == hostAlias) { return host; } } } public get tailString() { var result = ""; for (let i = 0; i < this.tails.length; i++) { const tail = this.tails[i]; result = (result.length ? `${result}&${tail}` : `${tail}`) } return result; } public addTail(tails: string | string[]) { if (typeof tails == 'string') { this.tails.push(tails); } else { this.tails = this.tails.concat(tails); } } public resetTail() { this.tails = this.defaultTails.concat(); } public setEncryptionKey(encryptionKey: number) { this.encryptionKey = encryptionKey; } public getPrivateKey(): number { return this.encryptionKey; } private serverTimestamp: number; private tempTime: number; public initServerTimestamp(value: number) { this.serverTimestamp = value; this.tempTime = Date.now(); } public get serverTime() { return this.serverTimestamp + (Date.now() - this.tempTime); } public static dataToString(data: any): string { data = data || {}; let result = ""; for (let key in data) { let v = data[key]; if (typeof data[key] == 'object') { v = JSON.stringify(data[key]); } result += encodeURI(key) + "=" + encodeURI(v) + "&"; } return result; } public static encrypt(data: string, method: HttpMethod) { data = encodeURIComponent(data); let privateKey = HttpSystem.getPrivateKey(); data = encodeURIComponent(RC4.rc4(HttpSystem.publicKey + data, privateKey.toString())); if (method == HttpMethod.GET) { return "d=" + data + "&"; } else { return JSON.stringify({ d: data }); } } public static decrypt(data: any) { if (data) { data = decodeURIComponent(data.d); data = RC4.rc4(data, HttpSystem.publicKey); let keyIndex = data.indexOf(HttpSystem.publicKey); if (keyIndex != 0) {//密钥不正确 return JSON.stringify({ code: HttpResponseCode.KeyError }); } data = data.substr(HttpSystem.publicKey.length); } return data; } public send(path: string, useEncrypt: boolean, data?: any, useTail: boolean = true, method: HttpMethod = HttpMethod.GET, onProgress?: (loaded: number, total: number) => void) { return new Promise((resolve: (data: HttpRequest) => void, reject) => { let request = new HttpRequest(reject, resolve, onProgress); data = data || {}; data.timestamp = HttpSystem.serverTime; let getData: string = typeof data == 'object' ? HttpSystem.dataToString(data) : data; let postData = method == HttpMethod.GET ? null : (typeof data == 'object' ? JSON.stringify(data) : data); let url: string = this.getRootURL() + (method == HttpMethod.GET ? path + "?" + getData : path); this.useDebugLog && HttpSystem.useDebugLog && Log.info(`http请求[${url}]发送`); if (useEncrypt) {//如果消息加密 if (method == HttpMethod.GET) { getData = HttpSystem.encrypt(getData, method); } else { postData = HttpSystem.encrypt(postData, method); } } useTail && (getData += HttpSystem.tailString); url = this.getRootURL() + (method == HttpMethod.GET ? path + "?" + getData : path); request.open(url, method); request.send(postData); }) } public getRootURL(hostAlias = ""): string { let config = HttpSystem.getConfig(); var port = `:${config.port}`; if (config.SSL && config.port == 443 || !config.SSL && config.port == 80) { port = ''; } return `${config.SSL ? "https://" : "http://"}${config.host}${port}`; } /** * 根据主机别名获取主机的配置 * @param hostAlias 主机别名 * @returns */ public static getConfig(hostAlias?: string): HostData { return this.thisObject.getConfig(hostAlias); } /** * 续签公钥 */ public static resetPublicKey() { return this.thisObject.resetPublicKey(); } /** * 请求出错返回的数据类型 * @returns */ public static getErrorDataType() { return this.thisObject.getErrorDataType(); } /** * 尾巴内容 */ public static get tailString() { return this.thisObject.tailString; } /** * 是否启用日志 */ public static get useDebugLog() { return this.thisObject.useDebugLog; } public static set useDebugLog(value: boolean) { this.thisObject.useDebugLog = value; } /** * 服务器当前时间 * @returns */ public static get serverTime() { return this.thisObject.serverTime; } /** * 初始化服务器时间戳 */ public static initServerTimestamp(value: number) { this.thisObject.initServerTimestamp(value); } /** * 获取加密私钥 * @returns 私钥 */ public static getPrivateKey(): number { return this.thisObject.getPrivateKey(); } /** * 加密公钥 * @returns 私钥 */ public static get publicKey(): string { return this.thisObject.publicKey; } public static set publicKey(value: string) { this.thisObject.publicKey = value; } /** * 新增一个尾巴内容 * @param tails 尾巴内容,xxx=xxx */ public static addTail(tails: string | string[]) { this.thisObject.addTail(tails); } /** * 重置尾巴内容到默认值 */ public static resetTail() { this.thisObject.resetTail(); } /** * 设置加密密钥 * @param encryptionKey 密钥 */ public static setEncryptionKey(encryptionKey: number) { this.thisObject.setEncryptionKey(encryptionKey); } /** * 发送Http请求 * @param url 请求地址 * @param data 数据 * @param method 请求类型方法 * @param onProgress 进度 * @returns */ public static send(path: string, useEncrypt: boolean, data?: any, useTail: boolean = true, method: HttpMethod = HttpMethod.GET, onProgress?: (loaded: number, total: number) => void) { this.thisObject.send(path, useEncrypt, data, useTail, method, onProgress); } }