@huantv/vue
Version:
Hippy Vue for TV
205 lines (181 loc) • 6.62 kB
JavaScript
import Native from './native';
import {
getApp,
warn,
isFunction,
} from '../util/index.js';
const READY_STATE_CONNECTING = 0;
const READY_STATE_OPEN = 1;
const READY_STATE_CLOSING = 2;
const READY_STATE_CLOSED = 3;
const WEB_SOCKET_MODULE_NAME = 'websocket';
const WEB_SOCKET_NATIVE_EVENT = 'hippyWebsocketEvents';
let app;
/**
* The WebSocket API is an advanced technology that makes it possible to open a two-way
* interactive communication session between the user's browser and a server. With this API,
* you can send messages to a server and receive event-driven responses without having to
* poll the server for a reply.
*/
class WebSocket {
/**
* Returns a newly created WebSocket object.
*
* @param {string} url - The URL to which to connect; this should be the URL to which the
* WebSocket server will respond.
* @param {string | string[]} [protocols] - Either a single protocol string or an array
* of protocol strings. These strings are used to
* indicate sub-protocols, so that a single server
* can implement multiple WebSocket sub-protocols
* (for example, you might want one server to be able
* to handle different types of interactions depending
* on the specified protocol).
* If you don't specify a protocol string, an empty
* string is assumed.
* @param {Object} extrasHeaders - Http headers will append to connection.
*/
constructor(url, protocols, extrasHeaders) {
this.isMarkClose = false;
if (!app) {
app = getApp();
}
this.url = url;
this.readyState = READY_STATE_CONNECTING;
this.webSocketCallbacks = {};
this.onWebSocketEvent = this.onWebSocketEvent.bind(this);
const headers = {
...extrasHeaders,
};
console.log('websocket', '$on')
app.$on(WEB_SOCKET_NATIVE_EVENT, this.onWebSocketEvent);
if (!url || typeof url !== 'string') {
warn('Invalid WebSocket url')
return
}
if (Array.isArray(protocols) && protocols.length > 0) {
headers['Sec-WebSocket-Protocol'] = protocols.join(',');
} else if (typeof protocols === 'string') {
headers['Sec-WebSocket-Protocol'] = protocols;
}
const params = {
headers,
url,
};
Native.callNativeWithPromise(WEB_SOCKET_MODULE_NAME, 'connect', params).then((resp) => {
if (!resp || resp.code !== 0 || typeof resp.id !== 'number') {
warn('Fail to create websocket connection', resp);
return;
}
this.webSocketId = resp.id;
}, error => {
console.log('websocket', 'called connect error ' + error)
});
}
/**
* Closes the WebSocket connection or connection attempt, if any.
* If the connection is already CLOSED, this method does nothing.
*
* @param {number} [code] - A numeric value indicating the status code explaining
* why the connection is being closed. If this parameter
* is not specified, a default value of 1005 is assumed.
* See the list of status codes of CloseEvent for permitted values.
* @param {string} [reason] - A human-readable string explaining why the connection
* is closing. This string must be no longer than 123 bytes
* of UTF-8 text (not characters).
*/
close(code, reason) {
if (this.readyState !== READY_STATE_OPEN) {
this.isMarkClose = true;
console.log('websocket', 'mark close ' + this.webSocketId)
return;
}
console.log('websocket', 'to close')
this.readyState = READY_STATE_CLOSING;
Native.callNative(WEB_SOCKET_MODULE_NAME, 'close', {
id: this.webSocketId,
code,
reason,
});
}
/**
* Enqueues the specified data to be transmitted to the server over the WebSocket connection.
*
* @param {string} data - The data to send to the server. Hippy supports string type only.
*/
send(data) {
if (this.readyState !== READY_STATE_OPEN) {
warn('WebSocket is not connected');
return;
}
if (typeof data !== 'string') {
throw new TypeError(`Unsupported websocket data type: ${typeof data}`);
}
Native.callNative(WEB_SOCKET_MODULE_NAME, 'send', {
id: this.webSocketId,
data,
});
}
/**
* Set an EventHandler that is called when the WebSocket connection's readyState changes to OPEN;
*/
set onopen(callback) {
this.webSocketCallbacks.onOpen = callback;
}
/**
* Set an EventHandler that is called when the WebSocket connection's readyState
* changes to CLOSED.
*/
set onclose(callback) {
this.webSocketCallbacks.onClose = callback;
}
/**
* Set an EventHandler that is called when a message is received from the server.
*/
set onerror(callback) {
this.webSocketCallbacks.onError = callback;
}
/**
* Set an event handler property is a function which gets called when an error
* occurs on the WebSocket.
*/
set onmessage(callback) {
this.webSocketCallbacks.onMessage = callback;
}
/**
* WebSocket events handler from Native.
*
* @param {Object} param - Native response.
*/
onWebSocketEvent(param) {
if (typeof param !== 'object' || param.id !== this.webSocketId) {
return;
}
const eventType = param.type;
if (typeof eventType !== 'string') {
return;
}
if (eventType === 'onOpen') {
this.readyState = READY_STATE_OPEN;
if(this.isMarkClose) {
console.log('websocket', 'close with mark ' + this.webSocketId)
this.close()
}
} else if (eventType === 'onClose') {
this.readyState = READY_STATE_CLOSED;
// Vue.prototype.websocketOnTime--;
// console.log('websocket', ' before close - ' + Vue.prototype.websocketOnTime);
// if(Vue.prototype.websocketOnTime <= 0) {
// Vue.prototype.websocketOnTime = 0;
// app.$off(WEB_SOCKET_NATIVE_EVENT);
// console.log('websocket', '$off');
// }
app.$off(WEB_SOCKET_NATIVE_EVENT, this.onWebSocketEvent);
console.log('websocket', '$off');
}
const callback = this.webSocketCallbacks[eventType];
if (isFunction(callback)) {
callback(param.data);
}
}
}
export default WebSocket;