Background
大概是这样的。去年大概也是这个时候,欢迎新生新生晚会(关于这个槽点很多,入学2个月才开的晚会,而且参加的都是新生)上我做了一个微信公共号弹幕。大概的功能呢,相当于在大屏幕上开一个网页,然后用微信给指定的公共号发消息,然后弹幕就显示到屏幕上。
当时比较弱。。(现在也很弱,当时更弱)用flask阻塞的long polling + (commentCoreLibrariy)[https://github.com/jabbany/CommentCoreLibrary]随便写了一个东西。当时还年轻,很多细节没有处理。比如如何防止某些弹幕重复播放啊,如何满足高并发的需求啊,如何让多个公共号一起使用啊。balabala都没有。这一次又有了类似的需求,于是我准备用canvas + reactjs + koajs +mongodb搭一个方便的玩意儿。
Details
大概的框架是这样的。最后做出来的界面会分成两个,第一个是放弹幕的,第二个是管理页面。管理页面会做成方便其他微信公共号管理员用自己的公共号接入的一个页面。
这一部分我们要解决的问题是
1. 在页面上显示发送的弹幕。
2. 从服务器端拖弹幕信息,并保证同一条弹幕不会被拖多次。
3. 管理页面。方便管理弹幕字体、大小、速度等等等的setting。
bonus: 引入Google Slider, 在弹幕后面可以使用ppt。
Danmaku frontend
首先是第一个问题,我决定放弃不支持canvas的用户(这个问题别问为什么了,你用IE还有理?)。所以请大家在使用这个库的时候千万要使用最新版的Chrome或者Firefox。
写这个弹幕就有点像写canvas小游戏一样,一帧一帧地处理。
// 前端 danmaku.js
// danmakuList 是从服务器拖下来的还没进入屏幕的弹幕
// danmakuOnScreen 是已经在屏幕上的弹幕
function update(){
// insert
for (var i = 0; i < danmakuList.length; ++i) {
var newDanmaku = {
'x': viewWidth,
'y': (parseInt(Math.random() * (viewHeight / danmakuSettings["fontSize"] - 1)) + 1)* danmakuSettings["fontSize"],
'content': danmakuList[i].content
};
danmakuOnScreen.push(newDanmaku);
}
danmakuList = [];
// delete
for (var i = 0; i < danmakuOnScreen.length; ++i) {
var danmaku = danmakuOnScreen[i];
if (danmaku.x < -viewWidth) {
danmakuOnScreen.spice(i, 1);
--i;
}
}
// update
ctx.clearRect(0, 0, viewWidth, viewHeight);
for (var i = 0; i < danmakuOnScreen.length; ++i) {
danmaku = danmakuOnScreen[i];
danmaku.x -= danmakuSettings['speed'];
ctx.font = danmakuSettings['fontSize'] + 'px ' + danmakuSettings['font']
ctx.fillText(danmaku.content, danmaku.x, danmaku.y);
}
window.requestAnimationFrame(update)
};
window.requestAnimationFrame(update);
Time sync
接下来是第二个问题,处理时间戳,我要保证每一次拖的数据都不能重复。其实这个问题也蛮简单,我们只要把一段不可能再增加弹幕的时间段里的所有弹幕全部拖出来就好了。
其实我觉得我也讲不清楚什么逻辑。其实做法十分简单,每一次拖一个(last_time, now]时间段的所有弹幕返回,并且更新一下last_time.就能保证不重复地拖了。
还要处理一下特殊的情况,比如last_time不存在啊,now < last_time啊,now和last_time差的太远啊。这些情况下我们不反回结果,只调整last_time。
接下来就是db的问题,mongodb+koajs可以在coroutine的模式下调用,其中有多爽。。。自己写写看就知道了。mongo加一个索引{“channel”: 1, “timestamp”: 1}(这个channel的意思是为了区分不同公共号的弹幕频道)
WeChat Supervisor
关于管理页面,由于时间太紧我也懒得自己设计一份页面了,上网拖了一份模板就拿来用了(实际上我觉得那些模板比我见过的除了戍爷以外的设计师设计的都好)。
hash什么的都没弄,所以请大家用的时候弄几个弱密码就好了。关于csrf呢,由于操作本来就少,每一次操作的时候都输入密码,xsrf也懒得做了。
API:
POST /manager/api/register
{
“uid”: string,
“password”: string
}
POST /manager/api/set_token
{
“uid”: string
“token”: string,
“password”: string
}
也懒得写详细的response了,如果成功就200,不成功的话就是status的形式告知(也就是错误信息的设计没做= =)。
在接下来就是微信公共平台接入,贴一下文档和我自己写的一个能用的demo:
http://mp.weixin.qq.com/wiki/17/2d4265491f12608cd170a95559800f2d.html
https://github.com/voidrank/MrOrgr/blob/master/src/openchat/security.py
其实文档上讲得很清楚了,但是还是想强调一下。当你接入的时候,wechat服务器会发送一个get请求,让你验证,如果验证成功的话,让你返回那个rand值。之后每次微信向你发送消息的时候都会发。
Bonus:
嵌套一个iframe,用一个setting bar来控制它的src,然后从google slide里脱出分享的url(当然你想的话也可以放一个baidu.com在后面)
TODO:
redis, anti requests flood, register captcha, password hash,
本文介绍了一种基于Canvas、ReactJS、KoaJS和MongoDB的微信弹幕系统的实现过程,包括前端弹幕显示逻辑、时间同步机制及管理页面的设计。
1603

被折叠的 条评论
为什么被折叠?



