mirror of https://github.com/tp4a/teleport
修正:某些ssh录像无法回放(无法使用json编码,使用base64打包解决);
修正:ssh录像回放调速功能不正常; 改进:ssh录像回放增加“跳过无操作时间”选项。pull/40/merge
parent
17ff40746e
commit
a40af30a15
|
@ -5,6 +5,7 @@ import json
|
|||
import os
|
||||
import platform
|
||||
|
||||
from eom_common.eomcore.logger import log
|
||||
from eom_app.app.configs import app_cfg
|
||||
from eom_app.module import record
|
||||
from eom_app.module import user
|
||||
|
@ -163,6 +164,29 @@ class RecordGetInfo(TPBaseAdminAuthJsonHandler):
|
|||
return self.write_json(0, data=data)
|
||||
|
||||
|
||||
# class RecordGetInfo(TPBaseAdminAuthHandler):
|
||||
# def post(self):
|
||||
# args = self.get_argument('args', None)
|
||||
# if args is not None:
|
||||
# args = json.loads(args)
|
||||
# else:
|
||||
# return self.write(-1)
|
||||
#
|
||||
# record_id = args['id']
|
||||
# file_id = args['file_id']
|
||||
#
|
||||
# record_path = os.path.join(app_cfg().core.replay_path, 'ssh', '{:06d}'.format(int(record_id)))
|
||||
# file_info = os.path.join(record_path, 'tp-ssh.{:03d}'.format(int(file_id)))
|
||||
# try:
|
||||
# with open(file_info, 'rb') as f:
|
||||
# data = f.read()
|
||||
# log.v('data size:', len(data), '\n')
|
||||
# self.write(data)
|
||||
# except:
|
||||
# log.e('\n')
|
||||
# self.write(-1)
|
||||
|
||||
|
||||
class DeleteLog(TPBaseAdminAuthJsonHandler):
|
||||
# TODO: 用户可能会批量删除大量录像文件,因此io操作可能会比较耗时,这里应该改为异步方式。
|
||||
def post(self):
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import os
|
||||
import shutil
|
||||
import struct
|
||||
import base64
|
||||
|
||||
from eom_app.app.configs import app_cfg
|
||||
from eom_app.app.db import get_db
|
||||
|
@ -113,9 +114,13 @@ def read_record_info(record_id, file_id):
|
|||
temp['w'] = w
|
||||
temp['h'] = h
|
||||
elif action == 2:
|
||||
_data = _data.decode()
|
||||
# this is ssh data.
|
||||
temp['d'] = _data
|
||||
try:
|
||||
_d = _data.decode()
|
||||
temp['d'] = _d
|
||||
except:
|
||||
_data = base64.b64encode(_data)
|
||||
temp['a'] = 3
|
||||
temp['d'] = _data.decode()
|
||||
else:
|
||||
return None
|
||||
|
||||
|
|
|
@ -115,6 +115,7 @@ class Logger:
|
|||
self._log_datetime = True # 是否记录日志时间
|
||||
self._file_handle = None # 日志文件的句柄,为None时表示不记录到文件
|
||||
|
||||
self._log_console = self._log_pass
|
||||
self._win_color = None
|
||||
|
||||
self._set_console(True)
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
/**
|
||||
* Implements the attach method, that attaches the terminal to a WebSocket stream.
|
||||
* @module xterm/addons/attach/attach
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
(function (attach) {
|
||||
if (typeof exports === 'object' && typeof module === 'object') {
|
||||
/*
|
||||
* CommonJS environment
|
||||
*/
|
||||
module.exports = attach(require('../../xterm'));
|
||||
} else if (typeof define == 'function') {
|
||||
/*
|
||||
* Require.js is available
|
||||
*/
|
||||
define(['../../xterm'], attach);
|
||||
} else {
|
||||
/*
|
||||
* Plain browser environment
|
||||
*/
|
||||
attach(window.Terminal);
|
||||
}
|
||||
})(function (Xterm) {
|
||||
'use strict';
|
||||
|
||||
var exports = {};
|
||||
|
||||
/**
|
||||
* Attaches the given terminal to the given socket.
|
||||
*
|
||||
* @param {Xterm} term - The terminal to be attached to the given socket.
|
||||
* @param {WebSocket} socket - The socket to attach the current terminal.
|
||||
* @param {boolean} bidirectional - Whether the terminal should send data
|
||||
* to the socket as well.
|
||||
* @param {boolean} buffered - Whether the rendering of incoming data
|
||||
* should happen instantly or at a maximum
|
||||
* frequency of 1 rendering per 10ms.
|
||||
*/
|
||||
exports.attach = function (term, socket, bidirectional, buffered) {
|
||||
bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional;
|
||||
term.socket = socket;
|
||||
|
||||
term._flushBuffer = function () {
|
||||
term.write(term._attachSocketBuffer);
|
||||
term._attachSocketBuffer = null;
|
||||
clearTimeout(term._attachSocketBufferTimer);
|
||||
term._attachSocketBufferTimer = null;
|
||||
};
|
||||
|
||||
term._pushToBuffer = function (data) {
|
||||
if (term._attachSocketBuffer) {
|
||||
term._attachSocketBuffer += data;
|
||||
} else {
|
||||
term._attachSocketBuffer = data;
|
||||
setTimeout(term._flushBuffer, 10);
|
||||
}
|
||||
};
|
||||
|
||||
term._getMessage = function (ev) {
|
||||
if (buffered) {
|
||||
term._pushToBuffer(ev.data);
|
||||
} else {
|
||||
term.write(ev.data);
|
||||
}
|
||||
};
|
||||
|
||||
term._sendData = function (data) {
|
||||
socket.send(data);
|
||||
};
|
||||
|
||||
socket.addEventListener('message', term._getMessage);
|
||||
|
||||
if (bidirectional) {
|
||||
term.on('data', term._sendData);
|
||||
}
|
||||
|
||||
socket.addEventListener('close', term.detach.bind(term, socket));
|
||||
socket.addEventListener('error', term.detach.bind(term, socket));
|
||||
};
|
||||
|
||||
/**
|
||||
* Detaches the given terminal from the given socket
|
||||
*
|
||||
* @param {Xterm} term - The terminal to be detached from the given socket.
|
||||
* @param {WebSocket} socket - The socket from which to detach the current
|
||||
* terminal.
|
||||
*/
|
||||
exports.detach = function (term, socket) {
|
||||
term.off('data', term._sendData);
|
||||
|
||||
socket = (typeof socket == 'undefined') ? term.socket : socket;
|
||||
|
||||
if (socket) {
|
||||
socket.removeEventListener('message', term._getMessage);
|
||||
}
|
||||
|
||||
delete term.socket;
|
||||
};
|
||||
|
||||
/**
|
||||
* Attaches the current terminal to the given socket
|
||||
*
|
||||
* @param {WebSocket} socket - The socket to attach the current terminal.
|
||||
* @param {boolean} bidirectional - Whether the terminal should send data
|
||||
* to the socket as well.
|
||||
* @param {boolean} buffered - Whether the rendering of incoming data
|
||||
* should happen instantly or at a maximum
|
||||
* frequency of 1 rendering per 10ms.
|
||||
*/
|
||||
Xterm.prototype.attach = function (socket, bidirectional, buffered) {
|
||||
return exports.attach(this, socket, bidirectional, buffered);
|
||||
};
|
||||
|
||||
/**
|
||||
* Detaches the current terminal from the given socket.
|
||||
*
|
||||
* @param {WebSocket} socket - The socket from which to detach the current
|
||||
* terminal.
|
||||
*/
|
||||
Xterm.prototype.detach = function (socket) {
|
||||
return exports.detach(this, socket);
|
||||
};
|
||||
|
||||
return exports;
|
||||
});
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
* Fit terminal columns and rows to the dimensions of its DOM element.
|
||||
*
|
||||
* ## Approach
|
||||
* - Rows: Truncate the division of the terminal parent element height by the terminal row height.
|
||||
*
|
||||
* - Columns: Truncate the division of the terminal parent element width by the terminal character
|
||||
* width (apply display: inline at the terminal row and truncate its width with the current
|
||||
* number of columns).
|
||||
* @module xterm/addons/fit/fit
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
(function (fit) {
|
||||
if (typeof exports === 'object' && typeof module === 'object') {
|
||||
/*
|
||||
* CommonJS environment
|
||||
*/
|
||||
module.exports = fit(require('../../xterm'));
|
||||
} else if (typeof define == 'function') {
|
||||
/*
|
||||
* Require.js is available
|
||||
*/
|
||||
define(['../../xterm'], fit);
|
||||
} else {
|
||||
/*
|
||||
* Plain browser environment
|
||||
*/
|
||||
fit(window.Terminal);
|
||||
}
|
||||
})(function (Xterm) {
|
||||
var exports = {};
|
||||
|
||||
exports.proposeGeometry = function (term) {
|
||||
if (!term.element.parentElement) {
|
||||
return null;
|
||||
}
|
||||
var parentElementStyle = window.getComputedStyle(term.element.parentElement),
|
||||
parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height')),
|
||||
parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')) - 17),
|
||||
elementStyle = window.getComputedStyle(term.element),
|
||||
elementPaddingVer = parseInt(elementStyle.getPropertyValue('padding-top')) + parseInt(elementStyle.getPropertyValue('padding-bottom')),
|
||||
elementPaddingHor = parseInt(elementStyle.getPropertyValue('padding-right')) + parseInt(elementStyle.getPropertyValue('padding-left')),
|
||||
availableHeight = parentElementHeight - elementPaddingVer,
|
||||
availableWidth = parentElementWidth - elementPaddingHor,
|
||||
container = term.rowContainer,
|
||||
subjectRow = term.rowContainer.firstElementChild,
|
||||
contentBuffer = subjectRow.innerHTML,
|
||||
characterHeight,
|
||||
rows,
|
||||
characterWidth,
|
||||
cols,
|
||||
geometry;
|
||||
|
||||
subjectRow.style.display = 'inline';
|
||||
subjectRow.innerHTML = 'W'; // Common character for measuring width, although on monospace
|
||||
characterWidth = subjectRow.getBoundingClientRect().width;
|
||||
subjectRow.style.display = ''; // Revert style before calculating height, since they differ.
|
||||
characterHeight = subjectRow.getBoundingClientRect().height;
|
||||
subjectRow.innerHTML = contentBuffer;
|
||||
|
||||
rows = parseInt(availableHeight / characterHeight);
|
||||
cols = parseInt(availableWidth / characterWidth);
|
||||
|
||||
geometry = {cols: cols, rows: rows};
|
||||
return geometry;
|
||||
};
|
||||
|
||||
exports.fit = function (term) {
|
||||
var geometry = exports.proposeGeometry(term);
|
||||
|
||||
if (geometry) {
|
||||
term.resize(geometry.cols, geometry.rows);
|
||||
}
|
||||
};
|
||||
|
||||
Xterm.prototype.proposeGeometry = function () {
|
||||
return exports.proposeGeometry(this);
|
||||
};
|
||||
|
||||
Xterm.prototype.fit = function () {
|
||||
return exports.fit(this);
|
||||
};
|
||||
|
||||
return exports;
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
.xterm.fullscreen {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: auto;
|
||||
height: auto;
|
||||
z-index: 255;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* Fullscreen addon for xterm.js
|
||||
* @module xterm/addons/fullscreen/fullscreen
|
||||
* @license MIT
|
||||
*/
|
||||
(function (fullscreen) {
|
||||
if (typeof exports === 'object' && typeof module === 'object') {
|
||||
/*
|
||||
* CommonJS environment
|
||||
*/
|
||||
module.exports = fullscreen(require('../../xterm'));
|
||||
} else if (typeof define == 'function') {
|
||||
/*
|
||||
* Require.js is available
|
||||
*/
|
||||
define(['../../xterm'], fullscreen);
|
||||
} else {
|
||||
/*
|
||||
* Plain browser environment
|
||||
*/
|
||||
fullscreen(window.Terminal);
|
||||
}
|
||||
})(function (Xterm) {
|
||||
var exports = {};
|
||||
|
||||
/**
|
||||
* Toggle the given terminal's fullscreen mode.
|
||||
* @param {Xterm} term - The terminal to toggle full screen mode
|
||||
* @param {boolean} fullscreen - Toggle fullscreen on (true) or off (false)
|
||||
*/
|
||||
exports.toggleFullScreen = function (term, fullscreen) {
|
||||
var fn;
|
||||
|
||||
if (typeof fullscreen == 'undefined') {
|
||||
fn = (term.element.classList.contains('fullscreen')) ? 'remove' : 'add';
|
||||
} else if (!fullscreen) {
|
||||
fn = 'remove';
|
||||
} else {
|
||||
fn = 'add';
|
||||
}
|
||||
|
||||
term.element.classList[fn]('fullscreen');
|
||||
};
|
||||
|
||||
Xterm.prototype.toggleFullscreen = function (fullscreen) {
|
||||
exports.toggleFullScreen(this, fullscreen);
|
||||
};
|
||||
|
||||
return exports;
|
||||
});
|
|
@ -0,0 +1,207 @@
|
|||
/**
|
||||
* Methods for turning URL subscrings in the terminal's content into links (`a` DOM elements).
|
||||
* @module xterm/addons/linkify/linkify
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
(function (linkify) {
|
||||
if (typeof exports === 'object' && typeof module === 'object') {
|
||||
/*
|
||||
* CommonJS environment
|
||||
*/
|
||||
module.exports = linkify(require('../../xterm'));
|
||||
} else if (typeof define == 'function') {
|
||||
/*
|
||||
* Require.js is available
|
||||
*/
|
||||
define(['../../xterm'], linkify);
|
||||
} else {
|
||||
/*
|
||||
* Plain browser environment
|
||||
*/
|
||||
linkify(window.Terminal);
|
||||
}
|
||||
})(function (Xterm) {
|
||||
'use strict';
|
||||
|
||||
var exports = {},
|
||||
protocolClause = '(https?:\\/\\/)',
|
||||
domainCharacterSet = '[\\da-z\\.-]+',
|
||||
negatedDomainCharacterSet = '[^\\da-z\\.-]+',
|
||||
domainBodyClause = '(' + domainCharacterSet + ')',
|
||||
tldClause = '([a-z\\.]{2,6})',
|
||||
ipClause = '((\\d{1,3}\\.){3}\\d{1,3})',
|
||||
portClause = '(:\\d{1,5})',
|
||||
hostClause = '((' + domainBodyClause + '\\.' + tldClause + ')|' + ipClause + ')' + portClause + '?',
|
||||
pathClause = '(\\/[\\/\\w\\.-]*)*',
|
||||
negatedPathCharacterSet = '[^\\/\\w\\.-]+',
|
||||
bodyClause = hostClause + pathClause,
|
||||
start = '(?:^|' + negatedDomainCharacterSet + ')(',
|
||||
end = ')($|' + negatedPathCharacterSet + ')',
|
||||
lenientUrlClause = start + protocolClause + '?' + bodyClause + end,
|
||||
strictUrlClause = start + protocolClause + bodyClause + end,
|
||||
lenientUrlRegex = new RegExp(lenientUrlClause),
|
||||
strictUrlRegex = new RegExp(strictUrlClause);
|
||||
|
||||
/**
|
||||
* Converts all valid URLs found in the given terminal line into
|
||||
* hyperlinks. The terminal line can be either the HTML element itself
|
||||
* or the index of the termina line in the children of the terminal
|
||||
* rows container.
|
||||
*
|
||||
* @param {Xterm} terminal - The terminal that owns the given line.
|
||||
* @param {number|HTMLDivElement} line - The terminal line that should get
|
||||
* "linkified".
|
||||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is
|
||||
* false, the regex requires a protocol clause. Defaults to true.
|
||||
* @param {string} target - Sets target="" attribute with value provided to links.
|
||||
* Default doesn't set target attribute
|
||||
* @emits linkify
|
||||
* @emits linkify:line
|
||||
*/
|
||||
exports.linkifyTerminalLine = function (terminal, line, lenient, target) {
|
||||
if (typeof line == 'number') {
|
||||
line = terminal.rowContainer.children[line];
|
||||
} else if (! (line instanceof HTMLDivElement)) {
|
||||
var message = 'The "line" argument should be either a number';
|
||||
message += ' or an HTMLDivElement';
|
||||
|
||||
throw new TypeError(message);
|
||||
}
|
||||
|
||||
if (typeof target === 'undefined') {
|
||||
target = '';
|
||||
} else {
|
||||
target = 'target="' + target + '"';
|
||||
}
|
||||
|
||||
var buffer = document.createElement('span'),
|
||||
nodes = line.childNodes;
|
||||
|
||||
for (var j=0; j<nodes.length; j++) {
|
||||
var node = nodes[j],
|
||||
match;
|
||||
|
||||
/**
|
||||
* Since we cannot access the TextNode's HTML representation
|
||||
* from the instance itself, we assign its data as textContent
|
||||
* to a dummy buffer span, in order to retrieve the TextNode's
|
||||
* HTML representation from the buffer's innerHTML.
|
||||
*/
|
||||
buffer.textContent = node.data;
|
||||
|
||||
var nodeHTML = buffer.innerHTML;
|
||||
|
||||
/**
|
||||
* Apply function only on TextNodes
|
||||
*/
|
||||
if (node.nodeType != node.TEXT_NODE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var url = exports.findLinkMatch(node.data, lenient);
|
||||
|
||||
if (!url) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var startsWithProtocol = new RegExp('^' + protocolClause),
|
||||
urlHasProtocol = url.match(startsWithProtocol),
|
||||
href = (urlHasProtocol) ? url : 'http://' + url,
|
||||
link = '<a href="' + href + '" ' + target + '>' + url + '</a>',
|
||||
newHTML = nodeHTML.replace(url, link);
|
||||
|
||||
line.innerHTML = line.innerHTML.replace(nodeHTML, newHTML);
|
||||
}
|
||||
|
||||
/**
|
||||
* This event gets emitted when conversion of all URL susbtrings
|
||||
* to HTML anchor elements (links) has finished, for a specific
|
||||
* line of the current Xterm instance.
|
||||
*
|
||||
* @event linkify:line
|
||||
*/
|
||||
terminal.emit('linkify:line', line);
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds a link within a block of text.
|
||||
*
|
||||
* @param {string} text - The text to search .
|
||||
* @param {boolean} lenient - Whether to use the lenient search.
|
||||
* @return {string} A URL.
|
||||
*/
|
||||
exports.findLinkMatch = function (text, lenient) {
|
||||
var match = text.match(lenient ? lenientUrlRegex : strictUrlRegex);
|
||||
if (!match || match.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return match[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts all valid URLs found in the terminal view into hyperlinks.
|
||||
*
|
||||
* @param {Xterm} terminal - The terminal that should get "linkified".
|
||||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is
|
||||
* false, the regex requires a protocol clause. Defaults to true.
|
||||
* @param {string} target - Sets target="" attribute with value provided to links.
|
||||
* Default doesn't set target attribute
|
||||
* @emits linkify
|
||||
* @emits linkify:line
|
||||
*/
|
||||
exports.linkify = function (terminal, lenient, target) {
|
||||
var rows = terminal.rowContainer.children;
|
||||
|
||||
lenient = (typeof lenient == "boolean") ? lenient : true;
|
||||
for (var i=0; i<rows.length; i++) {
|
||||
var line = rows[i];
|
||||
|
||||
exports.linkifyTerminalLine(terminal, line, lenient, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* This event gets emitted when conversion of all URL substrings to
|
||||
* HTML anchor elements (links) has finished for the current Xterm
|
||||
* instance's view.
|
||||
*
|
||||
* @event linkify
|
||||
*/
|
||||
terminal.emit('linkify');
|
||||
};
|
||||
|
||||
/**
|
||||
* Extend Xterm prototype.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Converts all valid URLs found in the current terminal linte into
|
||||
* hyperlinks.
|
||||
*
|
||||
* @memberof Xterm
|
||||
* @param {number|HTMLDivElement} line - The terminal line that should get
|
||||
* "linkified".
|
||||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is
|
||||
* false, the regex requires a protocol clause. Defaults to true.
|
||||
* @param {string} target - Sets target="" attribute with value provided to links.
|
||||
* Default doesn't set target attribute
|
||||
*/
|
||||
Xterm.prototype.linkifyTerminalLine = function (line, lenient, target) {
|
||||
return exports.linkifyTerminalLine(this, line, lenient, target);
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts all valid URLs found in the current terminal into hyperlinks.
|
||||
*
|
||||
* @memberof Xterm
|
||||
* @param {boolean} lenient - The regex type that will be used to identify links. If lenient is
|
||||
* false, the regex requires a protocol clause. Defaults to true.
|
||||
* @param {string} target - Sets target="" attribute with value provided to links.
|
||||
* Default doesn't set target attribute
|
||||
*/
|
||||
Xterm.prototype.linkify = function (lenient, target) {
|
||||
return exports.linkify(this, lenient, target);
|
||||
};
|
||||
|
||||
return exports;
|
||||
});
|
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
* This module provides methods for attaching a terminal to a terminado WebSocket stream.
|
||||
*
|
||||
* @module xterm/addons/terminado/terminado
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
(function (attach) {
|
||||
if (typeof exports === 'object' && typeof module === 'object') {
|
||||
/*
|
||||
* CommonJS environment
|
||||
*/
|
||||
module.exports = attach(require('../../xterm'));
|
||||
} else if (typeof define == 'function') {
|
||||
/*
|
||||
* Require.js is available
|
||||
*/
|
||||
define(['../../xterm'], attach);
|
||||
} else {
|
||||
/*
|
||||
* Plain browser environment
|
||||
*/
|
||||
attach(window.Terminal);
|
||||
}
|
||||
})(function (Xterm) {
|
||||
'use strict';
|
||||
|
||||
var exports = {};
|
||||
|
||||
/**
|
||||
* Attaches the given terminal to the given socket.
|
||||
*
|
||||
* @param {Xterm} term - The terminal to be attached to the given socket.
|
||||
* @param {WebSocket} socket - The socket to attach the current terminal.
|
||||
* @param {boolean} bidirectional - Whether the terminal should send data
|
||||
* to the socket as well.
|
||||
* @param {boolean} buffered - Whether the rendering of incoming data
|
||||
* should happen instantly or at a maximum
|
||||
* frequency of 1 rendering per 10ms.
|
||||
*/
|
||||
exports.terminadoAttach = function (term, socket, bidirectional, buffered) {
|
||||
bidirectional = (typeof bidirectional == 'undefined') ? true : bidirectional;
|
||||
term.socket = socket;
|
||||
|
||||
term._flushBuffer = function () {
|
||||
term.write(term._attachSocketBuffer);
|
||||
term._attachSocketBuffer = null;
|
||||
clearTimeout(term._attachSocketBufferTimer);
|
||||
term._attachSocketBufferTimer = null;
|
||||
};
|
||||
|
||||
term._pushToBuffer = function (data) {
|
||||
if (term._attachSocketBuffer) {
|
||||
term._attachSocketBuffer += data;
|
||||
} else {
|
||||
term._attachSocketBuffer = data;
|
||||
setTimeout(term._flushBuffer, 10);
|
||||
}
|
||||
};
|
||||
|
||||
term._getMessage = function (ev) {
|
||||
var data = JSON.parse(ev.data)
|
||||
if( data[0] == "stdout" ) {
|
||||
if (buffered) {
|
||||
term._pushToBuffer(data[1]);
|
||||
} else {
|
||||
term.write(data[1]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
term._sendData = function (data) {
|
||||
socket.send(JSON.stringify(['stdin', data]));
|
||||
};
|
||||
|
||||
term._setSize = function (size) {
|
||||
socket.send(JSON.stringify(['set_size', size.rows, size.cols]));
|
||||
};
|
||||
|
||||
socket.addEventListener('message', term._getMessage);
|
||||
|
||||
if (bidirectional) {
|
||||
term.on('data', term._sendData);
|
||||
}
|
||||
term.on('resize', term._setSize);
|
||||
|
||||
socket.addEventListener('close', term.terminadoDetach.bind(term, socket));
|
||||
socket.addEventListener('error', term.terminadoDetach.bind(term, socket));
|
||||
};
|
||||
|
||||
/**
|
||||
* Detaches the given terminal from the given socket
|
||||
*
|
||||
* @param {Xterm} term - The terminal to be detached from the given socket.
|
||||
* @param {WebSocket} socket - The socket from which to detach the current
|
||||
* terminal.
|
||||
*/
|
||||
exports.terminadoDetach = function (term, socket) {
|
||||
term.off('data', term._sendData);
|
||||
|
||||
socket = (typeof socket == 'undefined') ? term.socket : socket;
|
||||
|
||||
if (socket) {
|
||||
socket.removeEventListener('message', term._getMessage);
|
||||
}
|
||||
|
||||
delete term.socket;
|
||||
};
|
||||
|
||||
/**
|
||||
* Attaches the current terminal to the given socket
|
||||
*
|
||||
* @param {WebSocket} socket - The socket to attach the current terminal.
|
||||
* @param {boolean} bidirectional - Whether the terminal should send data
|
||||
* to the socket as well.
|
||||
* @param {boolean} buffered - Whether the rendering of incoming data
|
||||
* should happen instantly or at a maximum
|
||||
* frequency of 1 rendering per 10ms.
|
||||
*/
|
||||
Xterm.prototype.terminadoAttach = function (socket, bidirectional, buffered) {
|
||||
return exports.terminadoAttach(this, socket, bidirectional, buffered);
|
||||
};
|
||||
|
||||
/**
|
||||
* Detaches the current terminal from the given socket.
|
||||
*
|
||||
* @param {WebSocket} socket - The socket from which to detach the current
|
||||
* terminal.
|
||||
*/
|
||||
Xterm.prototype.terminadoDetach = function (socket) {
|
||||
return exports.terminadoDetach(this, socket);
|
||||
};
|
||||
|
||||
return exports;
|
||||
});
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -16,6 +16,7 @@ var g_total_file_count = 0;
|
|||
var g_process = 0;
|
||||
var g_playing = false;
|
||||
var g_need_stop = false;
|
||||
var g_skip = true;
|
||||
var g_timer = null;
|
||||
var g_console_term = null;
|
||||
var g_current_time;
|
||||
|
@ -25,6 +26,7 @@ var g_req_count = 0;
|
|||
var g_dom_time = null;
|
||||
var g_dom_btn_play = null;
|
||||
var g_dom_btn_speed = null;
|
||||
var g_dom_btn_skip = null;
|
||||
var g_dom_progress = null;
|
||||
var g_dom_status = null;
|
||||
|
||||
|
@ -68,6 +70,7 @@ ywl.on_init = function (cb_stack, cb_args) {
|
|||
g_dom_time = $('#play-time');
|
||||
g_dom_btn_play = $('#btn-play');
|
||||
g_dom_btn_speed = $('#btn-speed');
|
||||
g_dom_btn_skip = $('#btn-skip');
|
||||
g_dom_progress = $('#progress');
|
||||
g_dom_status = $('#play-status');
|
||||
|
||||
|
@ -96,6 +99,7 @@ ywl.on_init = function (cb_stack, cb_args) {
|
|||
ywl.notify_error('网络通讯失败');
|
||||
}
|
||||
);
|
||||
|
||||
g_dom_btn_play.click(function () {
|
||||
if (g_playing)
|
||||
pause();
|
||||
|
@ -103,6 +107,19 @@ ywl.on_init = function (cb_stack, cb_args) {
|
|||
play();
|
||||
});
|
||||
|
||||
g_dom_btn_skip.click(function () {
|
||||
var obj = $('#btn-skip i');
|
||||
if (g_skip) {
|
||||
g_skip = false;
|
||||
obj.removeClass('fa-check-square-o').addClass('fa-square-o');
|
||||
} else {
|
||||
g_skip = true;
|
||||
obj.removeClass('fa-square-o').addClass('fa-check-square-o');
|
||||
}
|
||||
|
||||
console.log('skip:', g_skip);
|
||||
});
|
||||
|
||||
$('#btn-restart').click(function () {
|
||||
replay();
|
||||
});
|
||||
|
@ -131,7 +148,7 @@ ywl.on_init = function (cb_stack, cb_args) {
|
|||
function init() {
|
||||
g_last_time = 0;
|
||||
|
||||
if (g_console_term != null) {
|
||||
if (!_.isNull(g_console_term)) {
|
||||
g_console_term.destroy();
|
||||
}
|
||||
g_console_term = new Terminal({
|
||||
|
@ -162,7 +179,7 @@ ywl.on_init = function (cb_stack, cb_args) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (typeof(g_data[g_cur_play_file_id]) == "undefined") {
|
||||
if (_.isUndefined(g_data[g_cur_play_file_id])) {
|
||||
g_req_count++;
|
||||
if (g_req_count > 2000) {
|
||||
g_req_count = 0;
|
||||
|
@ -183,26 +200,25 @@ ywl.on_init = function (cb_stack, cb_args) {
|
|||
return;
|
||||
}
|
||||
g_dom_status.text("正在播放");
|
||||
g_current_time += record_tick;
|
||||
g_current_time += record_tick * speed_table[speed_offset].speed;
|
||||
internal_tick += record_tick;
|
||||
var play_data = g_data[g_cur_play_file_id][g_cur_play_file_offset];
|
||||
var temp_time = g_current_time * speed_table[speed_offset].speed;
|
||||
|
||||
//播放
|
||||
if (play_data.t < temp_time) {
|
||||
if (play_data.a === 1 || play_data.t < g_current_time) {
|
||||
var rec_length = g_data[g_cur_play_file_id].length;
|
||||
g_last_time = play_data.t;
|
||||
internal_tick = 0;
|
||||
|
||||
if (play_data.a == 1) {
|
||||
if (play_data.a === 1)
|
||||
g_console_term.resize(play_data.w, play_data.h);
|
||||
}
|
||||
else {
|
||||
else if (play_data.a === 2)
|
||||
g_console_term.write(play_data.d);
|
||||
}
|
||||
else
|
||||
g_console_term.write(base64_decode(play_data.d));
|
||||
|
||||
if ((g_cur_play_file_offset + 1) == rec_length) {
|
||||
if ((g_cur_play_file_id + 1) == g_total_file_count) {
|
||||
if ((g_cur_play_file_offset + 1) === rec_length) {
|
||||
if ((g_cur_play_file_id + 1) === g_total_file_count) {
|
||||
g_dom_progress.val(100);
|
||||
g_dom_status.text('播放完成');
|
||||
g_dom_time.text(parseInt(g_total_time / 1000) + '秒');
|
||||
|
@ -220,8 +236,14 @@ ywl.on_init = function (cb_stack, cb_args) {
|
|||
g_cur_play_file_offset++;
|
||||
}
|
||||
} else {
|
||||
//不播放
|
||||
if (g_skip) {
|
||||
if (play_data.t - g_current_time > 1000) {
|
||||
g_current_time = play_data.t - 999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
g_process = parseInt((g_last_time + internal_tick) * 100 / g_total_time);
|
||||
g_dom_progress.val(g_process);
|
||||
var temp = parseInt((g_last_time + internal_tick) / 1000);
|
||||
|
|
|
@ -1,292 +1,328 @@
|
|||
/*! ywl v1.0.1, (c)2016 eomsoft.net */
|
||||
"use strict";
|
||||
|
||||
var LOG_LEVEL_DEBUG = 1;
|
||||
var LOG_LEVEL_VERBOSE = 10;
|
||||
var LOG_LEVEL_INFO = 20;
|
||||
var LOG_LEVEL_WARN = 30;
|
||||
var LOG_LEVEL_ERROR = 40;
|
||||
|
||||
var WITH_LOG_LEVEL = LOG_LEVEL_VERBOSE;
|
||||
var WITH_LOG_TRACE = false;
|
||||
|
||||
var log = {};
|
||||
if (window.console && LOG_LEVEL_ERROR >= WITH_LOG_LEVEL) {
|
||||
log.e = function () {
|
||||
console.error.apply(console, arguments);
|
||||
if(WITH_LOG_TRACE)
|
||||
console.trace();
|
||||
};
|
||||
} else {
|
||||
log.e = function () {
|
||||
};
|
||||
}
|
||||
if (window.console && LOG_LEVEL_WARN >= WITH_LOG_LEVEL) {
|
||||
log.w = function () {
|
||||
console.warn.apply(console, arguments);
|
||||
if(WITH_LOG_TRACE)
|
||||
console.trace();
|
||||
};
|
||||
} else {
|
||||
log.w = function () {
|
||||
}
|
||||
}
|
||||
if (window.console && LOG_LEVEL_INFO >= WITH_LOG_LEVEL) {
|
||||
log.i = function () {
|
||||
console.info.apply(console, arguments);
|
||||
if(WITH_LOG_TRACE)
|
||||
console.trace();
|
||||
};
|
||||
} else {
|
||||
log.i = function () {
|
||||
}
|
||||
}
|
||||
if (window.console && LOG_LEVEL_VERBOSE >= WITH_LOG_LEVEL) {
|
||||
log.v = function () {
|
||||
console.log.apply(console, arguments);
|
||||
//if(WITH_LOG_TRACE)
|
||||
// console.trace();
|
||||
};
|
||||
} else {
|
||||
log.v = function () {
|
||||
}
|
||||
}
|
||||
if (window.console && LOG_LEVEL_DEBUG >= WITH_LOG_LEVEL) {
|
||||
log.d = function () {
|
||||
console.log.apply(console, arguments);
|
||||
//if(WITH_LOG_TRACE)
|
||||
// console.trace();
|
||||
};
|
||||
} else {
|
||||
log.d = function () {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 构造一个回调函数栈,遵循先进后出的原则进行调用。
|
||||
var CALLBACK_STACK = {
|
||||
create: function () {
|
||||
var self = {};
|
||||
|
||||
self.cb_stack = [];
|
||||
|
||||
self.add = function (cb_func, cb_args) {
|
||||
if (!_.isFunction(cb_func)) {
|
||||
log.e('need callable function.');
|
||||
}
|
||||
cb_args = cb_args || {};
|
||||
self.cb_stack.push({func: cb_func, args: cb_args});
|
||||
return self;
|
||||
};
|
||||
|
||||
self.exec = function (ex_args) {
|
||||
if (self.cb_stack.length > 0) {
|
||||
var cb = self.cb_stack.pop();
|
||||
var ex_ = ex_args || [];
|
||||
cb.func(self, cb.args, ex_);
|
||||
}
|
||||
};
|
||||
|
||||
self.pop = function () {
|
||||
if (self.cb_stack.length == 0) {
|
||||
return null;
|
||||
} else {
|
||||
return self.cb_stack.pop();
|
||||
}
|
||||
};
|
||||
|
||||
return self;
|
||||
}
|
||||
};
|
||||
|
||||
if (!String.prototype.startsWith) {
|
||||
String.prototype.startsWith = function (searchString, position) {
|
||||
position = position || 0;
|
||||
return this.indexOf(searchString, position) === position;
|
||||
};
|
||||
}
|
||||
|
||||
if (!String.prototype.realLength) {
|
||||
String.prototype.realLength = function () {
|
||||
var _len = 0;
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
if (this.charCodeAt(i) > 255) _len += 2; else _len += 1;
|
||||
}
|
||||
return _len;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function digital_precision(num, keep) {
|
||||
return Math.round(num * Math.pow(10, keep)) / Math.pow(10, keep);
|
||||
}
|
||||
|
||||
function prefixInteger(num, length) {
|
||||
return (num / Math.pow(10, length)).toFixed(length).substr(2);
|
||||
}
|
||||
|
||||
function size2str(size, precision) {
|
||||
precision = precision || 0;
|
||||
var s = 0;
|
||||
var k = '';
|
||||
if (size < KB) {
|
||||
s = size;
|
||||
k = 'B';
|
||||
}
|
||||
else if (size < MB) {
|
||||
s = digital_precision(size / KB, precision);
|
||||
k = 'KB'
|
||||
}
|
||||
else if (size < GB) {
|
||||
s = digital_precision(size / MB, precision);
|
||||
k = 'MB'
|
||||
}
|
||||
else if (size < TB) {
|
||||
s = digital_precision(size / GB, precision);
|
||||
k = 'GB'
|
||||
}
|
||||
else if (size < PB) {
|
||||
s = digital_precision(size / TB, precision);
|
||||
k = 'TB'
|
||||
}
|
||||
else {
|
||||
s = digital_precision(size / PB, precision);
|
||||
k = 'PB'
|
||||
}
|
||||
|
||||
return '' + s + ' ' + k;
|
||||
}
|
||||
|
||||
function second2str(sec) {
|
||||
var _ret = '';
|
||||
if (sec >= SECONDS_PER_DAY) {
|
||||
var _d = Math.floor(sec / SECONDS_PER_DAY);
|
||||
_ret = '' + _d + '天';
|
||||
sec = sec % SECONDS_PER_DAY;
|
||||
}
|
||||
|
||||
if (sec >= SECONDS_PER_HOUR) {
|
||||
var _h = Math.floor(sec / SECONDS_PER_HOUR);
|
||||
_ret += '' + _h + '小时';
|
||||
sec = sec % SECONDS_PER_HOUR;
|
||||
} else if (_ret.length > 0) {
|
||||
_ret += '0小时';
|
||||
}
|
||||
|
||||
if (sec >= SECONDS_PER_MINUTE) {
|
||||
var _m = Math.floor(sec / SECONDS_PER_MINUTE);
|
||||
_ret += '' + _m + '分';
|
||||
sec = sec % SECONDS_PER_MINUTE;
|
||||
} else if (_ret.length > 0) {
|
||||
_ret += '0分';
|
||||
}
|
||||
|
||||
_ret += '' + sec + '秒';
|
||||
return _ret;
|
||||
}
|
||||
|
||||
function get_cookie(name) {
|
||||
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
|
||||
return r ? r[1] : undefined;
|
||||
}
|
||||
|
||||
function utc_to_local(timestamp) {
|
||||
//console.log('utc_to_local:', timestamp);
|
||||
var d = new Date(timestamp * 1000);
|
||||
var _local = d.getTime() - (d.getTimezoneOffset() * 60000);
|
||||
return Math.round(_local / 1000);
|
||||
}
|
||||
|
||||
function local_to_utc(timestamp) {
|
||||
var d = new Date(timestamp * 1000);
|
||||
var _utc = d.getTime() + (d.getTimezoneOffset() * 60000);
|
||||
return Math.round(_utc / 1000);
|
||||
}
|
||||
function format_datetime(timestamp) {
|
||||
var d = new Date(timestamp * 1000);
|
||||
//return '' + d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate() + ' ' + d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds();
|
||||
|
||||
var fmt = 'yyyy-MM-dd HH:mm:ss';
|
||||
var o = {
|
||||
"M+": d.getMonth() + 1, //月份
|
||||
"d+": d.getDate(), //日
|
||||
"H+": d.getHours(), //小时
|
||||
"m+": d.getMinutes(), //分
|
||||
"s+": d.getSeconds() //秒
|
||||
//"q+": Math.floor((this.getMonth() + 3) / 3), //季度
|
||||
//"S": d.getMilliseconds() //毫秒
|
||||
};
|
||||
|
||||
if (/(y+)/.test(fmt)) {
|
||||
fmt = fmt.replace(RegExp.$1, (d.getFullYear() + "").substr(4 - RegExp.$1.length));
|
||||
}
|
||||
for (var k in o) {
|
||||
if (new RegExp("(" + k + ")").test(fmt)) {
|
||||
if(o.hasOwnProperty(k))
|
||||
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
|
||||
}
|
||||
}
|
||||
return fmt;
|
||||
}
|
||||
|
||||
var base64KeyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
function base64_encode(input) {
|
||||
var output = "";
|
||||
var chr1, chr2, chr3 = "";
|
||||
var enc1, enc2, enc3, enc4 = "";
|
||||
var i = 0;
|
||||
do {
|
||||
chr1 = input.charCodeAt(i++);
|
||||
chr2 = input.charCodeAt(i++);
|
||||
chr3 = input.charCodeAt(i++);
|
||||
enc1 = chr1 >> 2;
|
||||
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
||||
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
||||
enc4 = chr3 & 63;
|
||||
if (isNaN(chr2)) {
|
||||
enc3 = enc4 = 64;
|
||||
} else if (isNaN(chr3)) {
|
||||
enc4 = 64;
|
||||
}
|
||||
output = output + base64KeyStr.charAt(enc1) + base64KeyStr.charAt(enc2) + base64KeyStr.charAt(enc3) + base64KeyStr.charAt(enc4);
|
||||
chr1 = chr2 = chr3 = "";
|
||||
enc1 = enc2 = enc3 = enc4 = "";
|
||||
} while (i < input.length);
|
||||
return output;
|
||||
}
|
||||
|
||||
function get_file_name(path) {
|
||||
var reg = /(\\+)/g;
|
||||
path = path.replace(reg, "/");
|
||||
var _path = path.split('/');
|
||||
return _path[_path.length - 1]
|
||||
}
|
||||
|
||||
var g_unique_id = (new Date()).valueOf();
|
||||
function generate_id() {
|
||||
return g_unique_id++;
|
||||
}
|
||||
|
||||
|
||||
function htmlEncode(_s) {
|
||||
if (_s.length == 0) return "";
|
||||
var s = _s.replace(/&/g, "&");
|
||||
s = s.replace(/</g, "<");
|
||||
s = s.replace(/>/g, ">");
|
||||
//s = s.replace(/ /g, " ");
|
||||
s = s.replace(/\'/g, "'");
|
||||
s = s.replace(/\"/g, """);
|
||||
return s;
|
||||
}
|
||||
//
|
||||
///*2.用正则表达式实现html解码*/
|
||||
//function htmlDecode(_s) {
|
||||
// if (_s.length == 0) return "";
|
||||
// var s = str.replace(/&/g, "&");
|
||||
// s = s.replace(/</g, "<");
|
||||
// s = s.replace(/>/g, ">");
|
||||
// s = s.replace(/ /g, " ");
|
||||
// s = s.replace(/'/g, "\'");
|
||||
// s = s.replace(/"/g, "\"");
|
||||
// return s;
|
||||
//}
|
||||
/*! ywl v1.0.1, (c)2016 eomsoft.net */
|
||||
"use strict";
|
||||
|
||||
var LOG_LEVEL_DEBUG = 1;
|
||||
var LOG_LEVEL_VERBOSE = 10;
|
||||
var LOG_LEVEL_INFO = 20;
|
||||
var LOG_LEVEL_WARN = 30;
|
||||
var LOG_LEVEL_ERROR = 40;
|
||||
|
||||
var WITH_LOG_LEVEL = LOG_LEVEL_VERBOSE;
|
||||
var WITH_LOG_TRACE = false;
|
||||
|
||||
var log = {};
|
||||
if (window.console && LOG_LEVEL_ERROR >= WITH_LOG_LEVEL) {
|
||||
log.e = function () {
|
||||
console.error.apply(console, arguments);
|
||||
if (WITH_LOG_TRACE)
|
||||
console.trace();
|
||||
};
|
||||
} else {
|
||||
log.e = function () {
|
||||
};
|
||||
}
|
||||
if (window.console && LOG_LEVEL_WARN >= WITH_LOG_LEVEL) {
|
||||
log.w = function () {
|
||||
console.warn.apply(console, arguments);
|
||||
if (WITH_LOG_TRACE)
|
||||
console.trace();
|
||||
};
|
||||
} else {
|
||||
log.w = function () {
|
||||
}
|
||||
}
|
||||
if (window.console && LOG_LEVEL_INFO >= WITH_LOG_LEVEL) {
|
||||
log.i = function () {
|
||||
console.info.apply(console, arguments);
|
||||
if (WITH_LOG_TRACE)
|
||||
console.trace();
|
||||
};
|
||||
} else {
|
||||
log.i = function () {
|
||||
}
|
||||
}
|
||||
if (window.console && LOG_LEVEL_VERBOSE >= WITH_LOG_LEVEL) {
|
||||
log.v = function () {
|
||||
console.log.apply(console, arguments);
|
||||
//if(WITH_LOG_TRACE)
|
||||
// console.trace();
|
||||
};
|
||||
} else {
|
||||
log.v = function () {
|
||||
}
|
||||
}
|
||||
if (window.console && LOG_LEVEL_DEBUG >= WITH_LOG_LEVEL) {
|
||||
log.d = function () {
|
||||
console.log.apply(console, arguments);
|
||||
//if(WITH_LOG_TRACE)
|
||||
// console.trace();
|
||||
};
|
||||
} else {
|
||||
log.d = function () {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 构造一个回调函数栈,遵循先进后出的原则进行调用。
|
||||
var CALLBACK_STACK = {
|
||||
create: function () {
|
||||
var self = {};
|
||||
|
||||
self.cb_stack = [];
|
||||
|
||||
self.add = function (cb_func, cb_args) {
|
||||
if (!_.isFunction(cb_func)) {
|
||||
log.e('need callable function.');
|
||||
}
|
||||
cb_args = cb_args || {};
|
||||
self.cb_stack.push({func: cb_func, args: cb_args});
|
||||
return self;
|
||||
};
|
||||
|
||||
self.exec = function (ex_args) {
|
||||
if (self.cb_stack.length > 0) {
|
||||
var cb = self.cb_stack.pop();
|
||||
var ex_ = ex_args || [];
|
||||
cb.func(self, cb.args, ex_);
|
||||
}
|
||||
};
|
||||
|
||||
self.pop = function () {
|
||||
if (self.cb_stack.length == 0) {
|
||||
return null;
|
||||
} else {
|
||||
return self.cb_stack.pop();
|
||||
}
|
||||
};
|
||||
|
||||
return self;
|
||||
}
|
||||
};
|
||||
|
||||
if (!String.prototype.startsWith) {
|
||||
String.prototype.startsWith = function (searchString, position) {
|
||||
position = position || 0;
|
||||
return this.indexOf(searchString, position) === position;
|
||||
};
|
||||
}
|
||||
|
||||
if (!String.prototype.realLength) {
|
||||
String.prototype.realLength = function () {
|
||||
var _len = 0;
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
if (this.charCodeAt(i) > 255) _len += 2; else _len += 1;
|
||||
}
|
||||
return _len;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function digital_precision(num, keep) {
|
||||
return Math.round(num * Math.pow(10, keep)) / Math.pow(10, keep);
|
||||
}
|
||||
|
||||
function prefixInteger(num, length) {
|
||||
return (num / Math.pow(10, length)).toFixed(length).substr(2);
|
||||
}
|
||||
|
||||
function size2str(size, precision) {
|
||||
precision = precision || 0;
|
||||
var s = 0;
|
||||
var k = '';
|
||||
if (size < KB) {
|
||||
s = size;
|
||||
k = 'B';
|
||||
}
|
||||
else if (size < MB) {
|
||||
s = digital_precision(size / KB, precision);
|
||||
k = 'KB'
|
||||
}
|
||||
else if (size < GB) {
|
||||
s = digital_precision(size / MB, precision);
|
||||
k = 'MB'
|
||||
}
|
||||
else if (size < TB) {
|
||||
s = digital_precision(size / GB, precision);
|
||||
k = 'GB'
|
||||
}
|
||||
else if (size < PB) {
|
||||
s = digital_precision(size / TB, precision);
|
||||
k = 'TB'
|
||||
}
|
||||
else {
|
||||
s = digital_precision(size / PB, precision);
|
||||
k = 'PB'
|
||||
}
|
||||
|
||||
return '' + s + ' ' + k;
|
||||
}
|
||||
|
||||
function second2str(sec) {
|
||||
var _ret = '';
|
||||
if (sec >= SECONDS_PER_DAY) {
|
||||
var _d = Math.floor(sec / SECONDS_PER_DAY);
|
||||
_ret = '' + _d + '天';
|
||||
sec = sec % SECONDS_PER_DAY;
|
||||
}
|
||||
|
||||
if (sec >= SECONDS_PER_HOUR) {
|
||||
var _h = Math.floor(sec / SECONDS_PER_HOUR);
|
||||
_ret += '' + _h + '小时';
|
||||
sec = sec % SECONDS_PER_HOUR;
|
||||
} else if (_ret.length > 0) {
|
||||
_ret += '0小时';
|
||||
}
|
||||
|
||||
if (sec >= SECONDS_PER_MINUTE) {
|
||||
var _m = Math.floor(sec / SECONDS_PER_MINUTE);
|
||||
_ret += '' + _m + '分';
|
||||
sec = sec % SECONDS_PER_MINUTE;
|
||||
} else if (_ret.length > 0) {
|
||||
_ret += '0分';
|
||||
}
|
||||
|
||||
_ret += '' + sec + '秒';
|
||||
return _ret;
|
||||
}
|
||||
|
||||
function get_cookie(name) {
|
||||
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
|
||||
return r ? r[1] : undefined;
|
||||
}
|
||||
|
||||
function utc_to_local(timestamp) {
|
||||
//console.log('utc_to_local:', timestamp);
|
||||
var d = new Date(timestamp * 1000);
|
||||
var _local = d.getTime() - (d.getTimezoneOffset() * 60000);
|
||||
return Math.round(_local / 1000);
|
||||
}
|
||||
|
||||
function local_to_utc(timestamp) {
|
||||
var d = new Date(timestamp * 1000);
|
||||
var _utc = d.getTime() + (d.getTimezoneOffset() * 60000);
|
||||
return Math.round(_utc / 1000);
|
||||
}
|
||||
function format_datetime(timestamp) {
|
||||
var d = new Date(timestamp * 1000);
|
||||
//return '' + d.getFullYear() + '-' + (d.getMonth() + 1) + '-' + d.getDate() + ' ' + d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds();
|
||||
|
||||
var fmt = 'yyyy-MM-dd HH:mm:ss';
|
||||
var o = {
|
||||
"M+": d.getMonth() + 1, //月份
|
||||
"d+": d.getDate(), //日
|
||||
"H+": d.getHours(), //小时
|
||||
"m+": d.getMinutes(), //分
|
||||
"s+": d.getSeconds() //秒
|
||||
//"q+": Math.floor((this.getMonth() + 3) / 3), //季度
|
||||
//"S": d.getMilliseconds() //毫秒
|
||||
};
|
||||
|
||||
if (/(y+)/.test(fmt)) {
|
||||
fmt = fmt.replace(RegExp.$1, (d.getFullYear() + "").substr(4 - RegExp.$1.length));
|
||||
}
|
||||
for (var k in o) {
|
||||
if (new RegExp("(" + k + ")").test(fmt)) {
|
||||
if (o.hasOwnProperty(k))
|
||||
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
|
||||
}
|
||||
}
|
||||
return fmt;
|
||||
}
|
||||
|
||||
var base64KeyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
function base64_encode(input) {
|
||||
var output = "";
|
||||
var chr1, chr2, chr3 = "";
|
||||
var enc1, enc2, enc3, enc4 = "";
|
||||
var i = 0;
|
||||
do {
|
||||
chr1 = input.charCodeAt(i++);
|
||||
chr2 = input.charCodeAt(i++);
|
||||
chr3 = input.charCodeAt(i++);
|
||||
enc1 = chr1 >> 2;
|
||||
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
||||
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
||||
enc4 = chr3 & 63;
|
||||
if (isNaN(chr2)) {
|
||||
enc3 = enc4 = 64;
|
||||
} else if (isNaN(chr3)) {
|
||||
enc4 = 64;
|
||||
}
|
||||
output = output + base64KeyStr.charAt(enc1) + base64KeyStr.charAt(enc2) + base64KeyStr.charAt(enc3) + base64KeyStr.charAt(enc4);
|
||||
chr1 = chr2 = chr3 = "";
|
||||
enc1 = enc2 = enc3 = enc4 = "";
|
||||
} while (i < input.length);
|
||||
return output;
|
||||
}
|
||||
|
||||
function base64_decode(data) {
|
||||
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
|
||||
ac = 0,
|
||||
tmp_arr = [];
|
||||
|
||||
if (!data) {
|
||||
return data;
|
||||
}
|
||||
data += '';
|
||||
|
||||
do { // unpack four hexets into three octets using index points in b64
|
||||
h1 = base64KeyStr.indexOf(data.charAt(i++));
|
||||
h2 = base64KeyStr.indexOf(data.charAt(i++));
|
||||
h3 = base64KeyStr.indexOf(data.charAt(i++));
|
||||
h4 = base64KeyStr.indexOf(data.charAt(i++));
|
||||
|
||||
bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
|
||||
|
||||
o1 = bits >> 16 & 0xff;
|
||||
o2 = bits >> 8 & 0xff;
|
||||
o3 = bits & 0xff;
|
||||
|
||||
if (h3 === 64) {
|
||||
tmp_arr[ac++] = String.fromCharCode(o1);
|
||||
} else if (h4 === 64) {
|
||||
tmp_arr[ac++] = String.fromCharCode(o1, o2);
|
||||
} else {
|
||||
tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
|
||||
}
|
||||
} while (i < data.length);
|
||||
|
||||
return tmp_arr.join('');
|
||||
}
|
||||
|
||||
|
||||
|
||||
function get_file_name(path) {
|
||||
var reg = /(\\+)/g;
|
||||
path = path.replace(reg, "/");
|
||||
var _path = path.split('/');
|
||||
return _path[_path.length - 1]
|
||||
}
|
||||
|
||||
var g_unique_id = (new Date()).valueOf();
|
||||
function generate_id() {
|
||||
return g_unique_id++;
|
||||
}
|
||||
|
||||
|
||||
function htmlEncode(_s) {
|
||||
if (_s.length == 0) return "";
|
||||
var s = _s.replace(/&/g, "&");
|
||||
s = s.replace(/</g, "<");
|
||||
s = s.replace(/>/g, ">");
|
||||
//s = s.replace(/ /g, " ");
|
||||
s = s.replace(/\'/g, "'");
|
||||
s = s.replace(/\"/g, """);
|
||||
return s;
|
||||
}
|
||||
//
|
||||
///*2.用正则表达式实现html解码*/
|
||||
//function htmlDecode(_s) {
|
||||
// if (_s.length == 0) return "";
|
||||
// var s = str.replace(/&/g, "&");
|
||||
// s = s.replace(/</g, "<");
|
||||
// s = s.replace(/>/g, ">");
|
||||
// s = s.replace(/ /g, " ");
|
||||
// s = s.replace(/'/g, "\'");
|
||||
// s = s.replace(/"/g, "\"");
|
||||
// return s;
|
||||
//}
|
||||
|
|
|
@ -1,49 +1,66 @@
|
|||
<%!
|
||||
page_title_ = '录像回放'
|
||||
%>
|
||||
|
||||
<%inherit file="../page_no_sidebar_base.mako"/>
|
||||
<%block name="extend_js">
|
||||
<script type="text/javascript" src="${ static_url('js/common/term.js') }"></script>
|
||||
<script type="text/javascript" src="${ static_url('js/ui/record.js') }"></script>
|
||||
</%block>
|
||||
|
||||
<%block name="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li><i class="fa fa-server"></i> ${self.attr.page_title_}</li>
|
||||
<li><span id="recorder-info"></span></li>
|
||||
</ol>
|
||||
</%block>
|
||||
|
||||
|
||||
<div class="page-content">
|
||||
<div ng-controller="TerminalRecordCtrl">
|
||||
<button id="btn-play" type="button" class="btn btn-primary btn-sm" style="width:80px;"><i class="fa fa-pause"> 暂停</i></button>
|
||||
<button id="btn-restart" type="button" class="btn btn-success btn-sm"><i class="fa fa-refresh"></i> 重新播放</button>
|
||||
|
||||
<button id="btn-speed" type="button" class="btn btn-warning btn-sm" style="width:80px;">正常速度</button>
|
||||
<span id="play-status" class="badge badge-normal" style="margin-left:5px;">状态:正在获取数据</span>
|
||||
<span id="play-time" class="badge badge-success" style="margin-left:5px;">总时长:未知</span>
|
||||
<input id="progress" type="range" value="0" min=0 max=100 style="margin-top: 10px;"/>
|
||||
<div id="terminal" style="margin-top: 10px;"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<%block name="extend_content">
|
||||
|
||||
</%block>
|
||||
|
||||
|
||||
|
||||
<%block name="embed_js">
|
||||
<script type="text/javascript">
|
||||
ywl.add_page_options({
|
||||
record_id:${record_id}
|
||||
});
|
||||
|
||||
</script>
|
||||
<%!
|
||||
page_title_ = '录像回放'
|
||||
%>
|
||||
|
||||
<%inherit file="../page_no_sidebar_base.mako"/>
|
||||
|
||||
<%block name="extend_js">
|
||||
<script type="text/javascript" src="${ static_url('js/common/xterm.js') }"></script>
|
||||
<script type="text/javascript" src="${ static_url('js/ui/record.js') }"></script>
|
||||
</%block>
|
||||
|
||||
<%block name="extend_css">
|
||||
<link href="${ static_url('js/common/xterm.css') }" rel="stylesheet" type="text/css"/>
|
||||
|
||||
<style type="text/css">
|
||||
div.terminal {
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
</style>
|
||||
</%block>
|
||||
|
||||
<%block name="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li><i class="fa fa-server"></i> ${self.attr.page_title_}</li>
|
||||
<li><span id="recorder-info"></span></li>
|
||||
</ol>
|
||||
</%block>
|
||||
|
||||
|
||||
<div class="page-content">
|
||||
<div ng-controller="TerminalRecordCtrl">
|
||||
<button id="btn-play" type="button" class="btn btn-primary btn-sm" style="width:80px;"><i class="fa fa-pause fa-fw"> 暂停</i></button>
|
||||
<button id="btn-restart" type="button" class="btn btn-success btn-sm"><i class="fa fa-refresh fa-fw"></i> 重新播放</button>
|
||||
|
||||
<button id="btn-speed" type="button" class="btn btn-info btn-sm" style="width:80px;">正常速度</button>
|
||||
|
||||
<div style="display:inline-block;position:relative;top:4px;margin-left:10px;margin-right:15px;">
|
||||
## <label><input id="btn-skip" type="checkbox"> 跳过无操作时间</label>
|
||||
<span id="btn-skip" style="cursor:pointer;"><i class="fa fa-check-square-o fa-fw"></i> 跳过无操作时间</span>
|
||||
</div>
|
||||
|
||||
<span id="play-status" class="badge badge-normal" style="margin-left:5px;">状态:正在获取数据</span>
|
||||
<span id="play-time" class="badge badge-success" style="margin-left:5px;">总时长:未知</span>
|
||||
<input id="progress" type="range" value="0" min=0 max=100 style="margin-top: 10px;"/>
|
||||
<div id="terminal" style="margin-top:10px;"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<%block name="extend_content">
|
||||
|
||||
</%block>
|
||||
|
||||
|
||||
|
||||
<%block name="embed_js">
|
||||
<script type="text/javascript">
|
||||
ywl.add_page_options({
|
||||
record_id:${record_id}
|
||||
});
|
||||
|
||||
</script>
|
||||
</%block>
|
Loading…
Reference in New Issue