Merge with webternimal

pull/530/head
ibuler 2016-08-24 00:12:46 +08:00
commit bbecbc8578
11 changed files with 275 additions and 8 deletions

1
.gitignore vendored
View File

@ -14,3 +14,4 @@ migrations/
.idea/ .idea/
db.sqlite3 db.sqlite3
config.py config.py
*/migrations/*

View File

@ -13,7 +13,6 @@ https://docs.djangoproject.com/en/1.10/ref/settings/
import os import os
import sys import sys
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@ -22,11 +21,11 @@ sys.path.append(os.path.dirname(BASE_DIR))
# Import project config setting # Import project config setting
try: try:
from config import config as env_config, env from config import config as env_config, env
CONFIG = env_config.get(env, 'default')() CONFIG = env_config.get(env, 'default')()
except ImportError: except ImportError:
CONFIG = type('_', (), {'__getattr__': None})() CONFIG = type('_', (), {'__getattr__': None})()
# Quick-start development settings - unsuitable for production # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
@ -38,13 +37,13 @@ DEBUG = CONFIG.DEBUG or False
ALLOWED_HOSTS = CONFIG.ALLOWED_HOSTS or [] ALLOWED_HOSTS = CONFIG.ALLOWED_HOSTS or []
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
'users.apps.UsersConfig', 'users.apps.UsersConfig',
'assets.apps.AssetsConfig', 'assets.apps.AssetsConfig',
'perms.apps.PermsConfig', 'perms.apps.PermsConfig',
'webterminal.apps.WebterminalConfig',
'ops.apps.OpsConfig', 'ops.apps.OpsConfig',
'audits.apps.AuditsConfig', 'audits.apps.AuditsConfig',
'common.apps.CommonConfig', 'common.apps.CommonConfig',
@ -56,6 +55,8 @@ INSTALLED_APPS = [
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'ws4redis',
] ]
MIDDLEWARE = [ MIDDLEWARE = [
@ -81,6 +82,9 @@ TEMPLATES = [
'django.template.context_processors.request', 'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth', 'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'django.template.context_processors.static',
'django.template.context_processors.request',
'ws4redis.context_processors.default',
], ],
}, },
}, },
@ -88,7 +92,6 @@ TEMPLATES = [
WSGI_APPLICATION = 'jumpserver.wsgi.application' WSGI_APPLICATION = 'jumpserver.wsgi.application'
# Database # Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases # https://docs.djangoproject.com/en/1.10/ref/settings/#databases
@ -111,7 +114,6 @@ else:
} }
} }
# Password validation # Password validation
# https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
@ -130,7 +132,6 @@ AUTH_PASSWORD_VALIDATORS = [
}, },
] ]
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/ # https://docs.djangoproject.com/en/1.10/topics/i18n/
@ -144,7 +145,6 @@ USE_L10N = True
USE_TZ = True USE_TZ = True
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/ # https://docs.djangoproject.com/en/1.10/howto/static-files/
@ -176,3 +176,26 @@ REST_FRAMEWORK = {
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly' 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
], ],
} }
# This setting is required to override the Django's main loop, when running in
# development mode, such as ./manage runserver
WSGI_APPLICATION = 'ws4redis.django_runserver.application'
# URL that distinguishes websocket connections from normal requests
WEBSOCKET_URL = '/ws/'
# WebSocket Redis
WS4REDIS_CONNECTION = {
'host': '127.0.0.1',
'port': 6379,
'db': 2,
}
# Set the number of seconds each message shall persited
WS4REDIS_EXPIRE = 3600
WS4REDIS_HEARTBEAT = 'love you'
WS4REDIS_PREFIX = 'demo'
SESSION_ENGINE = 'redis_sessions.session'
SESSION_REDIS_PREFIX = 'session'

View File

@ -17,11 +17,21 @@ from django.conf.urls import url, include
from django.conf import settings from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.http import HttpResponseRedirect
def view(request, **kwargs):
if kwargs:
print kwargs
return HttpResponseRedirect('/' + kwargs["module"] + '/' + kwargs["version"] + '/' + kwargs["api"])
urlpatterns = [ urlpatterns = [
url(r'^$', TemplateView.as_view(template_name='base.html')), url(r'^$', TemplateView.as_view(template_name='base.html')),
url(r'^users/', include('users.urls')), url(r'^users/', include('users.urls')),
url(r'^assets/', include('assets.urls')), url(r'^assets/', include('assets.urls')),
url(r'^terminal/', include('webterminal.urls')),
url(r'^api/(?P<version>.*)/(?P<module>.*)/(?P<api>.*)', view),
# url(r'^admin/', admin.site.urls), # url(r'^admin/', admin.site.urls),
] ]

View File

View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

7
apps/webterminal/apps.py Normal file
View File

@ -0,0 +1,7 @@
from __future__ import unicode_literals
from django.apps import AppConfig
class WebterminalConfig(AppConfig):
name = 'webterminal'

View File

@ -0,0 +1,5 @@
from __future__ import unicode_literals
from django.db import models
# Create your models here.

View File

@ -0,0 +1,176 @@
{% extends 'base.html' %}
{% block content %}
<div class="container">
<div id="term">
</div>
</div>
<div class="termChangBar">
<input type="number" min="100" value="100" placeholder="col" id="term-col"/>
<input type="number" min="35" value="35" placeholder="row" id="term-row"/>
<button id="col-row">修改窗口大小</button>
</div>
{% endblock %}
{% block custom_foot_js %}
<script type="application/javascript" src="/static/js/jquery-2.1.1.js"></script>
<script type="application/javascript" src="/static/js/term.js"></script>
<script>/**
* Created by liuzheng on 3/3/16.
*/
var rowHeight = 1;
var colWidth = 1;
function WSSHClient() {
}
WSSHClient.prototype._generateEndpoint = function (options) {
console.log(options);
if (window.location.protocol == 'https:') {
var protocol = 'wss://';
} else {
var protocol = 'ws://';
}
var endpoint = protocol + document.URL.match(RegExp('//(.*?)/'))[1] + '/ws/foobar?subscribe-broadcast&publish-broadcast&echo';
return endpoint;
};
WSSHClient.prototype.connect = function (options) {
var endpoint = this._generateEndpoint(options);
if (window.WebSocket) {
this._connection = new WebSocket(endpoint);
}
else if (window.MozWebSocket) {
this._connection = MozWebSocket(endpoint);
}
else {
options.onError('WebSocket Not Supported');
return;
}
this._connection.onopen = function () {
options.onConnect();
};
this._connection.onmessage = function (evt) {
try {
options.onData(evt.data);
} catch (e) {
var data = JSON.parse(evt.data.toString());
options.onError(data.error);
}
};
this._connection.onclose = function (evt) {
options.onClose();
};
};
WSSHClient.prototype.send = function (data) {
this._connection.send(JSON.stringify({'data': data}));
};
function openTerminal(options) {
var client = new WSSHClient();
var rowHeight, colWidth;
try {
rowHeight = localStorage.getItem('term-row');
colWidth = localStorage.getItem('term-col');
} catch (err) {
rowHeight = 35;
colWidth = 100
}
if (rowHeight) {
} else {
rowHeight = 35
}
if (colWidth) {
} else {
colWidth = 100
}
var term = new Terminal({
rows: rowHeight,
cols: colWidth,
useStyle: true,
screenKeys: true
});
term.open();
term.on('data', function (data) {
client.send(data)
});
$('.terminal').detach().appendTo('#term');
//term.resize(colWidth, rowHeight);
term.write('Connecting...');
client.connect($.extend(options, {
onError: function (error) {
term.write('Error: ' + error + '\r\n');
},
onConnect: function () {
// Erase our connecting message
client.send({'resize': {'rows': rowHeight, 'cols': colWidth}});
term.write('\r');
},
onClose: function () {
term.write('Connection Reset By Peer');
},
onData: function (data) {
if (data == "love you")
console.log(data);
else
term.write(data);
}
}));
//rowHeight = 0.0 + 1.00 * $('.terminal').height() / 24;
//colWidth = 0.0 + 1.00 * $('.terminal').width() / 80;
return {'term': term, 'client': client};
}
//function resize() {
// $('.terminal').css('width', window.innerWidth - 25);
// console.log(window.innerWidth);
// console.log(window.innerWidth - 10);
// var rows = Math.floor(window.innerHeight / rowHeight) - 2;
// var cols = Math.floor(window.innerWidth / colWidth) - 1;
//
// return {rows: rows, cols: cols};
//}
$(document).ready(function () {
var options = {};
$('#ssh').show();
var term_client = openTerminal(options);
console.log(rowHeight);
// by liuzheng712 because it will bring record bug
//window.onresize = function () {
// var geom = resize();
// console.log(geom);
// term_client.term.resize(geom.cols, geom.rows);
// term_client.client.send({'resize': {'rows': geom.rows, 'cols': geom.cols}});
// $('#ssh').show();
//}
try {
$('#term-row')[0].value = localStorage.getItem('term-row');
$('#term-col')[0].value = localStorage.getItem('term-col');
} catch (err) {
$('#term-row')[0].value = 35;
$('#term-col')[0].value = 100;
}
$('#col-row').click(function () {
var col = $('#term-col').val();
var row = $('#term-row').val();
localStorage.setItem('term-col', col);
localStorage.setItem('term-row', row);
term_client.term.resize(col, row);
term_client.client.send({'resize': {'rows': row, 'cols': col}});
$('#ssh').show();
});
$(".terminal").mouseleave(function () {
$(".termChangBar").slideDown();
});
$(".terminal").mouseenter(function () {
$(".termChangBar").slideUp();
})
});</script>
{% endblock %}

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

11
apps/webterminal/urls.py Normal file
View File

@ -0,0 +1,11 @@
# coding:utf-8
from django.conf.urls import url
from .views import *
from django.contrib import admin
admin.autodiscover()
app_name = 'webterminal'
urlpatterns = [
url(r'^$', TerminalView.as_view(), name='webterminal'),
]

28
apps/webterminal/views.py Normal file
View File

@ -0,0 +1,28 @@
from django.shortcuts import render
from django.urls import reverse_lazy
from django.db.models import Q
from django.views.generic.list import ListView
from django.views.generic.edit import CreateView, DeleteView, UpdateView
from django.views.generic.detail import DetailView
from django.views.generic.base import TemplateView
from django.views import View
from django.http import HttpResponse
from ws4redis.redis_store import RedisMessage
from ws4redis.publisher import RedisPublisher
from django.conf import settings
# Create your views here.
class TerminalView(TemplateView):
template_name = 'main.html'
def get(self, request, *args, **kwargs):
welcome = RedisMessage('Hello everybody') # create a welcome message to be sent to everybody
RedisPublisher(facility='foobar', broadcast=True).publish_message(welcome)
return super(TerminalView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
redis_publisher = RedisPublisher(facility='foobar', groups=[request.POST.get('group')])
message = RedisMessage(request.POST.get('message'))
redis_publisher.publish_message(message)
return HttpResponse('OK')