mirror of
https://github.com/lwch/natpass.git
synced 2024-04-21 12:41:54 +00:00
实现web shell
This commit is contained in:
+1
-1
@@ -5,4 +5,4 @@
|
||||
/tmp
|
||||
/logs
|
||||
/run
|
||||
/*.yaml
|
||||
/*.yaml
|
||||
@@ -9,5 +9,7 @@ LDFLAGS="-X 'main._GIT_HASH=$HASH'
|
||||
-X 'main._BUILD_TIME=$BUILD_TIME'
|
||||
-X 'main._VERSION=$VERSION'"
|
||||
|
||||
go run contrib/bindata/main.go -pkg shell -o code/client/shell/assets.go \
|
||||
-prefix html/shell "$@" html/shell/...
|
||||
CGO_ENABLED=0 go build -ldflags "$LDFLAGS" -o bin/np-svr code/server/*.go
|
||||
CGO_ENABLED=0 go build -ldflags "$LDFLAGS" -o bin/np-cli code/client/*.go
|
||||
|
||||
+24
-12
@@ -13,22 +13,26 @@ import (
|
||||
|
||||
type Conn struct {
|
||||
sync.RWMutex
|
||||
Idx uint32
|
||||
parent *Pool
|
||||
conn *network.Conn
|
||||
read map[string]chan *network.Msg // link id => channel
|
||||
unknownRead chan *network.Msg // read message without link
|
||||
write chan *network.Msg // link id => channel
|
||||
Idx uint32
|
||||
ReadTimeout time.Duration
|
||||
WriteTimeout time.Duration
|
||||
parent *Pool
|
||||
conn *network.Conn
|
||||
read map[string]chan *network.Msg // link id => channel
|
||||
unknownRead chan *network.Msg // read message without link
|
||||
write chan *network.Msg // link id => channel
|
||||
}
|
||||
|
||||
func newConn(parent *Pool, conn *network.Conn, idx uint32) *Conn {
|
||||
ret := &Conn{
|
||||
Idx: idx,
|
||||
parent: parent,
|
||||
conn: conn,
|
||||
read: make(map[string]chan *network.Msg),
|
||||
unknownRead: make(chan *network.Msg),
|
||||
write: make(chan *network.Msg),
|
||||
Idx: idx,
|
||||
ReadTimeout: parent.cfg.ReadTimeout,
|
||||
WriteTimeout: parent.cfg.WriteTimeout,
|
||||
parent: parent,
|
||||
conn: conn,
|
||||
read: make(map[string]chan *network.Msg),
|
||||
unknownRead: make(chan *network.Msg),
|
||||
write: make(chan *network.Msg),
|
||||
}
|
||||
logging.Info("new connection: %s-%d", ret.parent.cfg.ID, ret.Idx)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
@@ -148,6 +152,14 @@ func (conn *Conn) ChanRead(id string) <-chan *network.Msg {
|
||||
return conn.read[id]
|
||||
}
|
||||
|
||||
// Reset reset message next read
|
||||
func (conn *Conn) Reset(id string, msg *network.Msg) {
|
||||
conn.RLock()
|
||||
ch := conn.read[id]
|
||||
conn.RUnlock()
|
||||
ch <- msg
|
||||
}
|
||||
|
||||
func (conn *Conn) ChanUnknown() <-chan *network.Msg {
|
||||
return conn.unknownRead
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/assets.go
|
||||
@@ -3,7 +3,9 @@ package shell
|
||||
import (
|
||||
"fmt"
|
||||
"natpass/code/client/pool"
|
||||
"natpass/code/network"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/lwch/logging"
|
||||
"github.com/lwch/runtime"
|
||||
@@ -21,10 +23,35 @@ func (shell *Shell) New(pool *pool.Pool, w http.ResponseWriter, r *http.Request)
|
||||
conn := pool.Get(id)
|
||||
conn.SendShellCreate(id, shell.cfg)
|
||||
conn.AddLink(id)
|
||||
lk := NewLink(shell, id, shell.cfg.Target, conn)
|
||||
link := NewLink(shell, id, shell.cfg.Target, conn)
|
||||
shell.Lock()
|
||||
shell.links[id] = lk
|
||||
shell.links[id] = link
|
||||
shell.Unlock()
|
||||
ch := conn.ChanRead(id)
|
||||
timeout := time.After(conn.ReadTimeout)
|
||||
for {
|
||||
var msg *network.Msg
|
||||
select {
|
||||
case msg = <-ch:
|
||||
case <-timeout:
|
||||
logging.Error("create shell %s on tunnel %s failed, timtout", link.id, link.parent.Name)
|
||||
http.Error(w, "timeout", http.StatusBadGateway)
|
||||
return
|
||||
}
|
||||
if msg.GetXType() != network.Msg_shell_created {
|
||||
conn.Reset(id, msg)
|
||||
time.Sleep(conn.ReadTimeout / 10)
|
||||
continue
|
||||
}
|
||||
rep := msg.GetScreated()
|
||||
if !rep.GetOk() {
|
||||
logging.Error("create shell %s on tunnel %s failed, err=%s",
|
||||
link.id, link.parent.Name, msg.GetScreated().GetMsg())
|
||||
http.Error(w, rep.GetMsg(), http.StatusBadGateway)
|
||||
return
|
||||
}
|
||||
break
|
||||
}
|
||||
logging.Info("new shell: name=%s, id=%s", shell.Name, id)
|
||||
fmt.Fprint(w, id)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package shell
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"html/template"
|
||||
"io"
|
||||
"mime"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (shell *Shell) Render(w http.ResponseWriter, r *http.Request) {
|
||||
dir := strings.TrimPrefix(r.URL.Path, "/")
|
||||
data, err := Asset(dir)
|
||||
if err == nil {
|
||||
ctype := mime.TypeByExtension(filepath.Ext(dir))
|
||||
if ctype == "" {
|
||||
ctype = http.DetectContentType(data)
|
||||
}
|
||||
w.Header().Set("Content-Type", ctype)
|
||||
io.Copy(w, bytes.NewReader(data))
|
||||
return
|
||||
}
|
||||
data, _ = Asset("index.html")
|
||||
tpl, err := template.New("all").Parse(string(data))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
tpl.Execute(w, shell)
|
||||
}
|
||||
@@ -47,7 +47,6 @@ func (shell *Shell) localForward(id string, local *websocket.Conn) {
|
||||
link := shell.links[id]
|
||||
shell.RUnlock()
|
||||
defer link.Close()
|
||||
<-link.onWork
|
||||
for {
|
||||
_, data, err := local.ReadMessage()
|
||||
if err != nil {
|
||||
@@ -74,14 +73,6 @@ func (shell *Shell) remoteForward(id string, local *websocket.Conn) {
|
||||
}
|
||||
link.SetTargetIdx(msg.GetFromIdx())
|
||||
switch msg.GetXType() {
|
||||
case network.Msg_shell_created:
|
||||
if msg.GetScreated().GetOk() {
|
||||
link.onWork <- struct{}{}
|
||||
continue
|
||||
}
|
||||
logging.Error("create shell %s on tunnel %s failed, err=%s",
|
||||
link.id, link.parent.Name, msg.GetScreated().GetMsg())
|
||||
return
|
||||
case network.Msg_shell_data:
|
||||
err := local.WriteMessage(websocket.TextMessage, msg.GetSdata().GetData())
|
||||
if err != nil {
|
||||
|
||||
@@ -17,7 +17,6 @@ type Link struct {
|
||||
target string // target id
|
||||
targetIdx uint32 // target idx
|
||||
remote *pool.Conn
|
||||
onWork chan struct{}
|
||||
// in remote
|
||||
pid int
|
||||
stdin io.WriteCloser
|
||||
@@ -34,7 +33,6 @@ func NewLink(parent *Shell, id, target string, remote *pool.Conn) *Link {
|
||||
id: id,
|
||||
target: target,
|
||||
remote: remote,
|
||||
onWork: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ func (shell *Shell) Handle(pl *pool.Pool) {
|
||||
mux.HandleFunc("/new", pf(shell.New))
|
||||
mux.HandleFunc("/ws/", pf(shell.WS))
|
||||
mux.HandleFunc("/resize", pf(shell.Resize))
|
||||
mux.HandleFunc("/", shell.Render)
|
||||
svr := &http.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", shell.cfg.LocalAddr, shell.cfg.LocalPort),
|
||||
Handler: mux,
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
bindata "github.com/go-bindata/go-bindata/v3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := bindata.NewConfig()
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Printf("Usage: %s [options] <input directories>\n\n", os.Args[0])
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
flag.BoolVar(&c.Debug, "debug", c.Debug, "Do not embed the assets, but provide the embedding API. Contents will still be loaded from disk.")
|
||||
flag.StringVar(&c.Package, "pkg", c.Package, "Package name to use in the generated code.")
|
||||
flag.StringVar(&c.Prefix, "prefix", c.Prefix, "Optional path prefix to strip off asset names.")
|
||||
flag.StringVar(&c.Output, "o", c.Output, "Optional name of the output file to be generated.")
|
||||
flag.Parse()
|
||||
|
||||
if flag.NArg() == 0 {
|
||||
fmt.Fprintf(os.Stderr, "Missing <input dir>\n\n")
|
||||
flag.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
c.Input = make([]bindata.InputConfig, flag.NArg())
|
||||
for i := range c.Input {
|
||||
c.Input[i] = parseInput(flag.Arg(i))
|
||||
}
|
||||
|
||||
err := bindata.Translate(c)
|
||||
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "bindata: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func parseInput(path string) bindata.InputConfig {
|
||||
if strings.HasSuffix(path, "/...") {
|
||||
return bindata.InputConfig{
|
||||
Path: filepath.Clean(path[:len(path)-4]),
|
||||
Recursive: true,
|
||||
}
|
||||
}
|
||||
return bindata.InputConfig{
|
||||
Path: filepath.Clean(path),
|
||||
Recursive: false,
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ go 1.16
|
||||
require (
|
||||
github.com/creack/pty v1.1.15
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/go-bindata/go-bindata/v3 v3.1.3
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/kardianos/service v1.2.0
|
||||
github.com/lwch/logging v0.0.0-20210528090125-a154917d90c6
|
||||
|
||||
@@ -2,6 +2,8 @@ github.com/creack/pty v1.1.15 h1:cKRCLMj3Ddm54bKSpemfQ8AtYFBhAI2MPmdys22fBdc=
|
||||
github.com/creack/pty v1.1.15/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/go-bindata/go-bindata/v3 v3.1.3 h1:F0nVttLC3ws0ojc7p60veTurcOm//D4QBODNM7EGrCI=
|
||||
github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
@@ -9,12 +11,25 @@ github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0U
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/kardianos/service v1.2.0 h1:bGuZ/epo3vrt8IPC7mnKQolqFeYJb7Cs8Rk4PSOBB/g=
|
||||
github.com/kardianos/service v1.2.0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
||||
github.com/kisielk/errcheck v1.2.0 h1:reN85Pxc5larApoH1keMBiu2GWtPqXQ1nc9gx+jOU+E=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/lwch/logging v0.0.0-20210528090125-a154917d90c6 h1:R52s6I/vW1NfNaJdY+Yr/ivkiFicouKmK0v3nvDQh4s=
|
||||
github.com/lwch/logging v0.0.0-20210528090125-a154917d90c6/go.mod h1:aXQui5bsF/d4I+z6szuiBWY5m4y9t6pyZ2Q/sLgkBBg=
|
||||
github.com/lwch/runtime v0.0.0-20190520054850-8c97e19e0c6d h1:Xg+zzPtvX22DaoJD5Bp0tqPdB8gn5WypghIJ4fluqiQ=
|
||||
github.com/lwch/runtime v0.0.0-20190520054850-8c97e19e0c6d/go.mod h1:uEt0zu1MDC7WnVvodPBGSYAD/KMKk0v36xE8UE5veM8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88=
|
||||
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f h1:kDxGY2VmgABOe55qheT/TFqUMtcTHnomIPS1iv3G4Ms=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
Vendored
+2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.xterm .xterm-viewport {
|
||||
width: 100% !important;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>shell - [{{.Name}}]</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="/xterm.js/xterm.css" />
|
||||
<script src="/xterm.js/addon/xterm-addon-attach/xterm-addon-attach.js"></script>
|
||||
<script src="/xterm.js/addon/xterm-addon-fit/xterm-addon-fit.js"></script>
|
||||
<script src="/xterm.js/xterm.js"></script>
|
||||
<script src="/jquery/jquery-3.6.0.min.js"></script>
|
||||
<link rel="stylesheet" href="/index.css" />
|
||||
<script src="/index.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="terminal"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,36 @@
|
||||
var page = {
|
||||
init: function() {
|
||||
page.terminal = new Terminal({
|
||||
renderType: 'canvas'
|
||||
});
|
||||
page.terminal.open(document.getElementById('terminal'));
|
||||
page.terminal.writeln('正在连接...');
|
||||
$.get('/new', function(ret) {
|
||||
page.id = ret;
|
||||
page.websocket = new WebSocket('ws://'+location.host+'/ws/'+ret);
|
||||
page.websocket.onclose = page.onclose;
|
||||
page.terminal.reset();
|
||||
page.terminal.loadAddon(new AttachAddon.AttachAddon(page.websocket));
|
||||
document.getElementById('terminal').style.height = (window.innerHeight-1) + 'px';
|
||||
var fit = new FitAddon.FitAddon();
|
||||
page.terminal.loadAddon(fit);
|
||||
fit.fit();
|
||||
page.resize();
|
||||
});
|
||||
},
|
||||
resize: function() {
|
||||
$.post('/resize', {
|
||||
id: page.id,
|
||||
rows: page.terminal.rows,
|
||||
cols: page.terminal.cols
|
||||
});
|
||||
},
|
||||
onclose: function() {
|
||||
page.terminal.writeln('');
|
||||
page.terminal.writeln("\033[0;31m连接已断开!");
|
||||
},
|
||||
id: undefined,
|
||||
terminal: undefined,
|
||||
websocket: undefined
|
||||
};
|
||||
$(document).ready(page.init);
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../jquery
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../xterm.js-4.14.1
|
||||
@@ -0,0 +1,2 @@
|
||||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.AttachAddon=e():t.AttachAddon=e()}(self,(function(){return(()=>{"use strict";var t={};return(()=>{var e=t;Object.defineProperty(e,"__esModule",{value:!0}),e.AttachAddon=void 0;var s=function(){function t(t,e){this._disposables=[],this._socket=t,this._socket.binaryType="arraybuffer",this._bidirectional=!(e&&!1===e.bidirectional)}return t.prototype.activate=function(t){var e=this;this._disposables.push(o(this._socket,"message",(function(e){var s=e.data;t.write("string"==typeof s?s:new Uint8Array(s))}))),this._bidirectional&&(this._disposables.push(t.onData((function(t){return e._sendData(t)}))),this._disposables.push(t.onBinary((function(t){return e._sendBinary(t)})))),this._disposables.push(o(this._socket,"close",(function(){return e.dispose()}))),this._disposables.push(o(this._socket,"error",(function(){return e.dispose()})))},t.prototype.dispose=function(){for(var t=0,e=this._disposables;t<e.length;t++)e[t].dispose()},t.prototype._sendData=function(t){1===this._socket.readyState&&this._socket.send(t)},t.prototype._sendBinary=function(t){if(1===this._socket.readyState){for(var e=new Uint8Array(t.length),s=0;s<t.length;++s)e[s]=255&t.charCodeAt(s);this._socket.send(e)}},t}();function o(t,e,s){return t.addEventListener(e,s),{dispose:function(){s&&t.removeEventListener(e,s)}}}e.AttachAddon=s})(),t})()}));
|
||||
//# sourceMappingURL=xterm-addon-attach.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"xterm-addon-attach.js","mappings":"CAAA,SAA2CA,EAAMC,GAC1B,iBAAZC,SAA0C,iBAAXC,OACxCA,OAAOD,QAAUD,IACQ,mBAAXG,QAAyBA,OAAOC,IAC9CD,OAAO,GAAIH,GACe,iBAAZC,QACdA,QAAqB,YAAID,IAEzBD,EAAkB,YAAIC,IARxB,CASGK,MAAM,WACT,M,sHCGA,iBAKE,WAAYC,EAAmBC,GAFvB,KAAAC,aAA8B,GAGpCC,KAAKC,QAAUJ,EAEfG,KAAKC,QAAQC,WAAa,cAC1BF,KAAKG,iBAAmBL,IAAqC,IAA1BA,EAAQM,eA6C/C,OA1CS,YAAAC,SAAP,SAAgBC,GAAhB,WACEN,KAAKD,aAAaQ,KAChBC,EAAkBR,KAAKC,QAAS,WAAW,SAAAQ,GACzC,IAAMC,EAA6BD,EAAGC,KACtCJ,EAASK,MAAsB,iBAATD,EAAoBA,EAAO,IAAIE,WAAWF,QAIhEV,KAAKG,iBACPH,KAAKD,aAAaQ,KAAKD,EAASO,QAAO,SAAAH,GAAQ,SAAKI,UAAUJ,OAC9DV,KAAKD,aAAaQ,KAAKD,EAASS,UAAS,SAAAL,GAAQ,SAAKM,YAAYN,QAGpEV,KAAKD,aAAaQ,KAAKC,EAAkBR,KAAKC,QAAS,SAAS,WAAM,SAAKgB,cAC3EjB,KAAKD,aAAaQ,KAAKC,EAAkBR,KAAKC,QAAS,SAAS,WAAM,SAAKgB,eAGtE,YAAAA,QAAP,WACE,IAAgB,UAAAjB,KAAKD,aAAL,eAAJ,KACRkB,WAIE,YAAAH,UAAR,SAAkBJ,GAGgB,IAA5BV,KAAKC,QAAQiB,YAGjBlB,KAAKC,QAAQkB,KAAKT,IAGZ,YAAAM,YAAR,SAAoBN,GAClB,GAAgC,IAA5BV,KAAKC,QAAQiB,WAAjB,CAIA,IADA,IAAME,EAAS,IAAIR,WAAWF,EAAKW,QAC1BC,EAAI,EAAGA,EAAIZ,EAAKW,SAAUC,EACjCF,EAAOE,GAA0B,IAArBZ,EAAKa,WAAWD,GAE9BtB,KAAKC,QAAQkB,KAAKC,KAEtB,EAtDA,GAwDA,SAASZ,EAAqDX,EAAmB2B,EAASC,GAExF,OADA5B,EAAO6B,iBAAiBF,EAAMC,GACvB,CACLR,QAAS,WACFQ,GAIL5B,EAAO8B,oBAAoBH,EAAMC,KAhE1B,EAAAG,YAAAA,G","sources":["webpack://AttachAddon/webpack/universalModuleDefinition","webpack://AttachAddon/./src/AttachAddon.ts"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"AttachAddon\"] = factory();\n\telse\n\t\troot[\"AttachAddon\"] = factory();\n})(self, function() {\nreturn ","/**\n * Copyright (c) 2014, 2019 The xterm.js authors. All rights reserved.\n * @license MIT\n *\n * Implements the attach method, that attaches the terminal to a WebSocket stream.\n */\n\nimport { Terminal, IDisposable, ITerminalAddon } from 'xterm';\n\ninterface IAttachOptions {\n bidirectional?: boolean;\n}\n\nexport class AttachAddon implements ITerminalAddon {\n private _socket: WebSocket;\n private _bidirectional: boolean;\n private _disposables: IDisposable[] = [];\n\n constructor(socket: WebSocket, options?: IAttachOptions) {\n this._socket = socket;\n // always set binary type to arraybuffer, we do not handle blobs\n this._socket.binaryType = 'arraybuffer';\n this._bidirectional = !(options && options.bidirectional === false);\n }\n\n public activate(terminal: Terminal): void {\n this._disposables.push(\n addSocketListener(this._socket, 'message', ev => {\n const data: ArrayBuffer | string = ev.data;\n terminal.write(typeof data === 'string' ? data : new Uint8Array(data));\n })\n );\n\n if (this._bidirectional) {\n this._disposables.push(terminal.onData(data => this._sendData(data)));\n this._disposables.push(terminal.onBinary(data => this._sendBinary(data)));\n }\n\n this._disposables.push(addSocketListener(this._socket, 'close', () => this.dispose()));\n this._disposables.push(addSocketListener(this._socket, 'error', () => this.dispose()));\n }\n\n public dispose(): void {\n for (const d of this._disposables) {\n d.dispose();\n }\n }\n\n private _sendData(data: string): void {\n // TODO: do something better than just swallowing\n // the data if the socket is not in a working condition\n if (this._socket.readyState !== 1) {\n return;\n }\n this._socket.send(data);\n }\n\n private _sendBinary(data: string): void {\n if (this._socket.readyState !== 1) {\n return;\n }\n const buffer = new Uint8Array(data.length);\n for (let i = 0; i < data.length; ++i) {\n buffer[i] = data.charCodeAt(i) & 255;\n }\n this._socket.send(buffer);\n }\n}\n\nfunction addSocketListener<K extends keyof WebSocketEventMap>(socket: WebSocket, type: K, handler: (this: WebSocket, ev: WebSocketEventMap[K]) => any): IDisposable {\n socket.addEventListener(type, handler);\n return {\n dispose: () => {\n if (!handler) {\n // Already disposed\n return;\n }\n socket.removeEventListener(type, handler);\n }\n };\n}\n"],"names":["root","factory","exports","module","define","amd","self","socket","options","_disposables","this","_socket","binaryType","_bidirectional","bidirectional","activate","terminal","push","addSocketListener","ev","data","write","Uint8Array","onData","_sendData","onBinary","_sendBinary","dispose","readyState","send","buffer","length","i","charCodeAt","type","handler","addEventListener","removeEventListener","AttachAddon"],"sourceRoot":""}
|
||||
@@ -0,0 +1,2 @@
|
||||
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FitAddon=t():e.FitAddon=t()}(self,(function(){return(()=>{"use strict";var e={};return(()=>{var t=e;Object.defineProperty(t,"__esModule",{value:!0}),t.FitAddon=void 0;var r=function(){function e(){}return e.prototype.activate=function(e){this._terminal=e},e.prototype.dispose=function(){},e.prototype.fit=function(){var e=this.proposeDimensions();if(e&&this._terminal){var t=this._terminal._core;this._terminal.rows===e.rows&&this._terminal.cols===e.cols||(t._renderService.clear(),this._terminal.resize(e.cols,e.rows))}},e.prototype.proposeDimensions=function(){if(this._terminal&&this._terminal.element&&this._terminal.element.parentElement){var e=this._terminal._core;if(0!==e._renderService.dimensions.actualCellWidth&&0!==e._renderService.dimensions.actualCellHeight){var t=window.getComputedStyle(this._terminal.element.parentElement),r=parseInt(t.getPropertyValue("height")),i=Math.max(0,parseInt(t.getPropertyValue("width"))),n=window.getComputedStyle(this._terminal.element),o=r-(parseInt(n.getPropertyValue("padding-top"))+parseInt(n.getPropertyValue("padding-bottom"))),a=i-(parseInt(n.getPropertyValue("padding-right"))+parseInt(n.getPropertyValue("padding-left")))-e.viewport.scrollBarWidth;return{cols:Math.max(2,Math.floor(a/e._renderService.dimensions.actualCellWidth)),rows:Math.max(1,Math.floor(o/e._renderService.dimensions.actualCellHeight))}}}},e}();t.FitAddon=r})(),e})()}));
|
||||
//# sourceMappingURL=xterm-addon-fit.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
||||
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
||||
* https://github.com/chjj/term.js
|
||||
* @license MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Originally forked from (with the author's permission):
|
||||
* Fabrice Bellard's javascript vt100 for jslinux:
|
||||
* http://bellard.org/jslinux/
|
||||
* Copyright (c) 2011 Fabrice Bellard
|
||||
* The original design remains. The terminal itself
|
||||
* has been extended to include xterm CSI codes, among
|
||||
* other features.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default styles for xterm.js
|
||||
*/
|
||||
|
||||
.xterm {
|
||||
position: relative;
|
||||
user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.xterm.focus,
|
||||
.xterm:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.xterm .xterm-helpers {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
/**
|
||||
* The z-index of the helpers must be higher than the canvases in order for
|
||||
* IMEs to appear on top.
|
||||
*/
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.xterm .xterm-helper-textarea {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
/* Move textarea out of the screen to the far left, so that the cursor is not visible */
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
left: -9999em;
|
||||
top: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
z-index: -5;
|
||||
/** Prevent wrapping so the IME appears against the textarea at the correct position */
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.xterm .composition-view {
|
||||
/* TODO: Composition position got messed up somewhere */
|
||||
background: #000;
|
||||
color: #FFF;
|
||||
display: none;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.xterm .composition-view.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.xterm .xterm-viewport {
|
||||
/* On OS X this is required in order for the scroll bar to appear fully opaque */
|
||||
background-color: #000;
|
||||
overflow-y: scroll;
|
||||
cursor: default;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen canvas {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-scroll-area {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.xterm-char-measure-element {
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -9999em;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.xterm {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.xterm.enable-mouse-events {
|
||||
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.xterm.xterm-cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.xterm.column-select.focus {
|
||||
/* Column selection mode */
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility,
|
||||
.xterm .xterm-message {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.xterm .live-region {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.xterm-dim {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.xterm-underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.xterm-strikethrough {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user