diff --git a/src/logcat.js b/src/logcat.js
index 0d106e2..cfb1009 100644
--- a/src/logcat.js
+++ b/src/logcat.js
@@ -2,6 +2,7 @@
// vscode stuff
const { EventEmitter, Uri } = require('vscode');
// node and external modules
+const fs = require('fs');
const os = require('os');
const path = require('path');
const WebSocketServer = require('ws').Server;
@@ -26,6 +27,7 @@ class LogcatContent {
this._notifying = 0;
this._refreshRate = 200; // ms
this._state = '';
+ this._htmltemplate = '';
this._adbclient = new ADBClient(uri.query);
this._initwait = new Promise((resolve, reject) => {
this._state = 'connecting';
@@ -44,11 +46,12 @@ class LogcatContent {
reject(e);
})
});
+ LogcatContent.byLogcatID[this._logcatid] = this;
}
get content() {
if (this._initwait) return this._initwait;
if (this._state !== 'disconnected')
- return this.htmlBootstrap(true, '');
+ return this.htmlBootstrap({connected:true, status:'',oldlogs:''});
// if we're in the disconnected state, and this.content is called, it means the user has requested
// this logcat again - check if the device has reconnected
return this._initwait = new Promise((resolve, reject) => {
@@ -71,94 +74,65 @@ class LogcatContent {
this._oldhtmllogs = this._prevlogs._oldhtmllogs;
this._prevlogs = null;
this._initwait = null;
- var cached_content = this.htmlBootstrap(false, 'Device disconnected');
+ var cached_content = this.htmlBootstrap({connected:false, status:'Device disconnected',oldlogs: this._oldhtmllogs.join(os.EOL)});
resolve(cached_content);
})
});
}
- sendDisconnectMsg() {
+ sendClientMessage(msg) {
var clients = LogcatContent._wss.clients.filter(client => client._logcatid === this._logcatid);
- clients.forEach(client => client.send(':disconnect'));
+ clients.forEach(client => client.send(msg+'\n')); // include a newline to try and persuade a buffer write
+ }
+ sendDisconnectMsg() {
+ this.sendClientMessage(':disconnect');
+ }
+ onClientConnect(client) {
+ if (this._oldhtmllogs.length) {
+ var lines = '
' + this._oldhtmllogs.join(os.EOL) + '
';
+ client.send(lines);
+ }
+ // if the window is tabbed away and then returned to, vscode assumes the content
+ // has not changed from the original bootstrap. So it proceeds to load the html page (with no data),
+ // causing a connection to the WSServer as if the connection is still valid (which it was, originally).
+ // If it's not, tell the client (again) that the device has disconnected
+ if (this._state === 'disconnected')
+ this.sendDisconnectMsg();
+ }
+ onClientMessage(client, message) {
+ if (message === 'cmd:clear_logcat') {
+ if (this._state !== 'connected') return;
+ new ADBClient(this._adbclient.deviceid).shell_cmd({command:'logcat -c'})
+ .then(() => {
+ // clear everything and tell the clients
+ this._logs = []; this._htmllogs = []; this._oldhtmllogs = [];
+ this.sendClientMessage(':logcat_cleared');
+ })
+ .fail(e => {
+ D('Clear logcat command failed: ' + e.message);
+ })
+ }
}
updateLogs() {
// no point in formatting the data if there are no connected clients
var clients = LogcatContent._wss.clients.filter(client => client._logcatid === this._logcatid);
if (clients.length) {
- var lines = '' + this._htmllogs.join('') + '
';
+ var lines = '' + this._htmllogs.join(os.EOL) + '
';
clients.forEach(client => client.send(lines));
}
// once we've updated all the clients, discard the info
- this._oldhtmllogs = this._htmllogs.concat(this._oldhtmllogs).slice(0, 5000);
+ this._oldhtmllogs = this._htmllogs.concat(this._oldhtmllogs).slice(0, 10000);
this._htmllogs = [], this._logs = [];
}
- htmlBootstrap(connected, statusmsg) {
- return `
-
-
-
- ${statusmsg}
- ${this._oldhtmllogs.join(os.EOL)}
-
-
- `;
+ htmlBootstrap(vars) {
+ if (!this._htmltemplate)
+ this._htmltemplate = fs.readFileSync(path.join(__dirname,'res/logcat.html'), 'utf8');
+ vars = Object.assign({
+ logcatid: this._logcatid,
+ wssport: LogcatContent._wssport,
+ }, vars);
+ // simple value replacement using !{name} as the placeholder
+ var html = this._htmltemplate.replace(/!\{(.*?)\}/g, (match,expr) => ''+(vars[expr.trim()]||''));
+ return html;
}
renotify() {
if (++this._notifying > 1) return;
@@ -172,16 +146,17 @@ class LogcatContent {
}
onLogcatContent(e) {
if (e.logs.length) {
- var mrfirst = e.logs.slice().reverse();
- this._logs = mrfirst.concat(this._logs);
- mrfirst.forEach(log => {
+ var mrlast = e.logs.slice();
+ this._logs = this._logs.concat(mrlast);
+ mrlast.forEach(log => {
if (!(log = log.trim())) return;
// replace html-interpreted chars
var m = log.match(/^\d\d-\d\d\s+?\d\d:\d\d:\d\d\.\d+?\s+?(.)/);
var style = (m && m[1]) || '';
log = log.replace(/[&"'<>]/g, c => ({ '&': '&', '"': '"', "'": ''', '<': '<', '>': '>' }[c]));
- this._htmllogs.unshift(`${log}
`);
- })
+ this._htmllogs.unshift(`${log}
`);
+
+ });
this.renotify();
}
}
@@ -192,6 +167,9 @@ class LogcatContent {
}
}
+// hashmap of all LogcatContent instances, keyed on device id
+LogcatContent.byLogcatID = {};
+
LogcatContent.initWebSocketServer = function () {
if (LogcatContent._wssdone) {
// already inited
@@ -210,13 +188,18 @@ LogcatContent.initWebSocketServer = function () {
this.wss.on('connection', client => {
// the client uses the url path to signify which logcat data it wants
client._logcatid = client.upgradeReq.url.match(/^\/?(.*)$/)[1];
- // we're not really interested in anything the client sends
- /*client.on('message', message => {
- console.log('ws received: %s', message);
- });
- client.on('close', e => {
- console.log('ws close');
+ var lc = LogcatContent.byLogcatID[client._logcatid];
+ if (lc) lc.onClientConnect(client);
+ else client.close();
+ client.on('message', function(message) {
+ var lc = LogcatContent.byLogcatID[this._logcatid];
+ if (lc) lc.onClientMessage(this, message);
+ }.bind(client));
+ /*client.on('close', e => {
+ console.log('client close');
});*/
+ // try and make sure we don't delay writes
+ client._socket && typeof(client._socket.setNoDelay)==='function' && client._socket.setNoDelay(true);
});
this.wss = null;
LogcatContent._wssdone.resolveWith(LogcatContent, []);
diff --git a/src/res/logcat.html b/src/res/logcat.html
new file mode 100644
index 0000000..81bb7a6
--- /dev/null
+++ b/src/res/logcat.html
@@ -0,0 +1,186 @@
+
+
+
+
+
+
+
+
+
+
+
!{status}
+
!{oldlogs}
+
+
+
+
+