用 Rails 开发 WebSSH(入门版)

简介: 用 Rails 开发 WebSSH(入门版)

一直想做一个在线交互式编程的学习平台,最近因为教育创业的缘故,所以按捺不住内心的冲动,终于开始撸了~

(和我一样激动的小伙伴别激动,目前只是花了一上午搞的个 Demo 而已)

屏幕截图 2023-09-06 114811.png


我用的是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 "."
     ....
├─ webpack-dev-middleware@5.0.0
├─ webpack-dev-server@4.0.0
├─ websocket-driver@0.7.4
├─ websocket-extensions@0.1.4
└─ ws@8.2.0
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
└─ xterm@4.13.0
info All dependencies
└─ xterm@4.13.0
✨  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
└─ xterm-addon-attach@0.6.0
info All dependencies
└─ xterm-addon-attach@0.6.0
✨  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 $ ");
})

======== UPDATE:采用更通用的方法 ========

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

然后就可以交互了。

GITHUB 仓库地址

参考文档:https://unihon.github.io/2019-05/use-xterm-js-attach-to-docker-container/

说明:这种教程,相比国外的同类教程来说已经写的非常简约了。我希望后续我基础类教程的分享甚至包括我解决小 bug 的过程。

大牛请绕道~

相关文章
|
数据采集 移动开发 前端开发
如何使用JavaScript实现前端导入和导出excel文件(H5编辑器实战复盘)
最近笔者终于把H5-Dooring的后台管理系统初步搭建完成, 有了初步的数据采集和数据分析能力, 接下来我们就复盘一下其中涉及的几个知识点,并一一阐述其在Dooring H5可视化编辑器中的解决方案. 笔者将分成3篇文章来复盘, 主要解决场景如下
977 0
|
9月前
|
开发框架 监控 JavaScript
解锁鸿蒙装饰器:应用、原理与优势全解析
ArkTS提供了多维度的状态管理机制。在UI开发框架中,与UI相关联的数据可以在组件内使用,也可以在不同组件层级间传递,比如父子组件之间、爷孙组件之间,还可以在应用全局范围内传递或跨设备传递。
269 2
|
Linux 文件存储 开发工具
贝锐花生壳内网穿透:无需公网IP,远程访问自建WebDAV文件共享!
WebDAV共享协议支持几乎所有系统和设备,极大方便了文件共享。群晖NAS等设备可通过安装WebDAV套件实现文件共享,结合花生壳内网穿透服务,只需三步即可实现远程访问。具体步骤包括:1. 安装花生壳客户端;2. 登录并配置映射;3. 创建映射,生成远程访问地址。这样,用户可以随时随地访问和管理文件资源。
770 3
|
Cloud Native 容器 Kubernetes
基于阿里云服务网格流量泳道的全链路流量管理(三):无侵入式的宽松模式泳道
本文简要讨论了使用流量泳道来实现全链路流量灰度管理的场景与方案,并回顾了阿里云服务网格 ASM 提供的严格与宽松两种模式的流量泳道、以及这两种模式各自的优势与挑战。接下来介绍了一种基于 OpenTelemetry 社区提出的 baggage 透传能力实现的无侵入式的宽松模式泳道,这种类型的流量泳道同时具有对业务代码侵入性低、同时保持宽松模式的灵活特性的特点。同时,我们还介绍了新的基于权重的流量引流策略,这种策略可以基于统一的流量匹配规则,将匹配到的流量以设定好的比例分发到不同的流量泳道。
73740 16
基于阿里云服务网格流量泳道的全链路流量管理(三):无侵入式的宽松模式泳道
|
安全 Oracle 关系型数据库
看完这篇 教你玩转渗透测试靶机vulnhub——FunBox4(CTF)
看完这篇 教你玩转渗透测试靶机vulnhub——FunBox4(CTF)
488 1
看完这篇 教你玩转渗透测试靶机vulnhub——FunBox4(CTF)
|
项目管理 C++
【VS Code】安装配置调试C/C++(二)
【VS Code】安装配置调试C/C++(二)
272 1
|
SQL 存储 网络协议
为什么MySQL默认的隔离级别是RR而大厂使用的是RC?
为什么MySQL默认的隔离级别是RR而大厂使用的是RC?
984 0
为什么MySQL默认的隔离级别是RR而大厂使用的是RC?
|
缓存 Java Android开发
Android Gradle Plugin 源码解析(上)
一、源码依赖 本文基于: android gradle plugin版本: com.android.tools.build:gradle:2.
2312 0
|
人工智能 物联网 大数据
阿里云认证考试多少分通过?没通过可以补考吗?
什么是未来最有发展力的行业,十个人中八个人都会回答IT行业,对于广大的普通人来说,计算机行业是能够快速挣钱的唯一行业了。
阿里云认证考试多少分通过?没通过可以补考吗?
|
算法 C语言
【C语言】——函数--递归及习题练习
【C语言】——函数--递归及习题练习