Source: websocket.js

  1. /**
  2. * Websocket Component<BR>
  3. * <BR><BR><img src=/tk/lib/components/w/img/ws.png width=30% style="border:1px lime dashed;padding:20px">
  4. * <BR><BR><a href="/tk/lib/components/w/html/ws.html">DEMO</a>
  5. */
  6. class WS extends HTMLElement {
  7. constructor() {
  8. wc.group("WS.constructor")
  9. super();
  10. wc.groupEnd();
  11. };
  12. /**
  13. * Set observable values here. When Changed, attributeChangedCallback is invoked
  14. * @observedAttributes
  15. */
  16. static get observedAttributes() {
  17. wc.group("WS.observedAttributes");
  18. this.observables = [];
  19. wc.groupEnd();
  20. return this.observables;
  21. };
  22. /**
  23. * Called when this is attached to DOM
  24. * @connectedCallback.
  25. */
  26. connectedCallback() {
  27. wc.group("WS.connectedCallback")
  28. // ADD A RANDOM ID IF NONE EXIST
  29. if (!this.id) {
  30. this.id = this.constructor.name.toLowerCase() + "-" + wc.uid();
  31. }
  32. // GET PROPERTIES AND INTERESTING ELEMENTS
  33. this._initialize();
  34. // ADD COMPONENT MARKTOP
  35. this.innerHTML = this._template()
  36. this.start();
  37. // ADD STATS AND OTHER FINAL STUFF
  38. this._finalize();
  39. ga('send', {'hitType': 'event','eventCategory': 'wc-connected','eventAction': 'connected','eventLabel': this.properties.cname, 'eventValue':JSON.stringify({'env':wcENV,'app':wcAPP,'url':wcURL})});
  40. wc.groupEnd();
  41. };
  42. /**
  43. * Initial Markup
  44. * @private
  45. * @_template
  46. */
  47. _template() {
  48. wc.group("WS.template");
  49. var temp = this.dom.content;
  50. wc.groupEnd();
  51. return temp;
  52. };
  53. /**
  54. * Called with .setAttribute(...) function call
  55. * @attributeChangedCallback
  56. */
  57. attributeChangedCallback(attr, oldval, newval) {
  58. wc.group("WS.attributeChangedCallback:", attr, oldval, newval);
  59. this.properties = this.properties || [];
  60. let obs = WS.observedAttributes;
  61. for (let i = 0; i < obs.length; i++) {
  62. if (newval) {
  63. this.properties[obs[i]] = newval;
  64. }
  65. }
  66. // YOUR CODE FOR CHANGES GO HERE (MAYBE NULL FIRST TIME THROUGH)
  67. try {
  68. switch(attr)
  69. {
  70. case "header":
  71. //this.querySelector("h1").innerHTML = newval;
  72. break;
  73. default:
  74. break;
  75. }
  76. } catch(e) {
  77. wc.warn(e.name + ' > ' + e.message);
  78. }
  79. wc.groupEnd();
  80. };
  81. /**
  82. * Stores DOM elements of interest for future use
  83. * @private
  84. * @_fetchElements
  85. */
  86. _fetchElements() {
  87. wc.group("WS._fetchElements");
  88. this.dom = this.dom || [];
  89. this.dom.content = this.innerHTML;
  90. wc.groupEnd();
  91. };
  92. /**
  93. * Component attributes are _fetched and defaults are set if undefined
  94. * @private
  95. * @_fetchAttributes
  96. */
  97. _fetchAttributes() {
  98. wc.group("WS._fetchAttributes");
  99. this.properties = {
  100. uparam : "",
  101. cname : "ws",
  102. author : "Mel M. Heravi, Ph.D.",
  103. version : "1.0"
  104. };
  105. // SAVE WIDGET SPECIFIC PROPERTIES
  106. this.propertiesW = [];
  107. // SAVE ALL OTHER PROPERTIES
  108. let attrs = wc.getAttributes(this)
  109. for (var key in attrs) {
  110. let attr = this.getAttribute(key) || this.properties.key;
  111. this.properties[key] = this.getAttribute(key);
  112. this.propertiesW[key] = this.getAttribute(key);
  113. wc.log(key + ": " + attrs[key]);
  114. }
  115. // SET ALL INITIAL ATTRIBUTES
  116. for (var key in this.properties) {
  117. switch(key)
  118. {
  119. case "header":
  120. break;
  121. default:
  122. break;
  123. }
  124. }
  125. wc.log("ATTRIBUTES: ", this.properties);
  126. wc.groupEnd();
  127. };
  128. /**
  129. * Initialize component
  130. * @private
  131. * @_initialize
  132. */
  133. _initialize() {
  134. wc.group("WS._initialize:", this.id);
  135. // FETCH ALL INTERESTING ELEMENTS
  136. this._fetchElements();
  137. // FETCH ALL ATTRIBUTES
  138. this._fetchAttributes();
  139. wc.groupEnd();
  140. };
  141. /**
  142. * Save data for analytics and final wrap up
  143. * @private
  144. * @_finalize
  145. */
  146. _finalize() {
  147. wc.group("WS._finalize:", this.id);
  148. this.classList.add("wc");
  149. // ADD ANALYTICS HERE
  150. wc.setStats(this, this.properties.cname, this.properties.version);
  151. // SHOW IT NOW (NO FLICKERS)
  152. this.style.visibility = "visible";
  153. wc.groupEnd();
  154. };
  155. /**
  156. * Invoked When component is removed. Usually with a .remove() function call
  157. * @disconnectedCallback
  158. */
  159. disconnectedCallback() {
  160. wc.group("WS.disconnectedCallback")
  161. ga('send', {'hitType': 'event','eventCategory': 'wc-disconnected','eventAction': 'disconnected','eventLabel': this.properties.cname, 'eventValue':JSON.stringify({'env':wcENV,'app':wcAPP,'url':wcURL})});
  162. wc.groupEnd();
  163. };
  164. /**
  165. * Destroy the instance object and artifacts
  166. * @destroy
  167. */
  168. destroy() {
  169. wc.group("WS.destroy");
  170. // FREE ALL MEMORY
  171. // you should delete all created objects here
  172. // FREE POINTER
  173. delete this;
  174. // REMOVE ITEM FROM DOM
  175. this.parentNode.removeChild(this);
  176. ga('send', {'hitType': 'event','eventCategory': 'wc-destroyed','eventAction': 'distroy','eventLabel': this.properties.cname, 'eventValue':JSON.stringify({'env':wcENV,'app':wcAPP,'url':wcURL})});
  177. wc.groupEnd();
  178. };
  179. /**
  180. * Start the instance object and artifacts
  181. * @start
  182. */
  183. start() {
  184. wc.group("WS.start");
  185. let self = this;
  186. window.ws = new WebSocket(this.properties.url);
  187. ////////////////////////////////////////////////////////////
  188. ////
  189. ////////////////////////////////////////////////////////////
  190. ws.onopen = () => {
  191. wc.group("ws.onopen");
  192. let time = new Date().getTime();
  193. ws.send("ping")
  194. wc.publish("wc-websocket", {
  195. time: new Date().getTime(),
  196. type: "info",
  197. msg: "CONNECTED",
  198. id: self.id
  199. });
  200. wc.groupEnd();
  201. }
  202. ////////////////////////////////////////////////////////////
  203. ////
  204. ////////////////////////////////////////////////////////////
  205. ws.onerror = (error) => {
  206. wc.group("ws.onerror");
  207. var msg = "UNKNOWN ERROR..."
  208. if (error.target.readyState == 3) {
  209. msg = `DISCONNECTED. will try again in ${this.properties.reconnect/1000} seconds...`
  210. }
  211. wc.error("C ERROR:", error.target.readyState, msg)
  212. wc.publish("wc-websocket", {
  213. time: new Date().getTime(),
  214. type: "error",
  215. msg: msg,
  216. id: self.id
  217. });
  218. wc.groupEnd();
  219. }
  220. ////////////////////////////////////////////////////////////
  221. ////
  222. ////////////////////////////////////////////////////////////
  223. ws.onmessage = (e) => {
  224. wc.group("ws.onmessage");
  225. let msg = e.data;
  226. let x = msg.split(" ");
  227. switch(x[0])
  228. {
  229. case "pong":
  230. wc.log(`C < ${msg}`);
  231. wc.publish("wc-websocket", {
  232. time: new Date().getTime(),
  233. type: "msg",
  234. msg: msg,
  235. id: self.id
  236. });
  237. break;
  238. default:
  239. let error = `ERROR: DO NOT UNDERSTAND COMMAND: ${msg}`;
  240. wc.error(error);
  241. wc.publish("wc-websocket", {
  242. time: new Date().getTime(),
  243. type: "error",
  244. msg: error,
  245. id: self.id
  246. });
  247. break;
  248. }
  249. // CONFIRM
  250. ws.send("ready");
  251. wc.groupEnd();
  252. }
  253. ////////////////////////////////////////////////////////////
  254. //// RESTART IF DISCONNECTED
  255. ////////////////////////////////////////////////////////////
  256. ws.onclose = function(e) {
  257. wc.group("ws.onclose");
  258. wc.log("DISCONNECTED!");
  259. wc.publish("wc-websocket", {
  260. time: new Date().getTime(),
  261. type: "info",
  262. msg: "CONNECTION CLOSED",
  263. id: self.id
  264. });
  265. setTimeout(() => {
  266. self.start()
  267. }, self.properties.reconnect);
  268. wc.groupEnd();
  269. };
  270. wc.groupEnd();
  271. }
  272. }
  273. window.customElements.define('wc-websocket', WS);