JCEngine.cs 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. using System;
  2. using System.Collections.Generic;
  3. using BestHTTP.WebSocket;
  4. using Newtonsoft.Json;
  5. public class JCEngine {
  6. public static string url;
  7. public static Type entityClass;
  8. public static void boot(string url, Type entityClass) {
  9. JCEngine.url = url;
  10. JCEngine.entityClass = entityClass;
  11. new JCEngineCore.WebSocketServer(url, null);
  12. }
  13. public static void reBoot(JCEntity entity) {
  14. new JCEngineCore.WebSocketServer(url, entity);
  15. }
  16. }
  17. public class JCEntity {
  18. public int id;
  19. public JCEngineCore.Channel channel;
  20. public bool isValid;
  21. public bool loaded;
  22. public Dictionary<string, object> components = new Dictionary<string, object>();
  23. public virtual void onLoad() {}
  24. public virtual void onReload() {}
  25. public virtual void onDestroy() {}
  26. public virtual void onMiss() {}
  27. public bool call(string func, params object[] args) {
  28. return call(func, args, null);
  29. }
  30. public bool call(string func, object[] args = null, Delegate callback = null) {
  31. if (this.isValid) {
  32. string uuid = "";
  33. int type = Convert.ToInt32(JCEngineCore.DataType.FUNCTION);
  34. if (func.IndexOf(".") > -1) {
  35. type = Convert.ToInt32(JCEngineCore.DataType.METHOD);
  36. uuid = JCEngineCore.CallbackHandler.addCallback(callback);
  37. }
  38. if (args == null) {
  39. args = new object[]{};
  40. }
  41. JCEngineCore.Data data = new JCEngineCore.Data();
  42. data.uuid = uuid;
  43. data.type = type;
  44. data.func = func;
  45. data.args = args;
  46. this.channel.writeAndFlush(JsonConvert.SerializeObject(data));
  47. return true;
  48. }
  49. return false;
  50. }
  51. }
  52. namespace JCEngineCore {
  53. public class Channel {
  54. private WebSocket webSocket;
  55. public Channel (WebSocket webSocket) {
  56. this.webSocket = webSocket;
  57. }
  58. public void writeAndFlush(string text) {
  59. this.webSocket.Send(text);
  60. }
  61. public void close() {
  62. this.webSocket.Close();
  63. }
  64. }
  65. class WebSocketServer {
  66. private WebSocket webSocket;
  67. private JCEntity tempEntity;
  68. public WebSocketServer(string url, JCEntity entity) {
  69. this.webSocket = new WebSocket(new Uri(url));
  70. this.webSocket.StartPingThread = true;
  71. this.tempEntity = entity != null ? entity : JCEngine.entityClass.Assembly.CreateInstance(JCEngine.entityClass.FullName) as JCEntity;
  72. this.webSocket.OnOpen += delegate(WebSocket webSocket) {
  73. this.call("loadTempEntity");
  74. };
  75. this.webSocket.OnClosed = delegate(WebSocket webSocket, UInt16 code, string message) {
  76. this.destroyTempEntity();
  77. };
  78. this.webSocket.OnError = delegate(WebSocket webSocket, Exception ex) {
  79. this.destroyTempEntity();
  80. };
  81. this.webSocket.OnMessage = delegate(WebSocket webSocket, string message) {
  82. this.invoke(JsonConvert.DeserializeObject<Data>(message));
  83. };
  84. this.webSocket.Open();
  85. }
  86. private void call(string func, object[] args = null) {
  87. if (args == null) {
  88. args = new object[]{};
  89. }
  90. Data data = new Data();
  91. data.uuid = "";
  92. data.type = Convert.ToInt32(DataType.EVENT);
  93. data.func = func;
  94. data.args = args;
  95. this.webSocket.Send(JsonConvert.SerializeObject(data));
  96. }
  97. private void invoke(Data data) {
  98. DataType dataType = (DataType) data.type;
  99. if (dataType == DataType.EVENT) {
  100. System.Reflection.MethodInfo method = this.GetType().GetMethod(data.func);
  101. Utility.formatArgsType(data.args, method.GetParameters());
  102. method.Invoke(this, data.args);
  103. return;
  104. }
  105. if (dataType == DataType.FUNCTION) {
  106. if (this.tempEntity.isValid) {
  107. string func = data.func;
  108. object context = this.tempEntity;;
  109. int pointIndex = func.LastIndexOf(".");
  110. if (pointIndex > -1) {
  111. context = null;
  112. string key = func.Substring(0, pointIndex);
  113. object matchContext;
  114. this.tempEntity.components.TryGetValue(key, out matchContext);
  115. if (matchContext != null) {
  116. string[] arr = func.Split(new char[]{'.'});
  117. func = arr[arr.Length - 1];
  118. context = matchContext;
  119. }
  120. }
  121. if (context != null) {
  122. System.Reflection.MethodInfo method = context.GetType().GetMethod(func);
  123. Utility.formatArgsType(data.args, method.GetParameters());
  124. method.Invoke(context, data.args);
  125. }
  126. }
  127. return;
  128. }
  129. if (dataType == DataType.METHOD) {
  130. CallbackHandler.handleCallback(data);
  131. }
  132. }
  133. public void loadTempEntity(int id) {
  134. this.tempEntity.id = id;
  135. this.tempEntity.channel = new Channel(this.webSocket);
  136. this.tempEntity.isValid = true;
  137. try {
  138. if (this.tempEntity.loaded) {
  139. this.tempEntity.onReload();
  140. } else {
  141. this.tempEntity.onLoad();
  142. }
  143. } catch (Exception) {}
  144. this.tempEntity.loaded = true;
  145. }
  146. public void destroyTempEntity() {
  147. if (this.tempEntity.isValid) {
  148. this.tempEntity.isValid = false;
  149. this.tempEntity.onDestroy();
  150. } else {
  151. this.tempEntity.onMiss();
  152. }
  153. }
  154. }
  155. class CallbackHandler {
  156. private static int nextID = 0;
  157. private static Dictionary<string, CallbackInfo> mapper = new Dictionary<string, CallbackInfo>();
  158. private static string uuid() {
  159. nextID++;
  160. return nextID.ToString();
  161. }
  162. public static string addCallback(Delegate callback) {
  163. string uuid = CallbackHandler.uuid();
  164. if (callback != null) {
  165. CallbackInfo callbackInfo = new CallbackInfo();
  166. callbackInfo.callback = callback;
  167. callbackInfo.deadTime = Utility.GetTimestamp() + 10 * 1000;
  168. mapper.Add(uuid, callbackInfo);
  169. }
  170. return uuid;
  171. }
  172. public static void handleCallback(Data data) {
  173. if (mapper.Count > 10) {
  174. long now = Utility.GetTimestamp();
  175. LinkedList<string> outKeys = new LinkedList<string>();
  176. foreach (var item in mapper) {
  177. if (now >= item.Value.deadTime) {
  178. outKeys.AddLast(item.Key);
  179. }
  180. }
  181. foreach (var item in outKeys) {
  182. mapper.Remove(item);
  183. }
  184. }
  185. CallbackInfo callbackInfo;
  186. mapper.TryGetValue(data.uuid, out callbackInfo);
  187. if (callbackInfo != null) {
  188. mapper.Remove(data.uuid);
  189. object target = callbackInfo.callback.Target;
  190. System.Reflection.MethodInfo method = callbackInfo.callback.Method;
  191. Utility.formatArgsType(data.args, method.GetParameters());
  192. method.Invoke(target, data.args);
  193. }
  194. }
  195. }
  196. class Utility {
  197. public static long GetTimestamp() {
  198. TimeSpan ts = DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1);
  199. return (long)ts.TotalMilliseconds;
  200. }
  201. public static void formatArgsType(object[] args, System.Reflection.ParameterInfo[] parameters) {
  202. int i = 0;
  203. foreach (var param in parameters) {
  204. args[i] = Convert.ChangeType(args[i], param.ParameterType);
  205. i++;
  206. }
  207. }
  208. }
  209. class CallbackInfo {
  210. public Delegate callback;
  211. public long deadTime;
  212. }
  213. class Data {
  214. public string uuid;
  215. public int type;
  216. public string func;
  217. public object[] args;
  218. }
  219. enum DataType {
  220. EVENT,
  221. FUNCTION,
  222. METHOD
  223. }
  224. }