Mercurial Hosting > luan
comparison src/luan/modules/http/tools/Shell.luan @ 1295:9dca1e912658
improve web shell
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Thu, 10 Jan 2019 21:42:11 -0700 |
parents | 007ceb8dcf89 |
children | 590ad449ac7f |
comparison
equal
deleted
inserted
replaced
1294:2555154ad19f | 1295:9dca1e912658 |
---|---|
1 local Luan = require "luan:Luan.luan" | 1 local Luan = require "luan:Luan.luan" |
2 local error = Luan.error | 2 local error = Luan.error |
3 local load = Luan.load or error() | 3 local load = Luan.load or error() |
4 local to_string = Luan.to_string or error() | 4 local to_string = Luan.to_string or error() |
5 local try = Luan.try or error() | 5 local try = Luan.try or error() |
6 local String = require "luan:String.luan" | 6 local range = Luan.range or error() |
7 local concat = String.concat or error() | |
8 local Table = require "luan:Table.luan" | 7 local Table = require "luan:Table.luan" |
8 local concat = Table.concat or error() | |
9 local pack = Table.pack or error() | 9 local pack = Table.pack or error() |
10 local unpack = Table.unpack or error() | 10 local unpack = Table.unpack or error() |
11 local Time = require "luan:Time.luan" | 11 local Time = require "luan:Time.luan" |
12 local Thread = require "luan:Thread.luan" | 12 local Thread = require "luan:Thread.luan" |
13 local Html = require "luan:Html.luan" | |
14 local html_encode = Html.encode or error() | |
15 local javascript_encode = Html.javascript_encode or error() | |
13 local Io = require "luan:Io.luan" | 16 local Io = require "luan:Io.luan" |
14 local print = Io.print or error() | |
15 local Http = require "luan:http/Http.luan" | 17 local Http = require "luan:http/Http.luan" |
16 local Logging = require "luan:logging/Logging.luan" | 18 local Logging = require "luan:logging/Logging.luan" |
17 local logger = Logging.logger "Shell" | 19 local logger = Logging.logger "Shell" |
18 | 20 |
19 | 21 |
24 local new_session = Thread.global_callable("shell.new_session",forever,{next=function() | 26 local new_session = Thread.global_callable("shell.new_session",forever,{next=function() |
25 count = count + 1 | 27 count = count + 1 |
26 return to_string(count) | 28 return to_string(count) |
27 end}).next | 29 end}).next |
28 | 30 |
29 local history = "" | |
30 local env = {} | 31 local env = {} |
31 Shell.env = env | 32 Shell.env = env |
32 | 33 |
33 local fns = {} | 34 local fns = {} |
34 | 35 |
35 function fns.history() | |
36 return history | |
37 end | |
38 | |
39 function fns.run(cmd) | 36 function fns.run(cmd) |
40 Io.stdout = {} | 37 return try { |
41 Io.stdout.write = function(...) | |
42 history = concat(history,...) | |
43 end | |
44 print( "% "..cmd ) | |
45 try { | |
46 function() | 38 function() |
47 local line | 39 local line |
48 try { | 40 try { |
49 function() | 41 function() |
50 line = load("return "..cmd,"<web_shell>",env) | 42 line = load("return "..cmd,"<web_shell>",env) |
51 end | 43 end |
52 catch = function(e) | 44 catch = function(e) |
53 line = load(cmd,"<web_shell>",env) | 45 line = load(cmd,"<web_shell>",env) |
54 end | 46 end |
55 } | 47 } |
56 local rtn = pack( line() ) | 48 return line() |
57 if rtn.n > 0 then | |
58 print( unpack(rtn) ) | |
59 end | |
60 end | 49 end |
61 catch = function(e) | 50 catch = function(e) |
62 Io.print_to(Io.stderr,e) | 51 -- Io.print_to(Io.stderr,e) |
63 print(e) | 52 return to_string(e) |
64 end | 53 end |
65 } | 54 } |
66 end | 55 end |
67 | 56 |
68 local timeout = Time.period{hours=10} | 57 local timeout = Time.period{hours=10} |
69 | 58 |
70 local function get_session(session_id) | 59 local function get_session(session_id) |
71 return Thread.global_callable("shell.session"..session_id,timeout,fns) | 60 return Thread.global_callable("shell.session"..session_id,timeout,fns) |
72 end | 61 end |
73 | 62 |
74 local function remove_session(session_id) | |
75 return Thread.remove_global_callable("shell.session"..session_id) | |
76 end | |
77 | |
78 function Shell.respond() | 63 function Shell.respond() |
79 local session_id = Http.request.cookies["session"] | 64 Io.stdout = Http.response.text_writer() |
80 if session_id == nil then | 65 local cmd = Http.request.parameters.cmd |
81 session_id = new_session() | 66 if cmd ~= nil then |
82 Http.response.set_cookie("session",session_id) | 67 Http.response.headers["content-type"] = "application/javascript" |
68 local session_id = Http.request.parameters.session or error() | |
69 local session = get_session(session_id) | |
70 local rtn = pack( session.run(cmd) ) | |
71 %> | |
72 var pre = document.querySelector('pre'); | |
73 pre.innerHTML += '\n> <%=javascript_encode(html_encode(cmd))%>'; | |
74 <% | |
75 if rtn.n > 0 then | |
76 local t = {} | |
77 for i in range(1,rtn.n) do | |
78 t[#t+1] = javascript_encode(html_encode(to_string(rtn[i]))) | |
79 end | |
80 %> | |
81 pre.innerHTML += '\n<%=concat(t,"\t")%>'; | |
82 <% | |
83 end | |
84 return | |
83 end | 85 end |
84 local session = get_session(session_id) | |
85 | |
86 if Http.request.parameters.clear ~= nil then | |
87 remove_session(session_id) | |
88 Http.response.send_redirect(Http.request.path) -- reload page | |
89 return | |
90 else | |
91 local cmd = Http.request.parameters.cmd | |
92 if cmd ~= nil then | |
93 session.run(cmd) | |
94 end | |
95 end | |
96 | |
97 Io.stdout = Http.response.text_writer() | |
98 %> | 86 %> |
99 <!doctype html> | 87 <!doctype html> |
100 <html> | 88 <html> |
101 <head> | 89 <head> |
102 <title>Luan Shell</title> | 90 <title>Luan Shell</title> |
91 <script> | |
92 | |
93 function ajax(url) { | |
94 var request = new XMLHttpRequest(); | |
95 request.open( 'GET', url ); | |
96 request.onload = function() { | |
97 if( request.status !== 200 ) { | |
98 console.log( 'ajax failed: ' + request.status ); | |
99 return; | |
100 } | |
101 //console.log( request.responseText ); | |
102 eval( request.responseText ); | |
103 }; | |
104 request.send(); | |
105 } | |
106 | |
107 function submitted() { | |
108 var input = document.querySelector('input'); | |
109 ajax( '?session=<%=new_session()%>&cmd=' + encodeURIComponent(input.value) ); | |
110 input.value = ''; | |
111 } | |
112 | |
113 </script> | |
103 <style> | 114 <style> |
104 body { | 115 body { |
105 font-family: sans-serif; | 116 font-family: sans-serif; |
106 margin: 2em 5% 0 5%; | |
107 } | 117 } |
108 pre { | 118 pre { |
109 font: inherit; | 119 font: inherit; |
120 margin-bottom: 0; | |
110 } | 121 } |
111 input[type="text"] { | 122 table { |
123 width: 100%; | |
124 border-collapse: collapse; | |
125 } | |
126 td { | |
127 padding: 0; | |
128 } | |
129 td:last-child { | |
130 width: 100%; | |
131 } | |
132 input { | |
133 width: 100%; | |
112 font: inherit; | 134 font: inherit; |
113 padding: .5em .8em; | |
114 border-radius: 8px; | |
115 border-style: groove; | |
116 } | |
117 input[type="text"]:focus { | |
118 border-color: #66afe9; | |
119 outline: none; | 135 outline: none; |
120 } | |
121 input[type="submit"] { | |
122 color: white; | |
123 background: #337ab7; | |
124 border-color: #337ab7; | |
125 font: inherit; | |
126 padding: .5em; | |
127 border-radius: 4px; | |
128 } | |
129 input[type="submit"]:hover { | |
130 background: #236aa7 !important; | |
131 } | 136 } |
132 </style> | 137 </style> |
133 </head> | 138 </head> |
134 <body> | 139 <body> |
135 <h2>Luan Shell</h2> | 140 <pre>Luan <%=Luan.VERSION%></pre> |
136 <p>This is a command shell. Enter commands below.</p> | 141 <form autocomplete=off onsubmit="submitted(); return false"> |
137 <pre><%= session.history() %></pre> | 142 <table> |
138 <form method='post'> | 143 <tr> |
139 % <input type="text" name='cmd' size="80" autofocus> | 144 <td>> </td> |
140 <input type="submit" value="run"> | 145 <td><input name=cmd autofocus></td> |
141 <input type="submit" name="clear" value="clear"> | 146 </tr> |
147 </table> | |
142 </form> | 148 </form> |
143 </body> | 149 </body> |
144 </html> | 150 </html> |
145 <% | 151 <% |
146 end | 152 end |