JCEngine.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. export class JCEngine {
  2. public static entityClass: new() => JCEntity;
  3. public static boot(url: string, entityClass: new() => JCEntity) {
  4. JCEngine.entityClass = entityClass;
  5. new WebSocketServer(url);
  6. }
  7. }
  8. export class JCEntity {
  9. public id: number;
  10. public channel: JCChannel;
  11. public isValid: boolean;
  12. public onLoad() {}
  13. public onDestroy() {}
  14. public call(func: string, args?: any[], callback?: Function) {
  15. if (this.isValid) {
  16. let uuid = "";
  17. let type = JCDataType.FUNCTION;
  18. if (func.indexOf(".") > -1) {
  19. uuid = JCUtil.uuid();
  20. type = JCDataType.METHOD;
  21. if (!callback) {
  22. callback = arguments[arguments.length - 1];
  23. }
  24. CallbackManager.addCallback(uuid, callback);
  25. }
  26. if (args == undefined) {
  27. args = [];
  28. }
  29. let data = {uuid: uuid, type: type, func: func, args: args};
  30. this.channel.writeAndFlush(JSON.stringify(data));
  31. }
  32. }
  33. }
  34. class JCChannel {
  35. private webSocket: WebSocket;
  36. constructor(webSocket: WebSocket) {
  37. this.webSocket = webSocket;
  38. }
  39. public writeAndFlush(text: string) {
  40. this.webSocket.send(text);
  41. }
  42. public close() {
  43. this.webSocket.close();
  44. }
  45. }
  46. class WebSocketServer {
  47. private webSocket: WebSocket;
  48. private tempEntity: JCEntity;
  49. constructor(url: string) {
  50. if (this.webSocket && this.webSocket.OPEN) {
  51. this.webSocket.close();
  52. }
  53. this.webSocket = new WebSocket(url);
  54. this.webSocket.onopen = () => {
  55. this.call("loadTempEntity");
  56. }
  57. this.webSocket.onclose = () => {
  58. this.destroyTempEntity();
  59. }
  60. this.webSocket.onmessage = (event: MessageEvent) => {
  61. this.invoke(JSON.parse(event.data));
  62. }
  63. }
  64. private call(func: string, args?: any[]) {
  65. if (args == undefined) {
  66. args = [];
  67. }
  68. let data:JCData = {uuid: "", type: JCDataType.EVENT, func: func, args: args};
  69. this.webSocket.send(JSON.stringify(data));
  70. }
  71. private invoke(data: JCData) {
  72. if (data.type == JCDataType.EVENT) {
  73. this[data.func].apply(this, data.args);
  74. return;
  75. }
  76. if (data.type == JCDataType.FUNCTION) {
  77. if (this.tempEntity.isValid) {
  78. this.tempEntity[data.func].apply(this.tempEntity, data.args);
  79. }
  80. return;
  81. }
  82. if (data.type == JCDataType.METHOD) {
  83. CallbackManager.handleCallback(data);
  84. }
  85. }
  86. public loadTempEntity(id: number) {
  87. this.tempEntity = new JCEngine.entityClass();
  88. this.tempEntity.id = id;
  89. this.tempEntity.channel = new JCChannel(this.webSocket);
  90. this.tempEntity.isValid = true;
  91. this.tempEntity.onLoad();
  92. }
  93. public destroyTempEntity() {
  94. this.tempEntity.isValid = false;
  95. this.tempEntity.onDestroy();
  96. }
  97. }
  98. class CallbackManager {
  99. private static mapper: Map<string, CallbackInfo> = new Map();
  100. public static addCallback(uuid: string, callback: Function) {
  101. if (callback instanceof Function) {
  102. this.mapper.set(uuid, {
  103. callback: callback,
  104. deadTime: Date.now() + 10 * 1000
  105. });
  106. }
  107. }
  108. public static handleCallback(data: JCData) {
  109. if (this.mapper.size > 10) {
  110. let now = Date.now();
  111. for (let item of (this.mapper as any)) {
  112. let key = item[0].deadTime;
  113. let value = item[1];
  114. if (now >= value.deadTime) {
  115. this.mapper.delete(key);
  116. }
  117. }
  118. }
  119. let callbackInfo = this.mapper.get(data.uuid);
  120. if (callbackInfo && callbackInfo.callback instanceof Function) {
  121. this.mapper.delete(data.uuid);
  122. callbackInfo.callback(data.args[0]);
  123. }
  124. }
  125. }
  126. class JCUtil {
  127. public static uuid(): string {
  128. let arr = [];
  129. let hexDigits = "0123456789abcdef";
  130. for (let i = 0; i < 36; i++) {
  131. arr[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
  132. }
  133. arr[14] = "4";
  134. arr[19] = hexDigits.substr((arr[19] & 0x3) | 0x8, 1);
  135. arr[8] = arr[13] = arr[18] = arr[23] = "";
  136. return arr.join("");
  137. }
  138. }
  139. interface CallbackInfo {
  140. callback: Function;
  141. deadTime: number;
  142. }
  143. interface JCData {
  144. uuid: string;
  145. type: number;
  146. func: string;
  147. args: any[];
  148. }
  149. enum JCDataType {
  150. EVENT,
  151. FUNCTION,
  152. METHOD
  153. }