Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
李生煜
/
xterminal
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit a3da557f
authored
Oct 16, 2020
by
李生煜
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
init
1 parent
d1a7f04a
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
372 additions
and
11 deletions
package-lock.json
package.json
src/App.vue
src/websocket.ts
src/webtty.ts
src/xterm.ts
package-lock.json
View file @
a3da557
...
...
@@ -10933,6 +10933,21 @@
"integrity"
:
"sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
,
"dev"
:
true
},
"xterm"
:
{
"version"
:
"4.9.0"
,
"resolved"
:
"https://registry.npmjs.org/xterm/-/xterm-4.9.0.tgz"
,
"integrity"
:
"sha512-wGfqufmioctKr8VkbRuZbVDfjlXWGZZ1PWHy1yqqpGT3Nm6yaJx8lxDbSEBANtgaiVPTcKSp97sxOy5IlpqYfw=="
},
"xterm-addon-attach"
:
{
"version"
:
"0.6.0"
,
"resolved"
:
"https://registry.npmjs.org/xterm-addon-attach/-/xterm-addon-attach-0.6.0.tgz"
,
"integrity"
:
"sha512-Mo8r3HTjI/EZfczVCwRU6jh438B4WLXxdFO86OB7bx0jGhwh2GdF4ifx/rP+OB+Cb2vmLhhVIZ00/7x3YSP3dg=="
},
"xterm-addon-fit"
:
{
"version"
:
"0.4.0"
,
"resolved"
:
"https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.4.0.tgz"
,
"integrity"
:
"sha512-p4BESuV/g2L6pZzFHpeNLLnep9mp/DkF3qrPglMiucSFtD8iJxtMufEoEJbN8LZwB4i+8PFpFvVuFrGOSpW05w=="
},
"y18n"
:
{
"version"
:
"4.0.0"
,
"resolved"
:
"https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz"
,
...
...
package.json
View file @
a3da557
...
...
@@ -10,7 +10,10 @@
"dependencies"
:
{
"vue"
:
"^2.6.11"
,
"vue-class-component"
:
"^7.2.3"
,
"vue-property-decorator"
:
"^8.4.2"
"vue-property-decorator"
:
"^8.4.2"
,
"xterm"
:
"^4.9.0"
,
"xterm-addon-attach"
:
"^0.6.0"
,
"xterm-addon-fit"
:
"^0.4.0"
},
"devDependencies"
:
{
"@typescript-eslint/eslint-plugin"
:
"^2.33.0"
,
...
...
src/App.vue
View file @
a3da557
<
template
>
<div
id=
"app"
>
<img
alt=
"Vue logo"
src=
"./assets/logo.png"
/>
<HelloWorld
msg=
"Welcome to Your Vue.js + TypeScript App"
/>
</div>
<div
id=
"xterm"
class=
"xterm"
></div>
</
template
>
<
script
lang=
"ts"
>
import
{
Component
,
Vue
}
from
"vue-property-decorator"
;
import
HelloWorld
from
"./components/HelloWorld.vue"
;
import
"xterm/css/xterm.css"
;
import
{
Xterm
}
from
"./xterm"
;
import
{
FitAddon
}
from
"xterm-addon-fit"
;
import
{
AttachAddon
}
from
"xterm-addon-attach"
;
@
Component
({
components
:
{
HelloWorld
import
{
WebTTY
,
protocols
}
from
"./webtty"
;
import
{
ConnectionFactory
}
from
"./websocket"
;
@
Component
export
default
class
App
extends
Vue
{
socketURL
=
"ws://localhost:8080/ws"
;
closer
:
unknown
=
""
;
term
:
any
=
""
;
mounted
()
{
console
.
log
(
"Mounted"
);
this
.
initTerm
()
}
created
()
{
console
.
log
(
"Created"
);
}
})
export
default
class
App
extends
Vue
{}
//TODO: 样式还需修改。请求后端时改为ws://.../id
initTerm
()
{
const
xt
=
document
.
getElementById
(
"xterm"
);
console
.
log
(
xt
);
if
(
xt
)
{
const
term
:
any
=
new
Xterm
(
xt
);
this
.
term
=
term
;
// const attachAddon = new AttachAddon();
const
fitAddon
=
new
FitAddon
();
// this.term.term.loadAddon(attachAddon);
this
.
term
.
term
.
loadAddon
(
fitAddon
);
fitAddon
.
fit
();
this
.
term
.
term
.
focus
();
const
httpsEnabled
=
window
.
location
.
protocol
==
"https:"
;
const
url
=
(
httpsEnabled
?
"wss://"
:
"ws://"
)
+
"localhost:8080/"
+
"ws"
;
const
args
=
window
.
location
.
search
;
const
factory
=
new
ConnectionFactory
(
url
,
protocols
);
const
wt
=
new
WebTTY
(
term
,
factory
,
args
,
""
);
this
.
closer
=
wt
.
open
();
}
}
}
</
script
>
<
style
>
...
...
src/websocket.ts
0 → 100644
View file @
a3da557
export
class
ConnectionFactory
{
url
:
string
;
protocols
:
string
[];
constructor
(
url
:
string
,
protocols
:
string
[])
{
this
.
url
=
url
;
this
.
protocols
=
protocols
;
};
create
():
Connection
{
return
new
Connection
(
this
.
url
,
this
.
protocols
);
};
}
export
class
Connection
{
bare
:
WebSocket
;
constructor
(
url
:
string
,
protocols
:
string
[])
{
this
.
bare
=
new
WebSocket
(
url
,
protocols
);
}
open
()
{
// nothing todo for websocket
};
close
()
{
this
.
bare
.
close
();
};
send
(
data
:
string
)
{
this
.
bare
.
send
(
data
);
};
isOpen
():
boolean
{
if
(
this
.
bare
.
readyState
==
WebSocket
.
CONNECTING
||
this
.
bare
.
readyState
==
WebSocket
.
OPEN
)
{
return
true
}
return
false
}
onOpen
(
callback
:
()
=>
void
)
{
this
.
bare
.
onopen
=
(
event
)
=>
{
callback
();
}
};
onReceive
(
callback
:
(
data
:
string
)
=>
void
)
{
this
.
bare
.
onmessage
=
(
event
)
=>
{
callback
(
event
.
data
);
}
};
onClose
(
callback
:
()
=>
void
)
{
this
.
bare
.
onclose
=
(
event
)
=>
{
callback
();
};
};
}
src/webtty.ts
0 → 100644
View file @
a3da557
export
const
protocols
=
[
"webtty"
];
export
const
msgInputUnknown
=
'0'
;
export
const
msgInput
=
'1'
;
export
const
msgPing
=
'2'
;
export
const
msgResizeTerminal
=
'3'
;
export
const
msgUnknownOutput
=
'0'
;
export
const
msgOutput
=
'1'
;
export
const
msgPong
=
'2'
;
export
const
msgSetWindowTitle
=
'3'
;
export
const
msgSetPreferences
=
'4'
;
export
const
msgSetReconnect
=
'5'
;
export
interface
Terminal
{
info
():
{
columns
:
number
,
rows
:
number
};
output
(
data
:
string
):
void
;
showMessage
(
message
:
string
,
timeout
:
number
):
void
;
removeMessage
():
void
;
setWindowTitle
(
title
:
string
):
void
;
setPreferences
(
value
:
object
):
void
;
onInput
(
callback
:
(
input
:
string
)
=>
void
):
void
;
onResize
(
callback
:
(
colmuns
:
number
,
rows
:
number
)
=>
void
):
void
;
reset
():
void
;
deactivate
():
void
;
close
():
void
;
}
export
interface
Connection
{
open
():
void
;
close
():
void
;
send
(
data
:
string
):
void
;
isOpen
():
boolean
;
onOpen
(
callback
:
()
=>
void
):
void
;
onReceive
(
callback
:
(
data
:
string
)
=>
void
):
void
;
onClose
(
callback
:
()
=>
void
):
void
;
}
export
interface
ConnectionFactory
{
create
():
Connection
;
}
export
class
WebTTY
{
term
:
Terminal
;
connectionFactory
:
ConnectionFactory
;
args
:
string
;
authToken
:
string
;
reconnect
:
number
;
constructor
(
term
:
Terminal
,
connectionFactory
:
ConnectionFactory
,
args
:
string
,
authToken
:
string
)
{
this
.
term
=
term
;
this
.
connectionFactory
=
connectionFactory
;
this
.
args
=
args
;
this
.
authToken
=
authToken
;
this
.
reconnect
=
-
1
;
};
open
()
{
let
connection
=
this
.
connectionFactory
.
create
();
let
pingTimer
:
any
;
let
reconnectTimeout
:
any
;
const
setup
=
()
=>
{
connection
.
onOpen
(()
=>
{
const
termInfo
=
this
.
term
.
info
();
connection
.
send
(
JSON
.
stringify
(
{
Arguments
:
this
.
args
,
AuthToken
:
this
.
authToken
,
}
));
const
resizeHandler
=
(
colmuns
:
number
,
rows
:
number
)
=>
{
connection
.
send
(
msgResizeTerminal
+
JSON
.
stringify
(
{
columns
:
colmuns
,
rows
:
rows
}
)
);
};
this
.
term
.
onResize
(
resizeHandler
);
resizeHandler
(
termInfo
.
columns
,
termInfo
.
rows
);
this
.
term
.
onInput
(
(
input
:
string
)
=>
{
connection
.
send
(
msgInput
+
input
);
}
);
pingTimer
=
setInterval
(()
=>
{
connection
.
send
(
msgPing
)
},
30
*
1000
);
});
connection
.
onReceive
((
data
)
=>
{
const
payload
=
data
.
slice
(
1
);
switch
(
data
[
0
])
{
case
msgOutput
:
this
.
term
.
output
(
atob
(
payload
));
break
;
case
msgPong
:
break
;
case
msgSetWindowTitle
:
this
.
term
.
setWindowTitle
(
payload
);
break
;
case
msgSetPreferences
:
const
preferences
=
JSON
.
parse
(
payload
);
this
.
term
.
setPreferences
(
preferences
);
break
;
case
msgSetReconnect
:
const
autoReconnect
=
JSON
.
parse
(
payload
);
console
.
log
(
"Enabling reconnect: "
+
autoReconnect
+
" seconds"
)
this
.
reconnect
=
autoReconnect
;
break
;
}
});
connection
.
onClose
(()
=>
{
clearInterval
(
pingTimer
);
this
.
term
.
deactivate
();
this
.
term
.
showMessage
(
"Connection Closed"
,
0
);
if
(
this
.
reconnect
>
0
)
{
reconnectTimeout
=
setTimeout
(()
=>
{
connection
=
this
.
connectionFactory
.
create
();
this
.
term
.
reset
();
setup
();
},
this
.
reconnect
*
1000
);
}
});
connection
.
open
();
}
setup
();
return
()
=>
{
clearTimeout
(
reconnectTimeout
);
connection
.
close
();
}
};
};
src/xterm.ts
0 → 100644
View file @
a3da557
import
{
Terminal
}
from
"xterm"
;
// import { lib } from "libapps"
export
class
Xterm
{
elem
:
HTMLElement
;
term
:
Terminal
;
resizeListener
:
(()
=>
void
)
|
undefined
;
// decoder: lib.UTF8Decoder;
message
:
HTMLElement
;
messageTimeout
:
number
;
messageTimer
:
any
;
constructor
(
elem
:
HTMLElement
)
{
this
.
elem
=
elem
;
this
.
term
=
new
Terminal
();
this
.
message
=
elem
.
ownerDocument
.
createElement
(
"div"
);
this
.
message
.
className
=
"xterm-overlay"
;
this
.
messageTimeout
=
2000
;
this
.
term
.
onResize
(
()
=>
{
this
.
term
.
scrollToBottom
();
this
.
showMessage
(
String
(
this
.
term
.
cols
)
+
"x"
+
String
(
this
.
term
.
rows
),
this
.
messageTimeout
);
});
this
.
term
.
open
(
elem
);
// this.decoder = new lib.UTF8Decoder()
};
info
():
{
columns
:
number
,
rows
:
number
}
{
return
{
columns
:
this
.
term
.
cols
,
rows
:
this
.
term
.
rows
};
};
output
(
data
:
string
)
{
// this.term.write(this.decoder.decode(data));
this
.
term
.
write
(
data
);
};
showMessage
(
message
:
string
,
timeout
:
number
)
{
this
.
message
.
textContent
=
message
;
this
.
elem
.
appendChild
(
this
.
message
);
if
(
this
.
messageTimer
)
{
clearTimeout
(
this
.
messageTimer
);
}
if
(
timeout
>
0
)
{
this
.
messageTimer
=
setTimeout
(()
=>
{
this
.
elem
.
removeChild
(
this
.
message
);
},
timeout
);
}
};
removeMessage
():
void
{
if
(
this
.
message
.
parentNode
==
this
.
elem
)
{
this
.
elem
.
removeChild
(
this
.
message
);
}
}
setWindowTitle
(
title
:
string
)
{
document
.
title
=
title
;
};
setPreferences
(
value
:
object
)
{
};
onInput
(
callback
:
(
input
:
string
)
=>
void
)
{
this
.
term
.
onData
(
data
=>
{
callback
(
data
);
});
};
onResize
(
callback
:
(
colmuns
:
number
,
rows
:
number
)
=>
void
)
{
this
.
term
.
onResize
(
(
data
)
=>
{
callback
(
data
.
cols
,
data
.
rows
);
});
};
deactivate
():
void
{
// this.term.off("data");
// this.term.resize();
this
.
term
.
blur
();
}
reset
():
void
{
this
.
removeMessage
();
this
.
term
.
clear
();
}
close
():
void
{
// window.removeEventListener("resize", this.resizeListener);
this
.
term
.
dispose
();
}
}
Write
Preview
Markdown
is supported
Attach a file
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 post a comment