Unverified Commit b05f7d8e authored by 老广's avatar 老广 Committed by GitHub

Merge pull request #35 from jumpserver/dev

Dev
parents ebda194f f844a768
......@@ -22,7 +22,6 @@
"styles": [
"../node_modules/animate.css/animate.min.css",
"../node_modules/xterm/dist/xterm.css",
"../node_modules/elfinder/css/elfinder.min.css",
"sass/style.scss",
"styles.css",
"assets/ztree/awesomeStyle/awesome.css"
......@@ -35,7 +34,6 @@
"../node_modules/bootstrap/dist/js/bootstrap.min.js",
"assets/inspinia/inspinia.js",
"assets/slimscroll/jquery.slimscroll.min.js",
"../node_modules/elfinder/js/elfinder.min.js",
"../node_modules/xterm/dist/xterm.js",
"assets/ztree/jquery.ztree.all.min.js",
"assets/ztree/jquery.ztree.exhide.min.js"
......
#!/usr/bin/env python3
from flask import Flask, send_from_directory, render_template, request, jsonify, redirect, send_file
import sys
import threading
sys.path.append('/Users/guang/projects/coco')
from flask import Flask, send_from_directory, render_template, request, jsonify, \
redirect, send_file, abort
from flask_socketio import SocketIO, Namespace, emit, join_room, leave_room
import paramiko
import uuid
import eventlet
from threading import Lock
from flask import Flask, request, current_app, redirect
import eventlet
import time
import json
import socket
import logging
import select
from coco.models import WSProxy, Client, Request
from coco.httpd import ProxyNamespace
logger = logging.getLogger(__file__)
logger.setLevel(logging.DEBUG)
sh = logging.StreamHandler(stream=None)
logger.addHandler(sh)
logger2 = logging.getLogger('coco')
logger2.setLevel(logging.DEBUG)
logger2.addHandler(sh)
eventlet.monkey_patch()
# async_mode = 'threading'
async_mode = 'eventlet'
app = Flask(__name__, template_folder='dist')
socketio = None
thread = None
thread_lock = Lock()
class SSHws(Namespace):
def __init__(self, *args, **kwargs):
"""
:param args:
:param kwargs:
self.connections = {
"request_sid": {
"room_id": {
"id": room_id,
"proxy": None,
"client": None,
"forwarder": None,
"request": None,
"cols": 80,
"rows": 24
},
...
},
...
}
"""
super().__init__(*args, **kwargs)
self.connections = dict()
def ssh_with_password(self, ws, room_id):
nodes = '[{"id":"03059e2e-06b8-4ef1-b949-72e230b706fa","key":"0:9:5","name":"部门1","value":"部门1","parent":"ea4688ef-2b65-40cd-944d-5fca39e34f42","assets_granted":[{"id":"ad594b10-9f64-4913-b7b1-135fe63561d1","hostname":"ali-windows","ip":"47.104.243.139","port":3389,"system_users_granted":[{"id":"8763b81a-bb5e-484a-abca-10514c7bb185","name":"组织1-部门1-Administrator","username":"administrator","priority":10,"protocol":"rdp","comment":""}],"is_active":true,"system_users_join":"administrator","os":null,"domain":null,"platform":"Windows","comment":""},{"id":"d9020939-1dd7-4b18-9165-5124f20d1f77","hostname":"newwindows","ip":"10.1.10.114","port":3389,"system_users_granted":[{"id":"46b57293-c662-46f9-8bc4-dcf64f01bedc","name":"newwindows","username":"administrator","priority":10,"protocol":"rdp","comment":""},{"id":"8763b81a-bb5e-484a-abca-10514c7bb185","name":"组织1-部门1-Administrator","username":"administrator","priority":10,"protocol":"rdp","comment":""}],"is_active":true,"system_users_join":"administrator, administrator","os":null,"domain":null,"platform":"Windows","comment":""},{"id":"9ef36bb3-1bed-455f-be09-3770d3f4bf97","hostname":"test-vm1","ip":"172.19.185.6","port":22,"system_users_granted":[{"id":"7e326f71-aee5-4688-8cc1-717919470a09","name":"root","username":"root","priority":10,"protocol":"ssh","comment":""}],"is_active":true,"system_users_join":"root","os":null,"domain":null,"platform":"Linux","comment":""},{"id":"1600ed6d-e3b6-434c-a960-c5bb818806b6","hostname":"windows1","ip":"10.1.10.178","port":3389,"system_users_granted":[{"id":"413ea1d2-ef73-4a90-bae3-571ac1b39d93","name":"2012-test-no-passwd-rdp","username":"administrator","priority":10,"protocol":"rdp","comment":""},{"id":"46b57293-c662-46f9-8bc4-dcf64f01bedc","name":"newwindows","username":"administrator","priority":10,"protocol":"rdp","comment":""},{"id":"8763b81a-bb5e-484a-abca-10514c7bb185","name":"组织1-部门1-Administrator","username":"administrator","priority":10,"protocol":"rdp","comment":""}],"is_active":true,"system_users_join":"administrator, administrator, administrator","os":null,"domain":null,"platform":"Windows","comment":""},{"id":"27e50edc-52d9-41ef-8c9e-1bff9d1628b2","hostname":"test-vm2","ip":"172.19.185.7","port":22,"system_users_granted":[{"id":"7e326f71-aee5-4688-8cc1-717919470a09","name":"root","username":"root","priority":10,"protocol":"ssh","comment":""}],"is_active":true,"system_users_join":"root","os":null,"domain":null,"platform":"Linux","comment":""},{"id":"b6f16269-d02a-4055-9cd8-460fa10b1540","hostname":"test-vm3","ip":"172.19.185.8","port":22,"system_users_granted":[{"id":"7e326f71-aee5-4688-8cc1-717919470a09","name":"root","username":"root","priority":10,"protocol":"ssh","comment":""}],"is_active":true,"system_users_join":"root","os":null,"domain":null,"platform":"Linux","comment":""},{"id":"b952a481-a624-467e-b97f-9435155f0d53","hostname":"testserver","ip":"10.1.10.192","port":22,"system_users_granted":[{"id":"7e326f71-aee5-4688-8cc1-717919470a09","name":"root","username":"root","priority":10,"protocol":"ssh","comment":""}],"is_active":true,"system_users_join":"root","os":"CentOS","domain":"8789580f-b5ca-4478-b6d3-d0dafc4c48e8","platform":"Linux","comment":""},{"id":"969247e0-3796-4090-9aa6-3248560079e6","hostname":"test01","ip":"123.123.123.1","port":22,"system_users_granted":[{"id":"7e326f71-aee5-4688-8cc1-717919470a09","name":"root","username":"root","priority":10,"protocol":"ssh","comment":""}],"is_active":true,"system_users_join":"root","os":null,"domain":null,"platform":"Linux","comment":""},{"id":"7e8451cb-8eb7-4c9d-b652-961a6fdce3c4","hostname":"wz-test","ip":"54.222.180.235","port":22,"system_users_granted":[{"id":"7e326f71-aee5-4688-8cc1-717919470a09","name":"root","username":"root","priority":10,"protocol":"ssh","comment":""}],"is_active":true,"system_users_join":"root","os":"RedHat","domain":null,"platform":"Linux","comment":""}],"assets_amount":9}]'
class Forwarder:
def __init__(self, client):
self.client = client
width = client.request.meta['width']
height = client.request.meta['height']
self.server = self.ssh_with_password(width, height)
self.watch_win_size_change_async()
def proxy(self, asset, system_user):
while True:
r, w, x = select.select([self.server, self.client], [], [])
if self.server in r:
data = self.server.recv(1024)
if len(data) == 0:
break
self.client.send(data)
if self.client in r:
data = self.client.recv(1024)
if len(data) == 0:
break
self.server.send(data)
def watch_win_size_change_async(self):
thread = threading.Thread(target=self.watch_win_size_change)
thread.daemon = True
thread.start()
def ssh_with_password(self, width=80, height=24):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect("192.168.244.176", 22, "root", "redhat123")
width, height = self.get_win_size()
chan = ssh.invoke_shell(term='xterm', width=width, height=height)
# self.socketio.start_background_task(self.send_data, self.clients[request.sid]["chan"])
# self.chan.settimeout(0.1)
return chan
def proxy(self, ws, chan, room_id):
# eventlet.monkey_patch(thread=True, select=True, socket=True)
while True:
data = chan.recv(1024)
socketio.sleep(1)
if len(data) == 0:
def watch_win_size_change(self):
while self.client.request.change_size_event.wait():
self.client.request.change_size_event.clear()
width = self.client.request.meta.get('width', 80)
height = self.client.request.meta.get('height', 24)
logger.debug("Change win size: %s - %s" % (width, height))
try:
self.server.resize_pty(width=width, height=height)
# self.server.chan.resize_pty(width=width, height=height)
except Exception:
break
ws.emit(event="data", data={"data": data.decode(), "room": room_id}, room=room_id, namespace='/ssh')
def new_connection(self):
self.connections[request.sid] = dict()
def new_room(self):
room_id = str(uuid.uuid4())
room = {
"id": room_id,
"proxy": None,
"client": None,
"forwarder": None,
"request": self.ssh_with_password(self, room_id),
"cols": 80,
"rows": 24
}
self.connections[request.sid][room_id] = room
return room
@staticmethod
def get_win_size():
cols_request = request.cookies.get('cols')
rows_request = request.cookies.get('rows')
if cols_request and cols_request.isdigit():
cols = int(cols_request)
else:
cols = 80
if rows_request and rows_request.isdigit():
rows = int(rows_request)
else:
rows = 24
return cols, rows
class SSHws(ProxyNamespace):
def on_connect(self):
print("On connect event trigger")
logger.debug("ON connect")
self.new_connection()
# self.connections[request.sid] = connection
# self.rooms[connection['room']] = {
# "admin": request.sid,
# "member": [],
# "rw": []
# }
# join_room(connection['room'])
def on_host(self, message):
# 此处获取主机的信息
print("On host event trigger")
logger.debug("On host event trigger")
asset_id = message.get('uuid', None)
user_id = message.get('userid', None)
secret = message.get('secret', None)
room = self.new_room()
win_size = message.get('size', (80, 24))
req = self.make_coco_request(win_size[0], win_size[1])
room = self.new_room(req)
self.emit('room', {'room': room["id"], 'secret': secret})
print("Join room: {}".format(room["id"]))
join_room(room["id"])
if not asset_id or not user_id:
# self.on_connect()
return
global thread
if thread is None:
thread = self.socketio.start_background_task(
self.proxy, self, room["request"], room["id"]
)
def on_data(self, message):
"""
收到浏览器请求
:param message: {"data": "xxx", "room": "xxx"}
:return:
"""
room_id = message.get('room')
room = self.connections.get(request.sid, {}).get(room_id)
if not room:
return
room["request"].send(message['data'])
# asset = app_service.get_asset(asset_id)
# system_user = app_service.get_system_user(user_id)
# if not asset or not system_user:
# self.on_connect()
# return
child, parent = socket.socketpair()
client = Client(parent, room["request"])
forwarder = Forwarder(client)
room["client"] = client
room["forwarder"] = forwarder
room["proxy"] = WSProxy(self, child, room["id"])
room["cols"], room["rows"] = win_size
self.socketio.start_background_task(
forwarder.proxy, None, None
)
def on_token(self, message):
# 此处获取token含有的主机的信息
print("On token trigger")
logger.debug("On token trigger")
token = message.get('token', None)
secret = message.get('secret', None)
size = message.get('size', (80, 24))
room = self.new_room()
self.emit('room', {'room': room["id"], 'secret': secret})
if not token or not secret:
print("Token or secret is None")
self.emit('data', {'data': "\nOperation not permitted!",
'room': room["id"]})
self.emit('disconnect')
return None
info = self.app.service.get_token_asset(token)
print(info)
if not info:
print("Token info is None")
logger.debug("Token or secret is None: {}".format(token, secret))
self.emit('data', {'data': "\nOperation not permitted!",
'room': room["id"]})
self.emit('disconnect')
return None
user_id = info.get('user', None)
self.current_user = self.app.service.get_user_profile(user_id)
room["request"].user = self.current_user
print(self.current_user)
logger.debug(self.current_user)
self.on_host({
'secret': secret,
'uuid': info['asset'],
'userid': info['system_user'],
'uuid': 'asset',
'userid': 'system_user',
'size': size
})
def on_resize(self, message):
cols, rows = message.get('cols', None), message.get('rows', None)
print("On resize event trigger: {}*{}".format(cols, rows))
rooms = self.connections.get(request.sid)
if not rooms:
return
room_tmp = list(rooms.values())[0]
if (room_tmp["cols"], room_tmp["rows"]) != (cols, rows):
for room in rooms.values():
room["request"].resize_pty(width=cols, height=rows)
# room["request"].change_size_event.set()
# room.update({"cols": cols, "rows": rows})
# def on_room(self, session_id):
# print("On room event trigger")
# if session_id not in self.connections.keys():
# self.emit(
# 'error', "no such session",
# room=self.connections[request.sid]["room"]
# )
# else:
# self.emit(
# 'room', self.connections[session_id]["room"],
# room=self.connections[request.sid]["room"]
# )
#
# def on_join(self, room):
# print("On join room event trigger")
# self.on_leave(self.connections[request.id]["room"])
# self.connections[request.sid]["room"] = room
# self.rooms[room]["member"].append(request.sid)
# join_room(room=room)
#
# def on_leave(self, room):
# print("On leave room event trigger")
# if self.rooms[room]["admin"] == request.sid:
# self.emit("data", "\nAdmin leave", room=room)
# del self.rooms[room]
# leave_room(room=room)
def on_disconnect(self):
print("On disconnect event trigger")
# self.on_leave(self.clients[request.sid]["room"])
for room in self.connections.get(request.sid, {}):
self.on_logout(room["id"])
del self.connections[request.sid]
def on_logout(self, room_id):
print("On logout event trigger")
room = self.connections.get(request.sid, {}).get(room_id)
if room:
room["proxy"].close()
del self.connections[request.sid][room_id]
del room
@app.route('/luna/<path:path>')
def send_js(path):
......@@ -234,649 +156,14 @@ def send_js(path):
@app.route('/api/perms/v1/user/nodes-assets/')
def asset_groups_assets():
assets = [
{
"id": "67f92d6c-0f91-4d20-a0e4-ac83b7dd02b6",
"key": "0:11:77",
"name": "新节点 12",
"value": "新节点 12",
"parent": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"assets_granted": [
{
"id": "1600ed6d-e3b6-434c-a960-c5bb818806b6",
"hostname": "windows1",
"ip": "10.1.10.178",
"port": 3389,
"system_users_granted": [
{
"id": "8763b81a-bb5e-484a-abca-10514c7bb185",
"name": "组织1-部门1-Administrator",
"username": "Administrator",
"priority": 10,
"protocol": "rdp",
"comment": ""
}
],
"is_active": True,
"system_users_join": "Administrator",
"os": "",
"domain": "",
"nodes": [
{
"id": "67f92d6c-0f91-4d20-a0e4-ac83b7dd02b6",
"key": "0:11:77",
"value": "新节点 12",
"parent": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"assets_amount": 6,
"is_asset": False
},
{
"id": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"key": "0:11",
"value": "网域测试",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_amount": 6,
"is_asset": False
}
],
"platform": "Windows",
"comment": ""
},
{
"id": "b952a481-a624-467e-b97f-9435155f0d53",
"hostname": "testserver",
"ip": "10.1.10.192",
"port": 22,
"system_users_granted": [
{
"id": "7e326f71-aee5-4688-8cc1-717919470a09",
"name": "root",
"username": "root",
"priority": 10,
"protocol": "ssh",
"comment": ""
}
],
"is_active": True,
"system_users_join": "root, zbh",
"os": "CentOS",
"domain": "",
"nodes": [
{
"id": "67f92d6c-0f91-4d20-a0e4-ac83b7dd02b6",
"key": "0:11:77",
"value": "新节点 12",
"parent": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"assets_amount": 6,
"is_asset": False
},
{
"id": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"key": "0:11",
"value": "网域测试",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_amount": 6,
"is_asset": False
},
{
"id": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"key": "0",
"value": "Fit2cloud",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_amount": 6,
"is_asset": False
}
],
"platform": "Linux",
"comment": ""
},
{
"id": "9fcd7a09-a171-4cb7-b2f9-a025754f8635",
"hostname": "ali-windows",
"ip": "47.104.206.228",
"port": 3389,
"system_users_granted": [
{
"id": "8763b81a-bb5e-484a-abca-10514c7bb185",
"name": "组织1-部门1-Administrator",
"username": "Administrator",
"priority": 10,
"protocol": "rdp",
"comment": ""
}
],
"is_active": True,
"system_users_join": "Administrator",
"os": "",
"domain": "",
"nodes": [
{
"id": "67f92d6c-0f91-4d20-a0e4-ac83b7dd02b6",
"key": "0:11:77",
"value": "新节点 12",
"parent": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"assets_amount": 6,
"is_asset": False
},
{
"id": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"key": "0",
"value": "Fit2cloud",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_amount": 6,
"is_asset": False
}
],
"platform": "Windows",
"comment": ""
},
{
"id": "b6f16269-d02a-4055-9cd8-460fa10b1540",
"hostname": "test-vm3",
"ip": "172.19.185.8",
"port": 22,
"system_users_granted": [
{
"id": "7e326f71-aee5-4688-8cc1-717919470a09",
"name": "root",
"username": "root",
"priority": 10,
"protocol": "ssh",
"comment": ""
}
],
"is_active": True,
"system_users_join": "root, zbh",
"os": "",
"domain": "8789580f-b5ca-4478-b6d3-d0dafc4c48e8",
"nodes": [
{
"id": "67f92d6c-0f91-4d20-a0e4-ac83b7dd02b6",
"key": "0:11:77",
"value": "新节点 12",
"parent": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"assets_amount": 6,
"is_asset": False
},
{
"id": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"key": "0:11",
"value": "网域测试",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_amount": 6,
"is_asset": False
}
],
"platform": "Linux",
"comment": ""
},
{
"id": "27e50edc-52d9-41ef-8c9e-1bff9d1628b2",
"hostname": "test-vm2",
"ip": "172.19.185.7",
"port": 22,
"system_users_granted": [
{
"id": "7e326f71-aee5-4688-8cc1-717919470a09",
"name": "root",
"username": "root",
"priority": 10,
"protocol": "ssh",
"comment": ""
},
],
"is_active": True,
"system_users_join": "root, zbh",
"os": "",
"domain": "8789580f-b5ca-4478-b6d3-d0dafc4c48e8",
"nodes": [
{
"id": "67f92d6c-0f91-4d20-a0e4-ac83b7dd02b6",
"key": "0:11:77",
"value": "新节点 12",
"parent": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"assets_amount": 6,
"is_asset": False
},
{
"id": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"key": "0:11",
"value": "网域测试",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_amount": 6,
"is_asset": False
}
],
"platform": "Linux",
"comment": ""
},
{
"id": "9ef36bb3-1bed-455f-be09-3770d3f4bf97",
"hostname": "test-vm1",
"ip": "172.19.185.6",
"port": 22,
"system_users_granted": [
{
"id": "7e326f71-aee5-4688-8cc1-717919470a09",
"name": "root",
"username": "root",
"priority": 10,
"protocol": "ssh",
"comment": ""
},
{
"id": "17f384f4-683d-4944-a38d-db73608b92a9",
"name": "zbh-test",
"username": "zbh",
"priority": 10,
"protocol": "ssh",
"comment": ""
}
],
"is_active": True,
"system_users_join": "root, zbh",
"os": "",
"domain": "8789580f-b5ca-4478-b6d3-d0dafc4c48e8",
"nodes": [
{
"id": "67f92d6c-0f91-4d20-a0e4-ac83b7dd02b6",
"key": "0:11:77",
"value": "新节点 12",
"parent": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"assets_amount": 6,
"is_asset": False
},
{
"id": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"key": "0:11",
"value": "网域测试",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_amount": 6,
"is_asset": False
}
],
"platform": "Linux",
"comment": ""
}
],
"assets_amount": 6
},
{
"id": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"key": "0:11",
"name": "网域测试",
"value": "网域测试",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_granted": [
{
"id": "1600ed6d-e3b6-434c-a960-c5bb818806b6",
"hostname": "windows1",
"ip": "10.1.10.178",
"port": 3389,
"system_users_granted": [
{
"id": "8763b81a-bb5e-484a-abca-10514c7bb185",
"name": "组织1-部门1-Administrator",
"username": "Administrator",
"priority": 10,
"protocol": "rdp",
"comment": ""
}
],
"is_active": True,
"system_users_join": "Administrator",
"os": "",
"domain": "",
"nodes": [
{
"id": "67f92d6c-0f91-4d20-a0e4-ac83b7dd02b6",
"key": "0:11:77",
"value": "新节点 12",
"parent": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"assets_amount": 6,
"is_asset": False
},
{
"id": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"key": "0:11",
"value": "网域测试",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_amount": 6,
"is_asset": False
}
],
"platform": "Windows",
"comment": ""
},
{
"id": "b952a481-a624-467e-b97f-9435155f0d53",
"hostname": "testserver",
"ip": "10.1.10.192",
"port": 22,
"system_users_granted": [
{
"id": "7e326f71-aee5-4688-8cc1-717919470a09",
"name": "root",
"username": "root",
"priority": 10,
"protocol": "ssh",
"comment": ""
}
],
"is_active": True,
"system_users_join": "root, zbh",
"os": "CentOS",
"domain": "",
"nodes": [
{
"id": "67f92d6c-0f91-4d20-a0e4-ac83b7dd02b6",
"key": "0:11:77",
"value": "新节点 12",
"parent": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"assets_amount": 6,
"is_asset": False
},
{
"id": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"key": "0:11",
"value": "网域测试",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_amount": 6,
"is_asset": False
},
{
"id": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"key": "0",
"value": "Fit2cloud",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_amount": 6,
"is_asset": False
}
],
"platform": "Linux",
"comment": ""
},
{
"id": "b6f16269-d02a-4055-9cd8-460fa10b1540",
"hostname": "test-vm3",
"ip": "172.19.185.8",
"port": 22,
"system_users_granted": [
{
"id": "7e326f71-aee5-4688-8cc1-717919470a09",
"name": "root",
"username": "root",
"priority": 10,
"protocol": "ssh",
"comment": ""
},
{
"id": "17f384f4-683d-4944-a38d-db73608b92a9",
"name": "zbh-test",
"username": "zbh",
"priority": 10,
"protocol": "ssh",
"comment": ""
}
],
"is_active": True,
"system_users_join": "root, zbh",
"os": "",
"domain": "8789580f-b5ca-4478-b6d3-d0dafc4c48e8",
"nodes": [
{
"id": "67f92d6c-0f91-4d20-a0e4-ac83b7dd02b6",
"key": "0:11:77",
"value": "新节点 12",
"parent": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"assets_amount": 6,
"is_asset": False
},
{
"id": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"key": "0:11",
"value": "网域测试",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_amount": 6,
"is_asset": False
}
],
"platform": "Linux",
"comment": ""
},
{
"id": "27e50edc-52d9-41ef-8c9e-1bff9d1628b2",
"hostname": "test-vm2",
"ip": "172.19.185.7",
"port": 22,
"system_users_granted": [
{
"id": "7e326f71-aee5-4688-8cc1-717919470a09",
"name": "root",
"username": "root",
"priority": 10,
"protocol": "ssh",
"comment": ""
},
{
"id": "17f384f4-683d-4944-a38d-db73608b92a9",
"name": "zbh-test",
"username": "zbh",
"priority": 10,
"protocol": "ssh",
"comment": ""
}
],
"is_active": True,
"system_users_join": "root, zbh",
"os": "",
"domain": "8789580f-b5ca-4478-b6d3-d0dafc4c48e8",
"nodes": [
{
"id": "67f92d6c-0f91-4d20-a0e4-ac83b7dd02b6",
"key": "0:11:77",
"value": "新节点 12",
"parent": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"assets_amount": 6,
"is_asset": False
},
{
"id": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"key": "0:11",
"value": "网域测试",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_amount": 6,
"is_asset": False
}
],
"platform": "Linux",
"comment": ""
},
{
"id": "9ef36bb3-1bed-455f-be09-3770d3f4bf97",
"hostname": "test-vm1",
"ip": "172.19.185.6",
"port": 22,
"system_users_granted": [
{
"id": "7e326f71-aee5-4688-8cc1-717919470a09",
"name": "root",
"username": "root",
"priority": 10,
"protocol": "ssh",
"comment": ""
},
{
"id": "17f384f4-683d-4944-a38d-db73608b92a9",
"name": "zbh-test",
"username": "zbh",
"priority": 10,
"protocol": "ssh",
"comment": ""
}
],
"is_active": True,
"system_users_join": "root, zbh",
"os": "",
"domain": "8789580f-b5ca-4478-b6d3-d0dafc4c48e8",
"nodes": [
{
"id": "67f92d6c-0f91-4d20-a0e4-ac83b7dd02b6",
"key": "0:11:77",
"value": "新节点 12",
"parent": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"assets_amount": 6,
"is_asset": False
},
{
"id": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"key": "0:11",
"value": "网域测试",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_amount": 6,
"is_asset": False
}
],
"platform": "Linux",
"comment": ""
}
],
"assets_amount": 5
},
{
"id": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"key": "0",
"name": "Fit2cloud",
"value": "Fit2cloud",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_granted": [
{
"id": "b952a481-a624-467e-b97f-9435155f0d53",
"hostname": "testserver",
"ip": "10.1.10.192",
"port": 22,
"system_users_granted": [
{
"id": "7e326f71-aee5-4688-8cc1-717919470a09",
"name": "root",
"username": "root",
"priority": 10,
"protocol": "ssh",
"comment": ""
},
{
"id": "17f384f4-683d-4944-a38d-db73608b92a9",
"name": "zbh-test",
"username": "zbh",
"priority": 10,
"protocol": "ssh",
"comment": ""
}
],
"is_active": True,
"system_users_join": "root, zbh",
"os": "CentOS",
"domain": "",
"nodes": [
{
"id": "67f92d6c-0f91-4d20-a0e4-ac83b7dd02b6",
"key": "0:11:77",
"value": "新节点 12",
"parent": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"assets_amount": 6,
"is_asset": False
},
{
"id": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"key": "0:11",
"value": "网域测试",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_amount": 6,
"is_asset": False
},
{
"id": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"key": "0",
"value": "Fit2cloud",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_amount": 6,
"is_asset": False
}
],
"platform": "Linux",
"comment": ""
},
{
"id": "ad594b10-9f64-4913-b7b1-135fe63561d1",
"hostname": "ali-windows",
"ip": "47.104.206.228",
"port": 3389,
"system_users_granted": [
{
"id": "8763b81a-bb5e-484a-abca-10514c7bb185",
"name": "组织1-部门1-Administrator",
"username": "Administrator",
"priority": 10,
"protocol": "rdp",
"comment": ""
}
],
"is_active": True,
"system_users_join": "Administrator",
"os": "",
"domain": "",
"nodes": [
{
"id": "67f92d6c-0f91-4d20-a0e4-ac83b7dd02b6",
"key": "0:11:77",
"value": "新节点 12",
"parent": "9c83d432-a353-4a4e-9fd9-be27a5851c2d",
"assets_amount": 6,
"is_asset": False
},
{
"id": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"key": "0",
"value": "Fit2cloud",
"parent": "be9d9c3a-68d0-40ec-887c-5815d68e2f2c",
"assets_amount": 6,
"is_asset": False
}
],
"platform": "Windows",
"comment": ""
}
],
"assets_amount": 2
}
]
return jsonify(assets)
@app.route('/api/users/v1/profile/')
def user_profile():
assets = {
"id": "4fc67feb-9efa-4e7b-94b0-b73356a87b2e",
"username": "admin",
"name": "Administrator",
"email": "admin@mycomany.com",
"is_active": True,
"is_superuser": True,
"role": "Administrator",
"groups": [
"Default"
],
"wechat": "",
"phone": 13888888888,
"comment": "",
"date_expired": "2087-12-16 07:41:35"
}
return jsonify(assets)
node = json.loads(nodes)
return jsonify(node)
@app.route('/api/terminal/v1/sessions/test/replay/')
def replay():
return redirect("http://jps.ilz.me/media/2017-12-24/ec87a486-0344-4f12-b27a-620321944f7f.gz")
return redirect(
"http://jps.ilz.me/media/2017-12-24/ec87a486-0344-4f12-b27a-620321944f7f.gz")
@app.route('/api/terminal/v2/sessions/<pk>/replay/')
......@@ -887,9 +174,9 @@ def get_session_replay(pk):
# 'status': 'DONE'
# })
return jsonify({
'type': 'json',
'src': 'http://localhost/media/2018-05-02/dbd5302d-7861-4810-b555-5fe71e26ccc3.gz',
'status': 'DONE',
'type': 'json',
'src': 'http://localhost/media/2018-05-02/dbd5302d-7861-4810-b555-5fe71e26ccc3.gz',
'status': 'DONE',
})
......@@ -904,7 +191,6 @@ def read_file(filename, charset='utf-8'):
if __name__ == '__main__':
async_mode = 'threading'
socketio = SocketIO(app, async_mode=async_mode)
socketio.on_namespace(SSHws('/ssh'))
socketio.run(app, debug=True)
socketio.run(app, port=5001)
......@@ -4,7 +4,7 @@
"license": "GPLv3",
"scripts": {
"ng": "ng",
"start": "ng serve --proxy-config proxy.conf.json",
"start": "ng serve --proxy-config proxy.conf.json --host 0.0.0.0",
"build": "ng build --environment prod --aot --prod --base-href=/luna/ --deploy '/luna/'",
"test": "ng test",
"lint": "ng lint",
......@@ -25,6 +25,7 @@
"@angular/router": "5.2.0",
"@swimlane/ngx-datatable": "^11.3.2",
"@swimlane/ngx-ui": "^20.2.1",
"@types/socket.io-client": "^1.4.32",
"ajv": "^6.5.0",
"animate.css": "^3.6.1",
"body-parser": "^1.18.2",
......
{
"/api": {
"target": "http://127.0.0.1:5000",
"target": "http://127.0.0.1:5001",
"secure": false
},
"/luna/i18n": {
"target": "http://127.0.0.1:8088",
"target": "http://127.0.0.1:5001",
"secure": false
},
"/socket.io/": {
"target": "http://127.0.0.1:5000",
"secure": false
"target": "http://127.0.0.1:5001",
"secure": false,
"ws": true
},
"/rdp/socket.io/": {
"target": "http://localhost:9250",
......
import {Component, Input, OnInit, Inject, SimpleChanges, OnChanges} from '@angular/core';
import {Component, Input, OnInit, Inject, SimpleChanges, OnChanges, EventEmitter} from '@angular/core';
import {NavList, View} from '../../pages/control/control/control.component';
import {AppService, LogService} from '../../app.service';
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material';
import {FormControl, Validators} from '@angular/forms';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
declare var $: any;
......@@ -14,6 +15,7 @@ declare var $: any;
export class ElementAssetTreeComponent implements OnInit, OnChanges {
@Input() Data: any;
@Input() query: string;
@Input() searchEvt$: BehaviorSubject<string>;
nodes = [];
setting = {
view: {
......@@ -30,6 +32,7 @@ export class ElementAssetTreeComponent implements OnInit, OnChanges {
},
};
hiddenNodes: any;
expandNodes: any;
onCzTreeOnClick(event, treeId, treeNode, clickFlag) {
if (treeNode.isParent) {
......@@ -43,12 +46,19 @@ export class ElementAssetTreeComponent implements OnInit, OnChanges {
constructor(private _appService: AppService,
public _dialog: MatDialog,
public _logger: LogService) {
this.searchEvt$ = new BehaviorSubject<string>(this.query);
}
ngOnInit() {
if (this.Data) {
this.draw();
}
this.searchEvt$.asObservable()
.debounceTime(300)
.distinctUntilChanged()
.subscribe((n) => {
this.filter();
});
}
ngOnChanges(changes: SimpleChanges) {
......@@ -56,7 +66,8 @@ export class ElementAssetTreeComponent implements OnInit, OnChanges {
this.draw();
}
if (changes['query'] && !changes['query'].firstChange) {
this.filter();
this.searchEvt$.next(this.query);
// this.filter();
}
}
......@@ -98,8 +109,11 @@ export class ElementAssetTreeComponent implements OnInit, OnChanges {
this.nodes.sort(function(node1, node2) {
if (node1.isParent && !node2.isParent) {
return -1;
} else if (!node1.isParent && node2.isParent) {
return 1;
} else {
return node1.name < node2.name ? -1 : 1;
}
return node1.name < node2.name ? -1 : 1;
});
$.fn.zTree.init($('#ztree'), this.setting, this.nodes);
}
......@@ -174,25 +188,72 @@ export class ElementAssetTreeComponent implements OnInit, OnChanges {
return user;
}
filter() {
const zTreeObj = $.fn.zTree.getZTreeObj('ztree');
const _keywords = $('#keyword').val();
zTreeObj.showNodes(this.hiddenNodes);
recurseParent(node) {
const parentNode = node.getParentNode();
if (parentNode && parentNode.pId) {
return [parentNode, ...this.recurseParent(parentNode)];
} else if (parentNode) {
return [parentNode];
} else {
return [];
}
}
function filterFunc(node) {
if (node.isParent || node.name.indexOf(_keywords) !== -1) {
return false;
}
return true;
recurseChildren(node) {
if (!node.isParent) {
return [];
}
const children = node.children;
if (!children) {
return [];
}
let all_children = [];
children.forEach((n) => {
all_children = [...children, ...this.recurseChildren(n)];
});
return all_children;
}
this.hiddenNodes = zTreeObj.getNodesByFilter(filterFunc);
zTreeObj.hideNodes(this.hiddenNodes);
if (_keywords) {
zTreeObj.expandAll(true);
} else {
zTreeObj.expandAll(false);
filter() {
const zTreeObj = $.fn.zTree.getZTreeObj('ztree');
if (!zTreeObj) {
return null;
}
const _keywords = this.query;
const nodes = zTreeObj.transformToArray(zTreeObj.getNodes());
if (!_keywords) {
if (this.hiddenNodes) {
zTreeObj.showNodes(this.hiddenNodes);
this.hiddenNodes = null;
}
if (this.expandNodes) {
this.expandNodes.forEach((node) => {
if (node.id !== nodes[0].id) {
zTreeObj.expandNode(node, false);
}
});
this.expandNodes = null;
}
return null;
}
let shouldShow = [];
nodes.forEach((node) => {
if (shouldShow.indexOf(node) === -1 && node.name.indexOf(_keywords) !== -1) {
const parents = this.recurseParent(node);
const children = this.recurseChildren(node);
shouldShow = [...shouldShow, ...parents, ...children, node];
}
});
this.hiddenNodes = nodes;
this.expandNodes = shouldShow;
zTreeObj.hideNodes(nodes);
zTreeObj.showNodes(shouldShow);
shouldShow.forEach((node) => {
if (node.isParent) {
zTreeObj.expandNode(node, true);
}
});
// zTreeObj.expandAll(true);
}
}
......
......@@ -34,9 +34,6 @@ export class ElementSshTermComponent implements OnInit, AfterViewInit {
background: '#1f1b1b'
}
});
const rowInit = parseInt(this._cookie.get('rows') || '24', 10);
const colsInit = parseInt(this._cookie.get('cols') || '80', 10);
this.term.resize(colsInit, rowInit);
}
ngAfterViewInit() {
......@@ -49,11 +46,21 @@ export class ElementSshTermComponent implements OnInit, AfterViewInit {
joinRoom() {
NavList.List[this.index].Term = this.term;
console.log(this.term);
console.log('Col: ', this.term.cols, 'rows', this.term.rows);
if (this.host) {
ws.emit('host', {'uuid': this.host.id, 'userid': this.userid, 'secret': this.secret});
ws.emit('host', {
'uuid': this.host.id,
'userid': this.userid,
'secret': this.secret,
'size': [this.term.cols, this.term.rows]
});
}
if (this.token) {
ws.emit('token', {'token': this.token, 'secret': this.secret});
ws.emit('token', {
'token': this.token, 'secret': this.secret,
'size': [this.term.cols, this.term.rows]
});
}
const that = this;
......
......@@ -20,6 +20,7 @@ import {NavList} from '../../pages/control/control/control.component';
export class ElementTermComponent implements OnInit, AfterViewInit {
@ViewChild('term') el: ElementRef;
@Input() term: Terminal;
@Input() offset: Array<number>;
@Output() winSizeChangeTrigger = new EventEmitter<Array<number>>();
winSizeChange$: Observable<any>;
......@@ -33,7 +34,7 @@ export class ElementTermComponent implements OnInit, AfterViewInit {
this.winSizeChange$
.subscribe(() => {
if (NavList.List[NavList.Active].type === 'ssh') {
if (NavList.List[NavList.Active].type !== 'rdp') {
this.resizeTerm();
}
});
......@@ -62,15 +63,10 @@ export class ElementTermComponent implements OnInit, AfterViewInit {
Math.floor(availableHeight / (<any>this.term).renderer.dimensions.actualCellHeight) - 1
];
return geometry;
// const cols = Math.floor((activeEle.width() - 15) / markerEle.width() * 6) - 1;
// const rows = Math.floor(activeEle.height() / markerEle.height()) - 1;
// return [cols, rows];
}
resizeTerm() {
const size = this.getWinSize();
console.log('get SIze', size);
if (isNaN(size[0]) || isNaN(size[1])) {
fit(this.term);
} else {
......@@ -78,8 +74,6 @@ export class ElementTermComponent implements OnInit, AfterViewInit {
this.term.resize(size[0], size[1]);
}
this.winSizeChangeTrigger.emit([this.term.cols, this.term.rows]);
this._cookie.set('cols', this.term.cols.toString(), 0, '/', document.domain);
this._cookie.set('rows', this.term.rows.toString(), 0, '/', document.domain);
}
active() {
......
<div class="sidebar" fxLayout="column" ngxSplit="column">
<div fxflex="0 0 30px" class="search">
<input id="keyword" class="left-search" placeholder=" {{'Search'| trans }} ..." maxlength="2048" name="q"
<input #keyword id="keyword" class="left-search" placeholder=" {{'Search'| trans }} ..." maxlength="2048" name="q"
autocomplete="off"
title="Search"
type="text" tabindex="1" spellcheck="false" autofocus [(ngModel)]="q" (keyup.enter)="Search(q)">
type="text" tabindex="1" spellcheck="false" [(ngModel)]="q">
</div>
<div class="overflow ngx-scroll-overlay" fxflex="1 1 90%">
<elements-asset-tree [Data]="zNodes" [query]="q"></elements-asset-tree>
......
......@@ -7,7 +7,7 @@
* @author liuzheng <liuzheng712@gmail.com>
*/
import {Component, Inject, OnInit} from '@angular/core';
import {Component, Inject, OnInit, ViewChild, ElementRef} from '@angular/core';
import {AppService, HttpService, LogService} from '../../../app.service';
import {SearchComponent} from '../search/search.component';
import {DataStore} from '../../../globals';
......@@ -17,6 +17,7 @@ import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material';
import {FormControl, Validators} from '@angular/forms';
import {ElementServerMenuComponent} from '../../../elements/server-menu/server-menu.component';
import {DialogService} from '../../../elements/dialog/dialog.service';
import {Observable} from '../../../../../node_modules/rxjs';
export interface HostGroup {
name: string;
......@@ -102,7 +103,6 @@ export class CleftbarComponent implements OnInit {
});
}
Search(q) {
this._search.Search(q);
}
......
......@@ -44,7 +44,8 @@
font-family: 'Roboto', sans-serif;
font-size: 13px;
text-decoration: none;
padding-left: 24px;
padding-left: 12px;
padding-right: 14px;
line-height: 26px;
cursor: default;
width: 115px;
......@@ -68,7 +69,7 @@
}
.tabs ul li.active span {
padding-left: 24px;
padding-left: 12px;
line-height: 26px;
color: white;
height: 18px;
......
......@@ -7,7 +7,7 @@
<li *ngFor="let m of NavList.List;let i = index"
[ngClass]="{'active':i==NavList.Active,'disconnected':!m.connected, 'hidden': m.closed != false}"
id="termnav-{{i}}" (click)="setActive(i)" (dblclick)="m.edit=true;setActive(i)">
<span *ngIf="!m.edit">{{m.nick}}</span>
<span *ngIf="!m.edit">{{m.nick | truncatechars:25 }}</span>
<input *ngIf="m.edit" [(ngModel)]="m.nick" (blur)="m.edit=false" (keyup.enter)="m.edit=false" autofocus="true"/>
<a class="close" (click)="close(m,i)">&times;</a>
</li>
......
......@@ -11,13 +11,40 @@ function zeroPad(num, minLength) {
return str;
}
function formatTimeWithSeconds(seconds) {
let hour = 0, minute = 0, second = 0;
const ref = [3600, 60, 1];
for (let i = 0; i < ref.length; i++) {
const val = ref[i];
while (val <= seconds) {
seconds -= val;
switch (i) {
case 0:
hour++;
break;
case 1:
minute++;
break;
case 2:
second++;
break;
}
}
}
return [hour, minute, second];
}
function formatTime(millis: number) {
const totalSeconds = Math.floor(millis / 1000);
const seconds = totalSeconds % 60;
const minutes = Math.floor(totalSeconds / 60);
return zeroPad(minutes, 2) + ':' + zeroPad(seconds, 2);
const totalSeconds = millis / 1000;
const [hour, minute, second] = formatTimeWithSeconds(totalSeconds);
let time = zeroPad(minute, 2) + ':' + zeroPad(second, 2);
if (hour > 0) {
time = zeroPad(hour, 2) + ':' + time;
}
return time;
}
@Component({
selector: 'app-replay-guacamole',
templateUrl: './guacamole.component.html',
......@@ -115,6 +142,4 @@ export class ReplayGuacamoleComponent implements OnInit {
this.isPlaying = false;
}
}
}
<div>
<!--<button type="button" class="btn">-->
<!--<i class="fa fa-stop" aria-hidden="true"></i>-->
<!--</button>-->
<!--<button type="button" class="btn">-->
<!--<i class="fa fa-step-backward" aria-hidden="true"></i>-->
<!--</button>-->
<button type="button" class="btn">
<i class="fa fa-backward" aria-hidden="true" (click)="speedDown()"></i>
</button>
<button type="button" class="btn" (click)="toggle()">
<i class="fa" aria-hidden="true" [ngClass]="{'fa-play':!play,'fa-pause': play}"></i>
<i class="fa" aria-hidden="true" [ngClass]="{'fa-play':!isPlaying, 'fa-pause': isPlaying}"></i>
</button>
<button type="button" class="btn" (click)="speedUp()">
<i class="fa fa-forward" aria-hidden="true"></i>
</button>
<!--<button type="button" class="btn">-->
<!--<i class="fa fa-step-forward" aria-hidden="true"></i>-->
<!--</button>-->
<!--<button type="button" class="btn">-->
<!--<i class="fa fa-expand" aria-hidden="true"></i>-->
<!--</button>-->
<!--<button type="button" class="btn">-->
<!--<i class="fa fa-compress" aria-hidden="true"></i>-->
<!--</button>-->
<button type="button" class="btn" (click)="restart()">
<i class="fa fa-repeat" aria-hidden="true"></i>
</button>
<input id="scrubber" type="range" [(ngModel)]="percent" min=0 max=100 (mousedown)="stop()" (mouseup)="runFrom()"/>
<input id="scrubber" type="range" [(ngModel)]="time" min=0 [attr.max]="max" (mouseup)="runFrom()"/>
{{time | utcDate | date:"HH:mm:ss"}}
<span id="position">{{ position }}</span>
<span>/</span>
<span id="duration">{{ duration }}</span>
{{"Speed"|trans}}: {{speed}}
</div>
<elements-term [term]="term"></elements-term>
<div id="winContainer" style="height: 90%;width: 100%">
<elements-term [term]="term"></elements-term>
</div>
<!--<asciinema-player></asciinema-player>-->
......@@ -3,23 +3,75 @@ import {Terminal} from 'xterm';
import {HttpService, LogService} from '../../../app.service';
import {Replay} from '../replay.model';
function zeroPad(num, minLength) {
let str = num.toString();
// Add leading zeroes until string is long enough
while (str.length < minLength) {
str = '0' + str;
}
return str;
}
function formatTimeWithSeconds(seconds) {
let hour = 0, minute = 0, second = 0;
const ref = [3600, 60, 1];
for (let i = 0; i < ref.length; i++) {
const val = ref[i];
while (val <= seconds) {
seconds -= val;
switch (i) {
case 0:
hour++;
break;
case 1:
minute++;
break;
case 2:
second++;
break;
}
}
}
return [hour, minute, second];
}
function formatTime(millis: number) {
const totalSeconds = millis / 1000;
const [hour, minute, second] = formatTimeWithSeconds(totalSeconds);
let time = zeroPad(minute, 2) + ':' + zeroPad(second, 2);
if (hour > 0) {
time = zeroPad(hour, 2) + ':' + time;
}
return time;
}
@Component({
selector: 'app-replay-json',
templateUrl: './json.component.html',
styleUrls: ['./json.component.css']
})
export class JsonComponent implements OnInit {
isPlaying = false;
recording: any;
playerRef: any;
displayRef: any;
max = 0;
time = 0;
duration = '00:00';
timeList = [];
replayData = {};
speed = 2;
percent = 0;
play = false;
tick = 33;
timeStep = 33;
time = 1;
tick = 33; // 每33s滴答一次
timeStep = 33; // 步长
timer: any; // 多长时间播放下一个
pos = 0; // 播放点
scrubber: number;
term: Terminal;
get position() {
return formatTime(this.time);
}
set position(data) {
}
@Input() replay: Replay;
constructor(private _http: HttpService) {}
......@@ -37,12 +89,13 @@ export class JsonComponent implements OnInit {
this._http.get_replay_data(this.replay.src)
.subscribe(
data => {
this.replay.json = data;
this.replay.timelist = Object.keys(this.replay.json).map(Number);
this.replay.timelist = this.replay.timelist.sort((a, b) => {
this.replayData = data;
this.timeList = Object.keys(this.replayData).map(Number);
this.timeList = this.timeList.sort((a, b) => {
return a - b;
});
this.replay.totalTime = this.replay.timelist[this.replay.timelist.length - 1] * 1000;
this.max = this.timeList[this.timeList.length - 1] * 1000;
this.duration = formatTime(this.max);
this.toggle();
},
err => {
......@@ -56,55 +109,48 @@ export class JsonComponent implements OnInit {
restart() {
clearInterval(this.timer);
this.term.reset();
this.time = 1;
this.pos = 0;
this.play = true;
this.isPlaying = true;
this.timer = setInterval(() => {
this.advance();
}, this.tick);
}
toggle() {
if (this.play) {
if (this.isPlaying) {
clearInterval(this.timer);
this.play = !this.play;
this.isPlaying = !this.isPlaying;
} else {
this.timer = setInterval(() => {
this.advance();
}, this.tick);
this.play = !this.play;
this.isPlaying = !this.isPlaying;
}
}
advance() {
// 每个time间隔执行一次
// this.scrubber = Math.ceil((this.time / this.replay.totalTime) * 100);
for (; this.pos < this.replay.timelist.length; this.pos++) {
if (this.replay.timelist[this.pos] * 1000 <= this.time) {
this.term.write(this.replay.json[this.replay.timelist[this.pos].toString()]);
// for (let i in this.timeList) {
// }
for (; this.pos < this.timeList.length; this.pos++) {
if (this.timeList[this.pos] * 1000 <= this.time) {
this.term.write(this.replayData[this.timeList[this.pos].toString()]);
} else {
break;
}
}
// 超过了总的时间点, 停止播放
if (this.pos >= this.replay.timelist.length) {
this.play = !this.play;
if (this.pos >= this.timeList.length) {
this.isPlaying = !this.isPlaying;
clearInterval(this.timer);
}
// 如果两次时间间隔超过了5s
if (this.replay.timelist[this.pos] - this.replay.timelist[this.pos - 1] > 5) {
this.time += 5000;
}
this.time += this.timeStep * this.speed;
this.percent = this.time / this.replay.totalTime * 100;
}
stop() {
clearInterval(this.timer);
this.play = false;
this.isPlaying = false;
}
speedUp() {
......@@ -116,31 +162,15 @@ export class JsonComponent implements OnInit {
}
runFrom() {
clearInterval(this.timer);
const time = this.replay.totalTime * this.percent / 100;
this.replay.timelist.forEach((v, i) => {
const preTime = this.replay.timelist[i - 1];
if (time <= v * 1000 && time >= preTime * 1000) {
for (let i = 0; i < this.timeList.length; i++) {
const v = this.timeList[i];
const preTime = this.timeList[i - 1];
if (this.time <= v * 1000 && this.time >= preTime * 1000) {
this.time = v * 1000;
this.pos = i;
return;
break;
}
});
this.timer = setInterval(() => {
this.advance();
}, this.tick);
this.play = !this.play;
}
this.advance();
}
// this.pos = 0;
// this.term.reset();
// this.play = false;
// for (; this.pos < this.replay.timelist.length; this.pos++) {
// if (this.replay.timelist[this.pos] * 1000 <= this.percent / 100 * this.replay.totalTime) {
// this.term.term.write(this.replay.json[this.replay.timelist[this.pos].toString()]);
// } else {
// break;
// }
// }
// this.time = this.replay.totalTime * this.percent / 100;
// }
}
import {TransPipe} from './trans.pipe';
import {UtcDatePipe} from './date.pipe';
import {TruncatecharsPipe} from './truncatechars.pipe';
export const Pipes = [
UtcDatePipe,
TransPipe
TransPipe,
TruncatecharsPipe
];
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({name: 'truncatechars'})
export class TruncatecharsPipe implements PipeTransform {
transform(value: string, length: number): string {
if (!value) {
return value;
}
if (value.length < length) {
return value;
}
return value.slice(0, length) + '..';
}
}
......@@ -9,6 +9,7 @@
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es5",
"importHelpers": true,
"typeRoots": [
"node_modules/@types"
],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment