# 开发指南

这里会叙述 Console Lite 的基本架构和你在阅读我(Liu)写的代码时可能需要的Pit Fall。

# 架构

Console Lite 的基本架构类似 IM:高度中心化,真正干活的只有后端的存储层和前端的逻辑层,基本上由上至下可以表示为:

  • 前端显示(controller/view/**/*.js)
  • 前端逻辑(controller/action.js)
  • 前端连接(controller/connection/*.js)
  • 后端连接(server/socket.js)
  • 后端存储(server/backend/*.js)

投影窗口的所有事件都是从控制窗口转发的,不直接连接后端。

使用的技术是:

  • 共享
    • 运行时: Electron (可执行无限大)
    • 连接: Socket.io (WebSocket)
  • 前端
    • 语言: HTML5 CSS3 Javascript(ES6 <- V8真是猛,我就是骨粉)
    • 框架: Vue 1.0
  • 后端
    • 框架: 没有框架
    • DB: LevelDB

一些额外用到的库:

  • NodeJieba (拼音排序和补全)

# 阅读代码

整个项目分为三部分:

  • 控制窗口 Controller: /controller
  • 投影窗口 Projector: /projector
  • 后端 Server: /server

大多数的代码都应该是自解释的,在这里我解释一些有意或无意的设计(失误)造成的逻辑混乱:

# 投票的 Target

在投票里,目标 target 可能有如下值:

  • 0 无目标
  • 正数 目标票数
  • -1 文件三分之二

这么设计的原因是我之前把文件三分之二这茬忘了,就这样,嘻嘻。

# 投票的 vote

在投票矩阵中,vote 可能有如下值:

  • 1 赞同
  • 0 未投票/过
  • -1 弃权
  • -2 反对

这样规定的原意是在排序和画进度条的时候吧弃权放到中间,但是后来发现目标可能会跟随弃权的票数而改变,在文件三分之二中,目标更类似于赞同和反对中间的三分之二。为了在进度条中反映这一点,把弃权放到了反对的后面。说到底还是把文件三分之二忘了。

# 十万个连接层

抽象有什么错!说不定以后有 App 呢?你就忍忍吧,至少我把名字都起成一样的了。

# 事件传递

你可能注意到,控制端的更新是跟随服务端 Pingback 的事件更新的,即使事件的来源是自身,目的是保证与服务端同步。考虑如下场景:

A 发送了一个请求
B 发送了一个请求
B 接收到了 A 请求的 pingback
B 接收到了自己请求的 pingback

如果这个请求的顺序是很重要的,例如在计时器中,A 请求更新计时器,B 请求开始计时器,那么 B 处计时器的状态在接受 A pingback 之后会变为停止。

这个特性造成了一个副作用,在发言名单中凸显很明显,就是闪烁。在发言名单中拖动重排席位后,拖动的席位会飞到原来的位置然后又飞回来。解决方法是加了一个延迟再允许上游更新被显示。

# getFile 的 pingback 事件

和其他所有事件都不同,getFile 事件的返回事件后缀带有文件 ID,主要是考虑到文件较大,传输时间较长,为了区分多个请求而加的。其他的请求不加是基于对操作者手速的蔑视。毕竟这是局域网,数据库还是带缓存的 k-v 数据库。

# rebuildNative

事情是这样的: Electron 提供的 ABI 版本很飘逸,现在是 49,超过了 Node.js 最新版本的 ABI 48。项目所用的一个依赖 Leveldown 会自动根据 Node 版本下载已经编译好的二进制。这就麻烦了,和 Electron 不配套,所以需要根据 Electron 提供的头文件重新编译一次。另一个意义在于当 Node 真的到 49了,鬼知道 V8 版本和现在的 electron 一样不一样,到时候如果 ABI 检查通过但是 ABI 不兼容麻烦就大了。

# 下载

跟随 https://github.com/CircuitCoder/Console-Lite 的指引即可。

提一句,如果 Electron 的下载速度太慢,请使用淘宝的镜像。以 Linux 为例,在npm install前:

export ELECTRON_MIRROR https://npm.taobao.org/mirrors/electron/