Skip to content

Commit 542dd40

Browse files
author
Felix
committed
Migrate to xterm
1 parent 7c22827 commit 542dd40

File tree

13 files changed

+141
-181
lines changed

13 files changed

+141
-181
lines changed

chromeapp/css/style.css

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -72,29 +72,11 @@ div {
7272
-webkit-user-select: auto;
7373
}
7474

75-
76-
77-
.terminal {
78-
float: left;
79-
border: #000 solid 5px;
80-
font-family: "DejaVu Sans Mono", "Liberation Mono", monospace;
81-
font-size: 11px;
82-
color: #f0f0f0;
83-
background: #000;
84-
}
85-
8675
.reverse-video {
8776
color: #000;
8877
background: #f0f0f0;
8978
}
9079

91-
.terminal-col-fixed{
92-
width:1030px;
93-
//background:red;
94-
//position:fixed;
95-
height:100%;
96-
}
97-
9880
.modal-backdrop {
9981
z-index:100; /* default makes modal be hidden behind the modal-backdrop div.*/
10082
}

chromeapp/src/main/scala/util/ChromePlatformService.scala

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import scala.concurrent.ExecutionContext.Implicits.global
1616
import scala.concurrent.{Future, Promise}
1717
import scala.scalajs.js
1818
import scala.scalajs.js.Function1
19+
import scala.scalajs.js.typedarray.ArrayBuffer
1920

2021
object ChromePlatformService extends PlatformService {
2122
override def appVersion: String = chrome.runtime.getManifest().version
@@ -208,32 +209,14 @@ class ChromeDockerConnection(val connection: Connection) extends DockerConnectio
208209
// Bridge between common class and Chrome WebSocket
209210
class WebSocketAdapter(socket: WebSocket) extends BasicWebSocket {
210211

211-
override def send(data: String): Unit = socket.send(data)
212+
override def send(data: js.Any): Unit = socket.send(data.asInstanceOf[ArrayBuffer])
212213

213214
override def close(code: Int, reason: String): Unit = socket.close(code, reason)
214215

215-
socket.onopen = { event: Event => this.onopen() }
216-
socket.onmessage = { event: MessageEvent =>
217-
this.onmessage(new {
218-
def data = event.data.asInstanceOf[js.Any]
219-
})
220-
}
221-
socket.onclose = { event: CloseEvent =>
222-
this.onclose(new {
223-
def code = event.code
224-
})
225-
}
226-
227-
socket.onerror = { event: ErrorEvent =>
228-
this.onerror(new {
229-
def message = event.message
230-
})
231-
}
232-
233-
override var onopen: Function1[Unit, _] = { x: Unit => () }
234-
override var onmessage: js.Function1[ {def data: js.Any}, _] = { x: {def data: js.Any} => () }
235-
override var onclose: js.Function1[ {def code: Int}, _] = { x: {def code: Int} => () }
236-
override var onerror: js.Function1[ {def message: String}, _] = { x: {def message: String} => () }
216+
def addEventListener(`type`: String, listener: js.Function1[Any, _]): Unit =
217+
socket.addEventListener(`type`,listener)
237218

219+
def removeEventListener(`type`: String, listener: js.Function1[Any, _]): Unit =
220+
socket.addEventListener(`type`,listener)
238221

239222
}

electron/bower.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@
1919
"bootstrap": "~3.3.4",
2020
"bootcards": "~1.1.0",
2121
"font-awesome": "~4.3.0",
22-
"term.js": "~0.0.3"
22+
"xterm.js": "2.2.3"
2323
}
2424
}

electron/css/style.css

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -73,27 +73,11 @@ div {
7373
}
7474

7575

76-
77-
.terminal {
78-
float: left;
79-
border: #000 solid 5px;
80-
font-family: "DejaVu Sans Mono", "Liberation Mono", monospace;
81-
font-size: 11px;
82-
color: #f0f0f0;
83-
background: #000;
84-
}
85-
8676
.reverse-video {
8777
color: #000;
8878
background: #f0f0f0;
8979
}
9080

91-
.terminal-col-fixed{
92-
width:1030px;
93-
//background:red;
94-
//position:fixed;
95-
height:100%;
96-
}
9781

9882
.modal-backdrop {
9983
z-index:100; /* default makes modal be hidden behind the modal-backdrop div.*/

electron/index.html

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,23 @@
5353
<script src="./bower_components/chrome-platform-analytics/google-analytics-bundle.js"></script>
5454

5555
<script type="text/javascript"
56-
src="./bower_components/term.js/src/term.js"></script>
56+
src="./bower_components/xterm.js/dist/xterm.js"></script>
57+
58+
<script type="text/javascript"
59+
src="./bower_components/xterm.js/dist/addons/attach/attach.js"></script>
60+
61+
<script type="text/javascript"
62+
src="./bower_components/xterm.js/dist/addons/terminado/terminado.js"></script>
63+
64+
65+
<script type="text/javascript"
66+
src="./bower_components/xterm.js/dist/addons/fit/fit.js"></script>
67+
5768

5869
<link rel="stylesheet" href="./bower_components/font-awesome/css/font-awesome.min.css">
5970

71+
<link rel="stylesheet" href="./bower_components/xterm.js/dist/xterm.css" />
72+
6073
</head>
6174
<body>
6275
<div class="main-container">

electron/src/main/scala/util/ElectronPlatformService.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,15 @@ class ElectronDockerConnection(val connection: Connection) extends DockerConnect
112112
if (msg == null) {
113113
if (dialOptions.hijack) {
114114
processHijackResponse(onWebSocketCreated, response)
115+
115116
} else if (dialOptions.isStream) {
116117
def onComplete { p.success(Response("", 200)) }
117118
processStreamingResponse(onStreamingData, shouldAbort, onComplete, response)
119+
118120
} else {
119121
val responseText = js.Dynamic.global.JSON.stringify(response).asInstanceOf[String]
120122
p.success(Response(responseText, 200))
123+
121124
}
122125
} else {
123126
log.debug(s"dial fail: $msg")
@@ -197,6 +200,7 @@ class ElectronDockerConnection(val connection: Connection) extends DockerConnect
197200
hijack = true,
198201
openStdin = true
199202
)
203+
200204
dial(options, onWebSocketCreated = onWebSocketCreated)
201205
.onFailure { case ex: Exception =>
202206
log.debug(s"Unable to connect WS - ${ex.toString}")
Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,68 @@
11
package util
22

33
import model.BasicWebSocket
4+
import org.scalajs.dom.raw.Event
45
import util.logger.log
5-
66
import scala.language.reflectiveCalls
77
import scala.scalajs.js
8-
import scala.scalajs.js.Function1
8+
import scala.scalajs.js.annotation.{JSExport, JSExportAll}
9+
10+
import js.Dynamic.{ global => g, newInstance => jsnew }
911

1012
@js.native
1113
trait HijackSocket extends js.Object {
12-
def addListener(eventName: String, listener: js.Function1[js.Dynamic, _]): this.type = js.native
13-
def write(data: String): Unit = js.native
14+
def addListener(eventName: String, listener: js.Function1[_, _]): this.type = js.native
15+
16+
def removeListener(eventName: String, listener: js.Function1[_, _]): this.type = js.native
17+
def write(data: js.Any): Unit = js.native
1418
def destroy(): Unit = js.native
1519
}
1620

21+
@JSExportAll
22+
case class CustomTextEvent(data: String)
1723

24+
@JSExportAll
1825
class HijackWebSocket(socket: HijackSocket) extends BasicWebSocket {
1926

2027
socket.addListener("data", { socketData: js.Any =>
2128
log.debug(s"HijackWebSocket data: $socketData")
22-
onmessage(new {
23-
def data = socketData
24-
})
2529
})
2630

2731
socket.addListener("connect", { socketData: js.Any =>
2832
log.debug(s"HijackWebSocket connect: $socketData")
29-
onopen()
3033
})
3134

32-
socket.addListener("close", { socketData: js.Any =>
33-
log.debug(s"HijackWebSocket close: $socketData")
34-
onclose(new {
35-
def code = 1
36-
})
37-
})
38-
39-
socket.addListener("error", { socketData: js.Dynamic =>
40-
log.debug(s"HijackWebSocket error: $socketData")
41-
onerror(new {
42-
def message = socketData.message.toString
43-
})
44-
})
45-
46-
override def send(data: String): Unit = {
35+
@JSExport
36+
override def send(data: js.Any): Unit = {
4737
socket.write(data)
4838
}
4939

40+
@JSExport
5041
override def close(code: Int, reason: String): Unit = {
5142
socket.destroy()
5243
}
5344

54-
// Default impl, will be replaced by the attached Terminal
55-
override var onopen: Function1[Unit, _] = { x: Unit => () }
56-
override var onmessage: js.Function1[ {def data: js.Any}, _] = { x: {def data: js.Any} => () }
57-
override var onclose: js.Function1[ {def code: Int}, _] = { x: {def code: Int} => () }
58-
override var onerror: js.Function1[ {def message: String}, _] = { x: {def message: String} => () }
45+
@JSExport
46+
def addEventListener(`type`: String, listener: js.Function1[Any, _]): Unit = {
47+
if (`type` == "message") {
48+
socket.addListener("data", { socketData: js.Any =>
49+
log.debug(s"HijackWebSocket data: $socketData")
50+
val decoder = jsnew(g.TextDecoder)("utf-8")
51+
val data = decoder.decode(socketData).replace("\r$/g", "\r\n")
52+
listener(new CustomTextEvent(data.toString.replace("\n", "\r\n")))
53+
()
54+
})
55+
} else {
56+
socket.addListener(`type`, listener)
57+
}
58+
59+
}
60+
61+
@JSExport
62+
def removeEventListener(`type`: String, listener: js.Function1[Any, _]): Unit = {
63+
if (`type` == "message") {
64+
socket.removeListener("data", listener)
65+
}
66+
socket.removeListener(`type`, listener)
67+
}
5968
}

src/main/scala/api/DockerClient.scala

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ case class DockerClient(con: DockerConnection) {
124124
}
125125

126126
private def removeImage(imageId: String): Future[Unit] = {
127-
val id = imageId.replace("sha256:","")
127+
val id = imageId.replace("sha256:", "")
128128
con.delete(path = s"/images/$id").map { xhr =>
129129
log.info("[dockerClient.removeImage] return: " + xhr.statusCode)
130130
}.transform(identity, ex => ex match {
@@ -204,10 +204,11 @@ case class DockerClient(con: DockerConnection) {
204204
}
205205

206206
val tasksFut = orderedImages.map { imagesToGC =>
207-
val tasks = imagesToGC.map { image => () => {
208-
status(s"Removing ${image.id}/ ${image.RepoTags.mkString(" ")}")
209-
removeImage(image)
210-
}
207+
val tasks = imagesToGC.map { image =>
208+
() => {
209+
status(s"Removing ${image.id}/ ${image.RepoTags.mkString(" ")}")
210+
removeImage(image)
211+
}
211212

212213
}
213214
FutureUtils.sequenceWithDelay(tasks, FutureUtils.LongDelay, ignoreErrors = true)
@@ -240,6 +241,7 @@ case class DockerClient(con: DockerConnection) {
240241
case head :: tail => removeContainer(head.Id).andThen { case _ => delete(tail) }
241242
case Nil => Future.successful(())
242243
}
244+
243245
delete(all.drop(KeepInGarbageCollection).toList)
244246
}
245247
}
@@ -338,7 +340,11 @@ case class DockerClient(con: DockerConnection) {
338340

339341
// https://docs.docker.com/engine/reference/api/docker_remote_api_v1.19/#get-container-stats-based-on-resource-usage
340342
def containerStats(containerId: String)(updateUI: (Option[ContainerStats], ConnectedStream) => Unit): Unit =
341-
con.containerStats(containerId)(updateUI)
343+
con.containerStats(containerId)(updateUI)
344+
345+
def resizeTTY(containerId: String, h: Int, w: Int) = {
346+
con.post(path = s"/containers/$containerId/resize?h=$h&w=$w")
347+
}
342348
}
343349

344350
trait ConnectedStream {

src/main/scala/model/WebSocket.scala

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,10 @@ import scala.scalajs.js
66
// Shared code between Chrome app WebSocket and Node.js Socket
77
trait BasicWebSocket {
88

9-
var onmessage: js.Function1[ {def data: js.Any}, _]
10-
11-
var onopen: js.Function1[ Unit, _]
12-
13-
var onclose: js.Function1[ {def code: Int}, _]
14-
15-
var onerror: js.Function1[ {def message: String}, _]
16-
17-
def send(data: String): Unit
9+
def send(data: js.Any): Unit
1810

1911
def close(code: Int, reason: String): Unit
12+
13+
def addEventListener(`type`: String, listener: js.Function1[Any, _]): Unit
14+
def removeEventListener(`type`: String, listener: js.Function1[Any, _]): Unit
2015
}

0 commit comments

Comments
 (0)