Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
C
coco
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ops
coco
Commits
b5221652
Commit
b5221652
authored
May 18, 2018
by
ibuler
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Update] 优化coco中文显示
parent
0755d134
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
112 additions
and
69 deletions
+112
-69
httpd.py
coco/httpd.py
+8
-18
interactive.py
coco/interactive.py
+49
-31
utils.py
coco/utils.py
+55
-20
No files found.
coco/httpd.py
View file @
b5221652
...
@@ -19,7 +19,6 @@ logger = get_logger(__file__)
...
@@ -19,7 +19,6 @@ logger = get_logger(__file__)
class
BaseNamespace
(
Namespace
):
class
BaseNamespace
(
Namespace
):
clients
=
None
current_user
=
None
current_user
=
None
def
on_connect
(
self
):
def
on_connect
(
self
):
...
@@ -39,12 +38,6 @@ class BaseNamespace(Namespace):
...
@@ -39,12 +38,6 @@ class BaseNamespace(Namespace):
user
=
app_service
.
check_user_with_token
(
token
)
user
=
app_service
.
check_user_with_token
(
token
)
return
user
return
user
def
close
(
self
):
try
:
self
.
clients
[
request
.
sid
][
"client"
]
.
close
()
except
IndexError
:
pass
class
ProxyNamespace
(
BaseNamespace
):
class
ProxyNamespace
(
BaseNamespace
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
...
@@ -235,13 +228,6 @@ class ProxyNamespace(BaseNamespace):
...
@@ -235,13 +228,6 @@ class ProxyNamespace(BaseNamespace):
del
self
.
connections
[
request
.
sid
][
room_id
]
del
self
.
connections
[
request
.
sid
][
room_id
]
del
room
del
room
@staticmethod
def
on_error_default
(
e
):
traceback
.
print_exc
()
logger
.
warn
(
e
)
error_handler
=
on_error_default
class
HttpServer
:
class
HttpServer
:
# prepare may be rewrite it
# prepare may be rewrite it
...
@@ -264,13 +250,17 @@ class HttpServer:
...
@@ -264,13 +250,17 @@ class HttpServer:
self
.
flask_app
.
config
.
update
(
config
)
self
.
flask_app
.
config
.
update
(
config
)
self
.
socket_io
=
SocketIO
()
self
.
socket_io
=
SocketIO
()
self
.
register_routes
()
self
.
register_routes
()
self
.
add_error_handler
()
def
register_routes
(
self
):
def
register_routes
(
self
):
self
.
socket_io
.
on_namespace
(
ProxyNamespace
(
'/ssh'
))
self
.
socket_io
.
on_namespace
(
ProxyNamespace
(
'/ssh'
))
def
add_error_handler
(
self
):
@staticmethod
self
.
socket_io
.
on_error_default
(
ProxyNamespace
.
on_error_default
)
def
on_error_default
(
e
):
traceback
.
print_exc
()
logger
.
warn
(
e
)
def
register_error_handler
(
self
):
self
.
socket_io
.
on_error_default
(
self
.
on_error_default
)
def
run
(
self
):
def
run
(
self
):
host
=
self
.
flask_app
.
config
[
"BIND_HOST"
]
host
=
self
.
flask_app
.
config
[
"BIND_HOST"
]
...
@@ -282,4 +272,4 @@ class HttpServer:
...
@@ -282,4 +272,4 @@ class HttpServer:
self
.
socket_io
.
run
(
self
.
flask_app
,
port
=
port
,
host
=
host
,
debug
=
False
)
self
.
socket_io
.
run
(
self
.
flask_app
,
port
=
port
,
host
=
host
,
debug
=
False
)
def
shutdown
(
self
):
def
shutdown
(
self
):
pass
self
.
socket_io
.
server
.
close
()
coco/interactive.py
View file @
b5221652
...
@@ -12,7 +12,8 @@ from . import char
...
@@ -12,7 +12,8 @@ from . import char
from
.utils
import
wrap_with_line_feed
as
wr
,
wrap_with_title
as
title
,
\
from
.utils
import
wrap_with_line_feed
as
wr
,
wrap_with_title
as
title
,
\
wrap_with_warning
as
warning
,
is_obj_attr_has
,
\
wrap_with_warning
as
warning
,
is_obj_attr_has
,
\
is_obj_attr_eq
,
sort_assets
,
TtyIOParser
,
\
is_obj_attr_eq
,
sort_assets
,
TtyIOParser
,
\
ugettext
as
_
,
get_logger
,
net_input
ugettext
as
_
,
get_logger
,
net_input
,
format_with_zh
,
item_max_length
,
\
size_of_str_with_zh
from
.ctx
import
current_app
,
app_service
from
.ctx
import
current_app
,
app_service
from
.proxy
import
ProxyServer
from
.proxy
import
ProxyServer
...
@@ -56,11 +57,11 @@ class InteractiveServer:
...
@@ -56,11 +57,11 @@ class InteractiveServer:
banner
=
_
(
"""
\n
{title} {user}, 欢迎使用Jumpserver开源跳板机系统 {end}
\r\n\r
banner
=
_
(
"""
\n
{title} {user}, 欢迎使用Jumpserver开源跳板机系统 {end}
\r\n\r
1) 输入 {green}ID{end} 直接登录 或 输入{green}部分 IP,主机名,备注{end} 进行搜索登录(如果唯一).
\r
1) 输入 {green}ID{end} 直接登录 或 输入{green}部分 IP,主机名,备注{end} 进行搜索登录(如果唯一).
\r
2) 输入 {green}/{end} + {green}IP, 主机名{end} or {green}备注 {end}搜索. 如: /ip
\r
2) 输入 {green}/{end} + {green}IP, 主机名{end} or {green}备注 {end}搜索. 如: /ip
\r
3) 输入 {green}
P/
p{end} 显示您有权限的主机.
\r
3) 输入 {green}p{end} 显示您有权限的主机.
\r
4) 输入 {green}
G/
g{end} 显示您有权限的主机组.
\r
4) 输入 {green}g{end} 显示您有权限的主机组.
\r
5) 输入 {green}
G/g{end} + {green}组ID{end} 显示该组
下主机. 如: g1
\r
5) 输入 {green}
g{end} + {green}组ID{end} 显示该节点
下主机. 如: g1
\r
6) 输入 {green}
H/
h{end} 帮助.
\r
6) 输入 {green}h{end} 帮助.
\r
0) 输入 {green}
Q/
q{end} 退出.
\r\n
"""
)
.
format
(
0) 输入 {green}q{end} 退出.
\r\n
"""
)
.
format
(
title
=
"
\033
[1;32m"
,
green
=
"
\033
[32m"
,
title
=
"
\033
[1;32m"
,
green
=
"
\033
[32m"
,
end
=
"
\033
[0m"
,
user
=
self
.
client
.
user
end
=
"
\033
[0m"
,
user
=
self
.
client
.
user
)
)
...
@@ -123,17 +124,25 @@ class InteractiveServer:
...
@@ -123,17 +124,25 @@ class InteractiveServer:
self
.
client
.
send
(
warning
(
_
(
"无"
)))
self
.
client
.
send
(
warning
(
_
(
"无"
)))
return
return
fake_group
=
AssetGroup
(
name
=
_
(
"Name"
),
assets_amount
=
_
(
"Assets"
),
comment
=
_
(
"Comment"
))
id_length
=
max
(
len
(
str
(
len
(
self
.
asset_groups
))),
5
)
id_max_length
=
max
(
len
(
str
(
len
(
self
.
asset_groups
))),
5
)
name_length
=
item_max_length
(
self
.
asset_groups
,
15
,
key
=
lambda
x
:
x
.
name
)
name_max_length
=
max
(
max
([
len
(
group
.
name
)
for
group
in
self
.
asset_groups
]),
15
)
amount_length
=
item_max_length
(
self
.
asset_groups
,
10
,
amount_max_length
=
max
(
len
(
str
(
max
([
group
.
assets_amount
for
group
in
self
.
asset_groups
]))),
10
)
key
=
lambda
x
:
x
.
assets_amount
)
header
=
'{1:>
%
d} {0.name:
%
d} {0.assets_amount:<
%
s} '
%
(
id_max_length
,
name_max_length
,
amount_max_length
)
size_list
=
[
id_length
,
name_length
,
amount_length
]
comment_length
=
max
(
self
.
request
.
meta
[
"width"
]
-
len
(
header
.
format
(
fake_group
,
id_max_length
)),
2
)
fake_data
=
[
'ID'
,
_
(
"Name"
),
_
(
"Assets"
)]
line
=
header
+
'{0.comment:
%
s}'
%
(
comment_length
//
2
)
# comment中可能有中文
header_without_comment
=
format_with_zh
(
size_list
,
*
fake_data
)
header
+=
"{0.comment:
%
s}"
%
comment_length
comment_length
=
max
(
self
.
client
.
send
(
title
(
header
.
format
(
fake_group
,
"ID"
)))
self
.
request
.
meta
[
"width"
]
-
size_of_str_with_zh
(
header_without_comment
)
-
1
,
2
)
size_list
.
append
(
comment_length
)
fake_data
.
append
(
_
(
"Comment"
))
self
.
client
.
send
(
title
(
format_with_zh
(
size_list
,
*
fake_data
)))
for
index
,
group
in
enumerate
(
self
.
asset_groups
,
1
):
for
index
,
group
in
enumerate
(
self
.
asset_groups
,
1
):
self
.
client
.
send
(
wr
(
line
.
format
(
group
,
index
)))
data
=
[
index
,
group
.
name
,
group
.
assets_amount
,
group
.
comment
]
self
.
client
.
send
(
wr
(
format_with_zh
(
size_list
,
*
data
)))
self
.
client
.
send
(
wr
(
_
(
"总共: {}"
)
.
format
(
len
(
self
.
asset_groups
)),
before
=
1
))
self
.
client
.
send
(
wr
(
_
(
"总共: {}"
)
.
format
(
len
(
self
.
asset_groups
)),
before
=
1
))
def
display_group_assets
(
self
,
_id
):
def
display_group_assets
(
self
,
_id
):
...
@@ -146,21 +155,30 @@ class InteractiveServer:
...
@@ -146,21 +155,30 @@ class InteractiveServer:
self
.
display_search_result
()
self
.
display_search_result
()
def
display_search_result
(
self
):
def
display_search_result
(
self
):
self
.
search_result
=
sort_assets
(
self
.
search_result
,
current_app
.
config
[
"ASSET_LIST_SORT_BY"
])
sort_by
=
current_app
.
config
[
"ASSET_LIST_SORT_BY"
]
fake_asset
=
Asset
(
hostname
=
_
(
"Hostname"
),
ip
=
_
(
"IP"
),
_system_users_name_list
=
_
(
"LoginAs"
),
self
.
search_result
=
sort_assets
(
self
.
search_result
,
sort_by
)
comment
=
_
(
"Comment"
))
fake_data
=
[
_
(
"ID"
),
_
(
"Hostname"
),
_
(
"IP"
),
_
(
"LoginAs"
)]
id_max_length
=
max
(
len
(
str
(
len
(
self
.
search_result
))),
3
)
id_length
=
max
(
len
(
str
(
len
(
self
.
search_result
))),
4
)
hostname_max_length
=
max
(
max
([
len
(
asset
.
hostname
)
for
asset
in
self
.
search_result
+
[
fake_asset
]]),
15
)
hostname_length
=
item_max_length
(
self
.
search_result
,
15
,
sysuser_max_length
=
max
([
len
(
asset
.
system_users_name_list
)
for
asset
in
self
.
search_result
+
[
fake_asset
]])
key
=
lambda
x
:
x
.
hostname
)
header
=
'{1:>
%
d} {0.hostname:
%
d} {0.ip:15} {0.system_users_name_list:
%
d} '
%
\
sysuser_length
=
item_max_length
(
self
.
search_result
,
(
id_max_length
,
hostname_max_length
,
sysuser_max_length
)
key
=
lambda
x
:
x
.
system_users_name_list
)
comment_length
=
self
.
request
.
meta
[
"width"
]
-
len
(
header
.
format
(
fake_asset
,
id_max_length
))
size_list
=
[
id_length
,
hostname_length
,
16
,
sysuser_length
]
comment_length
=
max
([
comment_length
,
2
])
header_without_comment
=
format_with_zh
(
size_list
,
*
fake_data
)
line
=
header
+
'{0.comment:.
%
d}'
%
(
comment_length
//
2
)
# comment中可能有中文
comment_length
=
max
(
header
+=
'{0.comment:
%
s}'
%
comment_length
self
.
request
.
meta
[
"width"
]
-
self
.
client
.
send
(
wr
(
title
(
header
.
format
(
fake_asset
,
"ID"
))))
size_of_str_with_zh
(
header_without_comment
)
-
1
,
2
)
size_list
.
append
(
comment_length
)
fake_data
.
append
(
_
(
"Comment"
))
self
.
client
.
send
(
wr
(
title
(
format_with_zh
(
size_list
,
*
fake_data
))))
for
index
,
asset
in
enumerate
(
self
.
search_result
,
1
):
for
index
,
asset
in
enumerate
(
self
.
search_result
,
1
):
self
.
client
.
send
(
wr
(
line
.
format
(
asset
,
index
)))
data
=
[
index
,
asset
.
hostname
,
asset
.
ip
,
asset
.
system_users_name_list
,
asset
.
comment
]
self
.
client
.
send
(
wr
(
format_with_zh
(
size_list
,
*
data
)))
self
.
client
.
send
(
wr
(
_
(
"总共: {} 匹配: {}"
)
.
format
(
self
.
client
.
send
(
wr
(
_
(
"总共: {} 匹配: {}"
)
.
format
(
len
(
self
.
assets
),
len
(
self
.
search_result
)),
before
=
1
)
len
(
self
.
assets
),
len
(
self
.
search_result
)),
before
=
1
)
)
)
...
@@ -242,7 +260,7 @@ class InteractiveServer:
...
@@ -242,7 +260,7 @@ class InteractiveServer:
self
.
display_banner
()
self
.
display_banner
()
while
True
:
while
True
:
try
:
try
:
opt
=
net_input
(
self
.
client
)
opt
=
net_input
(
self
.
client
,
prompt
=
'Opt>'
,
before
=
1
)
rv
=
self
.
dispatch
(
opt
)
rv
=
self
.
dispatch
(
opt
)
if
rv
is
self
.
_sentinel
:
if
rv
is
self
.
_sentinel
:
break
break
...
...
coco/utils.py
View file @
b5221652
...
@@ -294,27 +294,14 @@ def get_logger(file_name):
...
@@ -294,27 +294,14 @@ def get_logger(file_name):
return
logging
.
getLogger
(
'coco.'
+
file_name
)
return
logging
.
getLogger
(
'coco.'
+
file_name
)
zh_pattern
=
re
.
compile
(
u'[
\u4e00
-
\u9fa5
]+'
)
def
net_input
(
client
,
prompt
=
'Opt> '
,
sensitive
=
False
,
before
=
0
,
after
=
0
):
def
len_display
(
s
):
length
=
0
for
i
in
s
:
if
zh_pattern
.
match
(
i
):
length
+=
2
else
:
length
+=
1
return
length
def
net_input
(
client
,
prompt
=
'Opt> '
,
sensitive
=
False
):
"""实现了一个ssh input, 提示用户输入, 获取并返回
"""实现了一个ssh input, 提示用户输入, 获取并返回
:return user input string
:return user input string
"""
"""
input_data
=
[]
input_data
=
[]
parser
=
TtyIOParser
()
parser
=
TtyIOParser
()
client
.
send
(
wrap_with_line_feed
(
prompt
,
before
=
0
,
after
=
0
))
client
.
send
(
wrap_with_line_feed
(
prompt
,
before
=
before
,
after
=
after
))
while
True
:
while
True
:
data
=
client
.
recv
(
10
)
data
=
client
.
recv
(
10
)
...
@@ -377,11 +364,59 @@ def register_service(service):
...
@@ -377,11 +364,59 @@ def register_service(service):
stack
[
'service'
]
=
service
stack
[
'service'
]
=
service
def
get_app
():
zh_pattern
=
re
.
compile
(
r'[\u4e00-\u9fa5]'
)
if
stack
.
get
(
"app"
):
return
stack
[
"app"
]
else
:
def
find_chinese
(
s
):
return
ValueError
(
"No app found"
)
return
zh_pattern
.
findall
(
s
)
def
align_with_zh
(
s
,
length
,
addin
=
' '
):
if
not
isinstance
(
s
,
str
):
s
=
str
(
s
)
zh_len
=
len
(
find_chinese
(
s
))
padding
=
length
-
(
len
(
s
)
-
zh_len
)
-
zh_len
*
2
padding_content
=
''
if
padding
>
0
:
padding_content
=
addin
*
padding
return
s
+
padding_content
def
format_with_zh
(
size_list
,
*
args
):
data
=
[]
for
length
,
s
in
zip
(
size_list
,
args
):
data
.
append
(
align_with_zh
(
s
,
length
))
return
' '
.
join
(
data
)
def
size_of_str_with_zh
(
s
):
if
isinstance
(
s
,
int
):
s
=
str
(
s
)
try
:
chinese
=
find_chinese
(
s
)
except
TypeError
:
print
(
type
(
s
))
raise
return
len
(
s
)
+
len
(
chinese
)
def
item_max_length
(
_iter
,
maxi
=
None
,
mini
=
None
,
key
=
None
):
if
key
:
_iter
=
[
key
(
i
)
for
i
in
_iter
]
length
=
[
size_of_str_with_zh
(
s
)
for
s
in
_iter
]
if
maxi
:
length
.
append
(
maxi
)
length
=
max
(
length
)
if
mini
and
length
<
mini
:
length
=
mini
return
length
def
int_length
(
i
):
return
len
(
str
(
i
))
ugettext
=
_gettext
()
ugettext
=
_gettext
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment