vscode server源码解析(三) - code server

如果初次接触code server,可以看我的code server介绍
如果对于整体架构还不清楚,可以看我的架构分析
在正式开始看代码前,我们再分析code server在整个远程开发方案中的作用。

Code Server在整个远程开发中的作用

1、code server最重要的作用就是server,也就是提供了服务器能力,能够将远程机器上的ide作为一个服务提供给外部,访问并使用,所以,code server本质是一个基于express框架,nodejs平台的轻量级服务器
2、code server提供了用户登录功能,使得ide即使作为一个服务可供外部访问,依旧可以保证安全性;且只有在用户登录后,才真正去加载vscode server内核代码
3、code server还提供了升级、代理、心跳检测等功能,当然这些都是基础的服务器功能,我们今天也不细说

我们今天就重点解析一下几个方面的代码
1、code server是如何启动的
2、code server是如何把ide作为一个服务提供出去的
3、code server的中间件和路由
4、code server如何启动vscode内核的

由于code server是一个基于express的框架,最好了解express框架再看,我之后也会补上相关文档,这里就不细说框架的知识了

Code Server程序入口

code server的入口文件是src/node/entry.ts,我们启动code server时候的命令是
./code-server --host 0.0.0.0 --port 9002
这个code-server实际就是个shell脚本,cat命令查看就能知道他本质上就是用node去启动程序,

# root其实code server的根目录,相当于`node .`,这样node会自动去package.json中找定义的入口文件
exec "$ROOT/lib/node" "$ROOT" "$@"

入口文件可以在package.json中看到定义

"main": "out/node/entry.js"

所以我们先从这个文件看,好吧,一来就是个难点,大家能看到有个判断isChild,这里我们就要叉出去说了,code server实际最终会启动两个nodejs进程
一个是父进程,他的逻辑非常简单,主要用于管理整个软件,启动子进程并且控制其生命周期;与其通信,比如接收子进程的日志输出,并打印到日志文件中
另一个是子进程,父进程启动后会去启动子进程,子进程才是真正的express框架的服务器,也是之后加载vscode server内核代码的进程

那么这里的逻辑就是,判断当前的进程是不是子进程,如果是父进程,就执行wrapper.start,就是我上面说的,去启动子进程,并与其建立通信
如果是子进程呢,先通过handshake和父进程建立通信,随后执行最重要的方法runCodeServer启动Code Server服务器

async function entry(): Promise<void> {
   // 判断父子进程
  if (isChild(wrapper)) {
    // 与父进程建立连接
    const args = await wrapper.handshake()
    wrapper.preventExit()
    // 真正地启动code server服务器
    const server = await runCodeServer(args)
    wrapper.onDispose(() => server.dispose())
    return
  }
  
  // 中间省略了部分内容,不影响当前分析
  
  // 父进程执行,实际是去启动子进程
  return wrapper.start(args)
}

父子进程相关代码在src/node/wrapper.ts,大概代码是

export class ParentProcess extends Process {}
export class ChildProcess extends Process {}

// 通过instanceof判断是不是子进程
export function isChild(proc: ChildProcess | ParentProcess): proc is ChildProcess {
  return proc instanceof ChildProcess
}

Code Server服务器启动

runCodeServer方法看起来内容很多,实际重要的就几行
1、通过createApp
2、通过register方法注册中间件和路由

export const runCodeServer = async (
  args: DefaultedArgs,
): Promise<{ dispose: Disposable["dispose"]; server: http.Server }> => {
	const app = await createApp(args)
    const disposeRoutes = await register(app, args)
}

咱们先说createApp,非常清晰,就是原生nodejs的http.createServer启动了服务器,然后监听我们传入的host和port,这样我们的ide就可以作为一个服务对外提供访问啦
然后一个重要的方法handleUpgrade就是这里注册了处理websocket连接的中间件,还记得我们架构篇说的,vscode server前后台的通信方式依赖websocket,这个我们之后专门出一篇websocket文档详细说明

export const createApp = async (args: DefaultedArgs): Promise<App> => {
 // 如果看源码会发现这里会判断args.cert,这个我们先省略,不影响理解
  const server = http.createServer(router)
  await listen(server, args)
  // 处理websocket的中间件
  handleUpgrade(wsRouter, server)
}

// listen方法里面就是server监听,监听我们启动命令传入的host和port
server.listen(opts.port, opts.host.replace(/^\[|\]$/g, ""), onListen)

我们接着说路由和中间件
如果你之前接触过express就很好理解了,没接触过也没事
路由简单来说,就是作为一个服务器提供GET/POST这种接口,供前台去调用,例如下面的router.get
假设我们前台发送请求到后台,http://172.22.22.22:9002/,最后的"/"就会匹配上这个路由,然后执行这里定义的回调函数

中间件呢?中间件也是一个函数通过use()方法注册到express框架中,注册的先后顺序也会影响执行顺序,比如下面的这段代码,就是先执行router.use中的方法,进行鉴权,通过了再使用next()方法到下一步router.get()中的函数

// 这个中间件就是在请求到达路由前执行的,通过authenticated方法鉴权
router.use(async (req, res, next) => {
  const to = (typeof req.query.to === "string" && req.query.to) || "/"
  if (await authenticated(req)) {
    return redirect(req, res, to, { to: undefined })
  }
  next()
})

// 通过验证后,通过getRoot返回资源
router.get("/", async (req, res) => {
  res.send(await getRoot(req))
})

好了我们说回code server,register方法里面就是大量处理路由和中间件的逻辑,比如/login的请求路径分发到Login Router,/health的分发到Health Router,每个Router里面又有各自的中间件去处理这些请求

vscode server内核启动

好吧,我们差不多要说code server是如何启动vscode server的内核了,其实也就是我们上面说的路由和中间件
逻辑在这个文件src/node/routes/vscode.ts
在经过了鉴权等路由之后,我们的请求会到达这个路由

this.router.get("/", this.ensureCodeServerLoaded, this.$root)

ensureCodeServerLoaded就是负责加载vscode代码的中间件
loadAMDModule实际就是原生vscode启动的那一套,实际是一个require引入模块,这里可以先忽略这点
加载后可以获得一个createVSServer方法,他就是真正去启动vscode内核的方法,在之后的文章说明

 private ensureCodeServerLoaded: express.Handler = async (req, _res, next) => {
     // See ../../../lib/vscode/src/vs/server/node/server.main.ts:72.
   const createVSServer = await loadAMDModule<CreateServer>("vs/server/node/server.main", "createServer")

   try {
     this._codeServerMain = await createVSServer(null, {
       ...(await toCodeArgs(args)),
       "without-connection-token": true,
     })
   } catch (error) {
     logError(logger, "CodeServerRouteWrapper", error)
     if (isDevMode) {
       return next(new Error((error instanceof Error ? error.message : error) + " (VS Code may still be compiling)"))
     }
     return next(error)
   }
 }
 
export const loadAMDModule = async <T>(amdPath: string, exportName: string): Promise<T> => {
  // Set default remote native node modules path, if unset
  process.env["VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH"] =
    process.env["VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH"] || path.join(vsRootPath, "remote", "node_modules")

  require(path.join(vsRootPath, "out/bootstrap-node")).injectNodeModuleLookupPath(
    process.env["VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH"],
  )

  const module = await new Promise<AMDModule<T>>((resolve, reject) => {
    require(path.join(vsRootPath, "out/bootstrap-amd")).load(amdPath, resolve, reject)
  })

  return module[exportName] as T
}

好了,现在code server的使命基本完成了,ide已经具备作为一个服务器对外访问的能力啦!
我们下一步解说vscode server内核,还有websocket协议~

  • 30
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要在Linux ARM平台上下载VSCode服务器,可以按照以下步骤进行操作。 首先,在你的Linux ARM设备上打开一个终端窗口。 然后,你可以前往VSCode官方网站(https://code.visualstudio.com/)找到“下载”选项,并选择“Server”标签。在“Server”标签页中,你可以找到不同操作系统和架构的VSCode服务器版本。 接下来,找到适用于Linux ARM架构的VSCode服务器版本并点击下载。你可以将下载的文件保存到你喜欢的位置,例如主目录或某个特定文件夹。 下载完成后,找到下载好的文件并解压缩它。你可以使用一些常用的解压工具,如tar命令或图形化解压软件。 解压缩后,你将得到一个文件夹,其中包含VSCode服务器的文件。 进入该文件夹,并找到其中的可执行文件。该文件通常称为“code-server”或类似的名称。你可以使用终端命令cd进入该文件夹,然后运行ls命令以查看其中的文件列表。 在终端中,使用Linux启动命令来启动VSCode服务器。这通常是运行"./code-server"或"./code-server --port=8080"等命令。 启动服务器后,在终端中会显示一些信息,包括服务器正在监听的端口号。 现在,你可以在你的Linux ARM设备的Web浏览器中访问该设备的IP地址,并在后面添加服务器监听的端口号(例如:http://192.168.1.100:8080)。这将打开VSCode服务器界面,并让你开始使用它。 总而言之,要在Linux ARM平台上下载VSCode服务器,你需要下载适用于该平台的版本并解压缩它,然后使用Linux命令启动服务器并在浏览器中访问它。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值