This commit is contained in:
yumoqing 2023-09-22 13:53:32 +08:00
parent 03c90f6bbb
commit 7ec7e69f4e
4 changed files with 124 additions and 15 deletions

View File

@ -46,18 +46,20 @@ class ConfiguredServer(AppLogger):
await auth.setupAuth(self.app) await auth.setupAuth(self.app)
return self.app return self.app
def run(self): def run(self, port=None):
config = getConfig() config = getConfig()
self.configPath(config) self.configPath(config)
a = TmpFileRecord() a = TmpFileRecord()
ssl_context = None ssl_context = None
if port is None:
port = config.website.port or 8080
if config.website.ssl: if config.website.ssl:
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_context.load_cert_chain(config.website.ssl.crtfile, ssl_context.load_cert_chain(config.website.ssl.crtfile,
config.website.ssl.keyfile) config.website.ssl.keyfile)
web.run_app(self.init_auth(),host=config.website.host or '0.0.0.0', web.run_app(self.init_auth(),host=config.website.host or '0.0.0.0',
port=config.website.port or 8080, port=port,
ssl_context=ssl_context) ssl_context=ssl_context)
def configPath(self,config): def configPath(self,config):

View File

@ -40,7 +40,7 @@ from appPublic.app_logger import AppLogger
from .baseProcessor import getProcessor from .baseProcessor import getProcessor
from .xlsxdsProcessor import XLSXDataSourceProcessor from .xlsxdsProcessor import XLSXDataSourceProcessor
from .websocketProcessor import WebsocketProcessor from .websocketProcessor import WebsocketProcessor, XtermProcessor
from .sqldsProcessor import SQLDataSourceProcessor from .sqldsProcessor import SQLDataSourceProcessor
from .functionProcessor import FunctionProcessor from .functionProcessor import FunctionProcessor
from .proxyProcessor import ProxyProcessor from .proxyProcessor import ProxyProcessor
@ -253,6 +253,7 @@ class ProcessorResource(AppLogger, StaticResource,Url2File):
self.y_env.i18nDict = i18nDICT self.y_env.i18nDict = i18nDICT
self.y_env.terminalType = getClientType(request) self.y_env.terminalType = getClientType(request)
self.y_env.entire_url = partial(self.entireUrl,request) self.y_env.entire_url = partial(self.entireUrl,request)
self.y_env.websocket_url = partial(self.websocketUrl,request)
self.y_env.abspath = self.abspath self.y_env.abspath = self.abspath
self.y_env.request2ns = getArgs self.y_env.request2ns = getArgs
self.y_env.aiohttp_client = client self.y_env.aiohttp_client = client
@ -367,12 +368,25 @@ class ProcessorResource(AppLogger, StaticResource,Url2File):
for word, handlername in self.y_processors: for word, handlername in self.y_processors:
if fpath.endswith(word): if fpath.endswith(word):
Klass = getProcessor(handlername) Klass = getProcessor(handlername)
try:
processor = Klass(path,self) processor = Klass(path,self)
return processor return processor
except Exception as e:
print('Exception:',e, 'handlername=', handlername)
return None
return None return None
def websocketUrl(self, request, url):
url = entireUrl(request, url)
if url.startswith('https'):
return 'wss' + url[5:]
return 'ws' + url[4:]
def entireUrl(self, request, url): def entireUrl(self, request, url):
if url.startswith('http://') or url.startswith('https://'): if url.startswith('http://') or \
url.startswith('https://') or \
url.startswith('ws://') or \
url.startswith('wss://'):
return url return url
scheme = request.headers.get('X-Forwarded-Scheme') or request.scheme scheme = request.headers.get('X-Forwarded-Scheme') or request.scheme
port = request.headers.get('X-Forwarded-Port') or str(request['port']) port = request.headers.get('X-Forwarded-Port') or str(request['port'])

View File

@ -26,7 +26,10 @@ class Url2File:
if len(url) > 0 and url[-1] == '/': if len(url) > 0 and url[-1] == '/':
url = url[:-1] url = url[:-1]
paths = url.split('/') paths = url.split('/')
if url.startswith('http://') or url.startswith('https://'): if url.startswith('http://') or \
url.startswith('https://') or \
url.startswith('ws://') or \
url.startswith('wss://'):
paths = paths[3:] paths = paths[3:]
f = os.path.join(self.path,*paths) f = os.path.join(self.path,*paths)
real_path = os.path.abspath(f) real_path = os.path.abspath(f)

View File

@ -1,31 +1,121 @@
import asyncio
import aiohttp import aiohttp
import json
import codecs
from aiohttp import web from aiohttp import web
from .baseProcessor import PythonScriptProcessor import aiohttp_cors
from appPublic.sshx import SSHNode
from .baseProcessor import BaseProcessor, PythonScriptProcessor
class XtermProcessor(BaseProcessor):
@classmethod
def isMe(self,name):
return name=='xterm'
async def ws_2_process(self, ws):
async for msg in ws:
if msg.type == aiohttp.WSMsgType.TEXT:
self.p_obj.stdin.write(msg.data)
elif msg.type == aiohttp.WSMsgType.ERROR:
print('ws connection closed with exception %s' % ws.exception())
return
async def process_2_ws(self, ws):
while self.running:
x = await self.p_obj.stdout.read(1024)
await self.ws_sendstr(ws, x)
async def datahandle(self,request):
await self.path_call(request)
async def path_call(self, request, params={}):
await self.set_run_env(request)
lenv = self.run_ns.copy()
lenv.update(params)
del lenv['request']
ws = web.WebSocketResponse()
await ws.prepare(request)
await self.create_process()
self.ws_sendstr(ws, 'Welcom to sshclient')
r1 = self.ws_2_process(ws)
r2 = self.process_2_ws(ws)
await asyncio.gather(r1,r2)
self.retResponse = ws
return ws
def get_login_info(self):
with codecs.open(self.real_path, 'r', 'utf-8') as f:
self.login_info = json.load(f)
print(f'{self.login_info=}')
async def create_process(self):
# id = lenv['params_kw'].get('termid')
self.get_login_info()
host = self.login_info['host']
port = self.login_info.get('port', 22)
username = self.login_info.get('username', 'root')
password = self.login_info.get('password',None)
self.sshnode = SSHNode(host, username=username,
password=password,
port=port)
await self.sshnode.connect()
self.p_obj = await self.sshnode._process('bash',
term_type='vt100',
term_size=(80, 24),
encoding='utf-8')
self.running = True
async def ws_sendstr(self, ws:web.WebSocketResponse, s:str):
data = {
"type":1,
"data":s
}
await ws.send_str(json.dumps(data))
def close_process(self):
self.sshnode.close()
self.p_obj.close()
class WebsocketProcessor(PythonScriptProcessor): class WebsocketProcessor(PythonScriptProcessor):
@classmethod @classmethod
def isMe(self,name): def isMe(self,name):
return name=='ws' return name=='ws'
async def ws_sendstr(self, ws:web.WebSocketResponse, s:str):
data = {
"type":1,
"data":s
}
await ws.send_str(json.dumps(data))
async def path_call(self, request,params={}): async def path_call(self, request,params={}):
print('1----------------------------------')
await self.set_run_env(request) await self.set_run_env(request)
lenv = self.run_ns.copy() lenv = self.run_ns.copy()
lenv.update(params) lenv.update(params)
del lenv['request'] del lenv['request']
print('2----------------------------------')
txt = self.loadScript(self.real_path) txt = self.loadScript(self.real_path)
exec(txt,lenv,lenv) exec(txt,lenv,lenv)
func = lenv['myfunc'] func = lenv['myfunc']
print('3----------------------------------')
ws = web.WebSocketResponse() ws = web.WebSocketResponse()
await ws.prepare(request) await ws.prepare(request)
print('4----------------------------------', aiohttp.WSMsgType.TEXT)
await self.ws_sendstr(ws, 'Welcome to websock')
async for msg in ws: async for msg in ws:
if msg.type == aiohttp/WSMsgType.TEXT: if msg.type == aiohttp.WSMsgType.TEXT:
if msg.data == 'close': print('msg=:', msg)
await ws.close()
else:
lenv['ws_data'] = msg.data lenv['ws_data'] = msg.data
resp = await func(request,**lenv) # resp = await func(request,**lenv)
await ws.send_str(resp) await self.ws_sendstr(ws, msg.data)
print('msg.data=', msg.data)
elif msg.type == aiohttp.WSMsgType.ERROR: elif msg.type == aiohttp.WSMsgType.ERROR:
print('ws connection closed with exception %s' % ws.exception()) print('ws connection closed with exception %s' % ws.exception())
else:
print('datatype error', msg.type)
print('5----------------------------------')
self.retResponse = ws
await ws.close()
return ws return ws