一直想做一个在线交互式编程的学习平台,最近因为教育创业的缘故,所以按捺不住内心的冲动,终于开始撸了~
(和我一样激动的小伙伴别激动,目前只是花了一上午搞的个 Demo 而已)
我用的是Rails 6.1
版本,ruby 2.7.4
。
不知道有没有人一样和我发现在 Mac Big Sur 上安装Ruby 3.0+
困难重重?
rails new
命令:$ rails new demo
create
create README.md
create Rakefile
create .ruby-version
create config.ru
create .gitignore
create .gitattributes
create Gemfile
run git init from "."
....
├─ [email protected]
├─ [email protected]
├─ [email protected]
├─ [email protected]
└─ [email protected]
Done in 4.98s.
Webpacker successfully installed 🎉 🍰
建议新手别用
Rails 6
, 我碰到过很多工作很多年的前端都玩不转前端那一套打包工具。。。。
再次吐槽一下,Rails 6
一点也不 Rails
...
$ rails webpack:install
scaffold
$ rails g scaffold casts title url
[WARNING] The model name 'casts' was recognized as a plural, using the singular 'cast' instead. Override with --force-plural or setup custom inflection rules for this noun before running the generator.
invoke active_record
create db/migrate/20210823080552_create_casts.rb
create app/models/cast.rb
invoke test_unit
create test/models/cast_test.rb
create test/fixtures/casts.yml
invoke resource_route
route resources :casts
invoke scaffold_controller
create app/controllers/casts_controller.rb
invoke erb
create app/views/casts
create app/views/casts/index.html.erb
create app/views/casts/edit.html.erb
create app/views/casts/show.html.erb
create app/views/casts/new.html.erb
create app/views/casts/_form.html.erb
invoke resource_route
invoke test_unit
create test/controllers/casts_controller_test.rb
create test/system/casts_test.rb
invoke helper
create app/helpers/casts_helper.rb
invoke test_unit
invoke jbuilder
create app/views/casts/index.json.jbuilder
create app/views/casts/show.json.jbuilder
create app/views/casts/_cast.json.jbuilder
invoke assets
invoke scss
create app/assets/stylesheets/casts.scss
invoke scss
identical app/assets/stylesheets/scaffolds.scss
$ rails db:migrage
== 20210823080552 CreateCasts: migrating ======================================
-- create_table(:casts)
-> 0.0020s
== 20210823080552 CreateCasts: migrated (0.0021s) =============================
xterm.js
$ yarn add xterm
yarn add v1.22.10
[1/4] 🔍 Resolving packages...
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
[4/4] 🔨 Building fresh packages...
success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ [email protected]
info All dependencies
└─ [email protected]
✨ Done in 2.54s.
xterm-addon-attach
$ yarn add xterm-addon-attach
yarn add v1.22.10
[1/4] 🔍 Resolving packages...
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
[4/4] 🔨 Building fresh packages...
success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ [email protected]
info All dependencies
└─ [email protected]
✨ Done in 2.47s.
app/javascript/packs/application.js
加入:require("xterm/css/xterm.css") // 偶个人觉得不太rails way...
import { Terminal } from "xterm"
import { AttachAddon } from 'xterm-addon-attach';
app/views/layouts/application.html.erb
中添加以下一行代码:<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
完整的代码如下:
<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<%= yield %>
</body>
</html>
app/javascript/packs/application.js
加入:document.addEventListener("turbolinks:load", () =>{
var term = new Terminal();
term.open(document.getElementById('terminal'));
const socket = new WebSocket('ws://localhost:5020/containers/b6bb364f6d06/attach/ws?stream=1&stdout=1');
const attachAddon = new AttachAddon(socket);
// Attach the socket to term
term.loadAddon(attachAddon);
term.write("Hello from \x1B[1;3;31mxterm.js\n\x1B[0m $ ");
})
WebSocket
的地址这样获得:之前分享过一篇Caddy 相关的文章,为了让这个例子,更具有通用性,特修改一下,不用socat,
改用Caddy
首先安装 socat
$ brew install socat
其次运行以下命令:
$ socat TCP-LISTEN:5020,reuseaddr,fork UNIX-CLIENT:$HOME/Library/Containers/com.docker.docker/Data/docker.raw.sock
Caddy
$ brew install caddy
touch
一个 Caddyfile
$ touch Caddyfile
Caddyfile
文件中输入以下代码:8080 {
reverse_proxy unix//Users/i/Library/Containers/com.docker.docker/Data/docker.raw.sock
}
WebSocket
的地址中的b6bb364f6d06
是 container 的 ID。
理论上来说,Docker 和 host 的共用的是
/var/run/docker.sock
,但是 Mac 上读取不出数据,有知道的可以解释一下?
总之,这里走的唯一的弯路就是这个sock
的地址。
然后我们再编辑一下app/views/casts/index.html.erb
在最下面添加一行:
<div id="terminal" style="width:800px;height:600px"></div>
重点是添加一个 id 是
terminal
的 div
rails s
$ rails s
这时候我们还需要一个启动 docker 镜像,启动的命令里面要加入-i -t
的参数,具体参数的意义最好参考一下官方文档。
这个对容器是有要求的,具体可以参考:https://docs.docker.com/engine/reference/commandline/attach/
到这里可以得出结论,xterm.js attach 到容器,最终能不能进行交互,和容器的 ENTRYPOINT/CMD 的命令有很大的关系。如果在创建容器时没指定 -it 或者 ENTRYPOINT/CMD 不是 bash 之类的可交互进程,xterm.js 虽然可以连接到容器,但都不可以与容器进行交互的。 而实际情况是,绝大多数的容器事务,这两个条件都没有。
我们这里贴出参考命令:
$ docker run --name test -d -it debian
然后就可以交互了:
参考文档:https://unihon.github.io/2019-05/use-xterm-js-attach-to-docker-container/
说明:这种教程,相比国外的同类教程来说已经写的非常简约了。我希望后续我基础类教程的分享甚至包括我解决小 bug 的过程。
大牛请绕道~