[关闭]
@wsd1 2017-08-13T22:52:07.000000Z 字数 6654 阅读 1280

ucast前端设计:微信H5客户端交互说明

ucast 微信 201705


架构角色(role)

uCast全景架构图_201705.png-67.6kB
uControl:是otu和实时引擎的整合;
uLogic:在uControl之上提供应用逻辑的角色;
Edge:是管理具体物联网应用的逻辑角色;
uLogicManager:负责收敛uLogic数据的cache层,微信登录,用户信息;
player\viewer: 玩家或观众

架构关系

20170716150020951437065.png

交互图

uCastAppH5交互稿v001_201705.png-185.2kB

localstorage传递入口参数

因为本交互不包含登录过程,所有参数通过localstorage获取。

在进入第一张页面之前,假设已经在localstorage存储如下字段:

page2:List 列表页

概述及界面元素

uCastAppH5交互稿_Page2list_201705.png-32.9kB
登录后,获取的第一个页面,展示各个项目的入口。下拉可以刷新数据。
1、过滤选择(暂不实现);
2、项目封面图片;
3、项目概述文字;
4、满队项目色调区别;

接口与数据结构

GET /api/v1/scenes

返回json

  1. [{
  2. "sceneDID":9527, //必然存在:场景控制器did
  3. "ctrlURL":"wss://ucast.cc", //必然存在:uControl地址
  4. "uLogicName":"race.rccar", //必然存在:uLogic名称
  5. "title":"~真.赛车车", //每一个项目自定义名称
  6. "queue":{rest:3, play:1, wait:10, free:2}, //参与信息
  7. },
  8. {...}];

媒体资源命名规则:

  1. $.get("/api/v1/scenes", (items)=>{
  2. //封面图片
  3. var first_scene_cover_img = `cover_${item[0].uLogicName}_${item[0].sceneDID}.jpg`
  4. })

媒体文件路径前缀为:http://ucast.oss-cn-beijing.aliyuncs.com/covers/

page3:Detail 详情页

概述及界面元素

uCastAppH5交互稿_Page3Detail_201705.png-28.1kB
点击列表项后,打开详情页,下拉可以刷新数据。

接口与数据结构

GET /api/v1/scenes/9527

返回json

  1. {
  2. "sceneDID":9527, //必然存在:场景控制器did
  3. "ctrlURL":"wss://ucast.cc", //必然存在:uControl地址
  4. "uLogicName":"race.rccar", //必然存在:uLogic名称
  5. "title":"~真.赛车车", //每一个项目自定义名称
  6. "queue":{rest:3, driver:1, wait:10, free:2}, //参与信息
  7. }

该接口用于刷新当前项目状态。

操作

点击排队按钮,开始尝试接入实时总线,逻辑如下:
首先,login;
其次,makerpc("participate")
通过后,snapshot record 并 subscribe event
如此,可以获得queue界面所需要的数据和事件资源;

  1. //登录网站后 获取用户关键信息
  2. var myname = localstorage.getItem("userID");
  3. var myToken = localstorage.getItem("jwt");
  4. //连接实时总线
  5. var client = deepstream(selected.ctrlURL).login(
  6. {
  7. username: myname,
  8. password: myToken
  9. },
  10. (success, data)=>{
  11. if (success) { //连接成功回调
  12. Log.info("Login OK: ");
  13. ...
  14. var rpc_data = {
  15. //参与的sceneDID(场景控制器did)
  16. sceneDID: selected.sceneDID,
  17. //用户自己的id
  18. userID: myname
  19. };
  20. let rpc_path = `rpc/uLogic/${selected.uLogicName}/participate`;
  21. client.rpc.make(rpc_path, rpc_data, (err, ret)=>{
  22. if (!err){
  23. //这里才算登录总线参与场景
  24. //建议这里才转入 page4:Queue 队列页
  25. //ret的格式类如:{record:{}}
  26. }
  27. })
  28. }
  29. }
  30. )

page4:Queue 队列页

概述及界面元素

在上一个界面,点击参加按钮,登录并调用参与接口成功后会引导到本界面。
本界面展示主要元素包括:
1、屏幕设置(状态);屏幕设置 将会引导进入 屏幕绑定界面;
2、队列情况;
3、弹幕输入;

uCastAppH5交互稿_Page4Queue_201705.png-35.1kB

接口与数据结构

本界面环境下,数据出入均通过实时总线:

UI更新逻辑

通过场景event更新
通过场景record渲染

客户端订阅路径:
event/uLogic/${selected.uLogicName}/${selected.sceneDID};
事件发生时,事件内容为:

  1. {
  2. "event":"xxx", <--- 表示类型
  3. "value":"xxx" <--- 携带参数
  4. }

伪代码如下:

  1. const CONST_ULOGIC_EVENT_QUEUE = "QUEUE";
  2. //队列变化会释放此事件,参数 value会带有最新队列
  3. const CONST_ULOGIC_EVENT_PLAY = "PLAY";
  4. //游戏开始(娃娃机IDLE 且 有司机存在)(暂未使用)
  5. const CONST_ULOGIC_EVENT_CATCH = "CATCH";
  6. //现场娃娃机下抓事件发生(可能是用户主动 也可能是娃娃机自己超时)。
  7. const CONST_ULOGIC_EVENT_SUCCESS = "SUCCESS";
  8. //现场娃娃机检测到抓取娃娃,事件value字段会带有编码或者字符串"NULL"表示没有检测出。(只发生在CATCH事件之后)
  9. const CONST_ULOGIC_EVENT_FAIL = "FAIL";
  10. //现场娃娃机判断抓取失败(只发生在CATCH事件之后)
  11. const CONST_ULOGIC_EVENT_BUSY = "BUSY"
  12. //现场娃娃机发现机器忙无法提供服务。(只发生在FAIL或SUCCESS之两个事件后)
  13. //更新数据(界面)的函数
  14. function refresh_state(){
  15. let record_path = `cache/uLogic/${selected.uLogicName}/${selected.sceneDID}`;
  16. //访问场景相关的record 获取 场景数据
  17. client.record.snapshot(record_path,
  18. (error, data) => {
  19. update_ui(data); //更新UI
  20. })
  21. }
  22. let event_path = `event/uLogic/${selected.uLogicName}/${selected.sceneDID}`;
  23. //订阅当前场景的事件接口
  24. client.event.subscribe(event_path, (dat) => {
  25. switch(dat.event){
  26. case CONST_ULOGIC_EVENT_QUEUE: //队列有变化
  27. console.log(`排队数据更新,如数组:${dat.value}`);
  28. break;
  29. case CONST_ULOGIC_EVENT_PLAY: //一轮新的游戏开始
  30. console.log(`这轮游戏司机是:${dat.value.driver}`);
  31. console.log(`这轮游戏的结束utc时间是:${dat.value.roundEndTime}`);
  32. break;
  33. case CONST_ULOGIC_EVENT_CATCH: //这一局已下抓
  34. console.log(`娃娃机现场发生了抓取事件`);
  35. break;
  36. case CONST_ULOGIC_EVENT_SUCCESS: //这里弹个庆祝图
  37. if(dat.value != "NULL")
  38. console.log(`恭喜你啊,抓到娃娃编码:${dat.value}`);
  39. else
  40. console.log(`恭喜你啊,抓到娃娃,但是我也不知道是哪种`);
  41. break;
  42. case CONST_ULOGIC_EVENT_FAIL: //这里弹个耻辱图
  43. console.log(`失败鸟~`);
  44. break;
  45. case CONST_ULOGIC_EVENT_BUSY: //这里可以notify()
  46. console.log(`我擦,机器要清理下,等会...`);
  47. break;
  48. }
  49. })

场景 record 详解

路径:
cache/uLogic/${selected.uLogicName}/${selected.sceneDID}

数据结构(关键成员):

  1. {
  2. sceneDID: xxx, //场景控制器DID
  3. stream: "rtmp://xx", //流地址
  4. queue: [“xxx”, "yyy", ...], //userID数组
  5. qScreen: ["aaa", "bbb", ...], //空串表示未绑定屏
  6. params: {
  7. qRest:3, //队列休息区容量
  8. qDriver:1, //队列司机容量
  9. qWait:10 //队列等候区容量
  10. },
  11. lastMsg: "",
  12. lastChange: 14xxxxxxxx,
  13. lastSubmit: 14xxxxxxxx
  14. }

场景event详解

路径:
event/uLogic/${selected.uLogicName}/${selected.sceneDID};

该事件提示客户端,场景record发生变化。
每当事件发生,客户端应当主动读取场景record(随机延时1~200ms)

场景队列详解

场景record中含有 queue字段,该字段为数组,放置当前排队用户的userID。

如需获取排队用户信息,比如头像、昵称,可以通过用户信息获取接口:

POST /api/v1/users/face

body:

  1. ["59358f38a5aa128ab902d8d7", "593590cca5aa128ab902d8f2", ...]

返回json

  1. [
  2. {
  3. "userID": "59358f38a5aa128ab902d8d7",
  4. "nickname": "zxc",
  5. "avatar": "http://xx.jpg"
  6. },
  7. {
  8. "userID": "593590cca5aa128ab902d8f2",
  9. "nickname": "123c",
  10. "avatar": "http://xx.jpg"
  11. },
  12. ...
  13. ]

弹幕实现详解

弹幕通过释放 弹幕事件 实现:

弹幕事件 路径:

  1. let nickname = localstorage.getItem("nickname");
  2. let evt_channel = `event/uLogic/${selected.uLogicName}/${selected.sceneDID}/bullet`;
  3. client.event.emit(evt_channel, nickname + ": 牛了~");
  4. ...

page5:BindScreen

概述及界面元素

该界面帮助用户绑定自己的屏幕。

uCastAppH5交互稿_Page5BindScreen_201705.png-18.9kB

背景:
由于直播系统依赖PC浏览器,所以产品的播放端放在PC上,手机作为遥控器的形态存在。产品传播到手机上之后,用户使用手机将播放器绑定到当前用户名下。
明确:播放器,特指PC浏览器下的播放器。

原理:
使用ucast的cache服务来实现播放端绑定。
1、播放端产生随机key,通过二维码展示。
2、手机侧扫码获取key,并在cache向该key写入用户信息。
3、播放端有限次数尝试访问,直到获取value,并写入localstorage,登录实时总线,开始播放和弹幕业务。

总结,播放器与手机的绑定,本质就是使用cache服务,用手机为播放器提供数据的过程。

接口与数据结构

播放器端 随机产生 player_key ,生成一个存入口(形成二维码),定时访问一个取路径。
先说取路径,如:

GET /portal/cache/:player_key

本质就是使用了cache服务,无权限情况下读取value的接口。

存入口,如:

GET /portal/player_entry.html?key=player_key

拥有账号(localstorage存在账户)的用户 在手机或者 微信浏览器内扫码,在打开的页面内调用写cache的api。
或者 使用微信JSSDK扫码,获取整个链接,从中截取 player_key,直接调用写cache的API。
写入JSON:

  1. {
  2. "jwt":xxx,
  3. "userID":xxx,
  4. "uLogicName":"ucastapp.race.rccar",
  5. "sceneDID":255,
  6. "ctrlURL":"wss://ucast.cc" //uControl地址
  7. }

page6:play

概述及界面元素

uCastAppH5交互稿_Page6play_201705.png-15.5kB

接口与数据结构

控制RPC:

路径:rpc/uLogic/${config.uLogicName}/joystick
参数:

  1. {
  2. sceneDID: 255,
  3. cmd: "up/down/left/right/catch",
  4. userID: "xxxx",
  5. }
  1. //下抓
  2. client.rpc.make("/rpc/ulogic/clawCube/joystick", {
  3. sceneDID: 255,
  4. cmd: "catch",
  5. userID: "xxxx",
  6. }, (err, ret)=>{})

page7:share

概述及界面元素

uCastAppH5交互稿_Page7share_201705.png-14.7kB

该界面可以使用mask表现,由文案和图片来表达。该界面状态下依然接受事件。

点击“分享出去”或 右上角关闭按钮后,根据是否还在队列,返回“queue”界面或"detail"界面。

点击再来一局,重复调用rpc/uLogic/${selected.uLogicName}/participate接口过程。注意先要unsubscribe之前关注的evt。

PC浏览器绑定页面

其生成 "屏幕授权页面" 二维码入口:

"https://ucast.cc/portal/screen_authorize.html?code=1234567890abcd1234567890" 

并持续尝试请求 "屏幕注册接口":

GET /portal/screen/regist/1234567890abcd1234567890

直到扫码进入页面的微信浏览器客户端登录并调用 "屏幕授权接口":

  1. POST /api/v1/authorize/screen
  2. BODY {screenCode: xxxx, 其他字段}

之后,访问"屏幕注册接口" 才能够得到临时账户信息,籍此屏幕localstorage缓存账户,读取"游客状态接口":

GET  /api/v1/tourists/:userID

获得正确信息后,跳转到下节播放器页面。

PC浏览器播放器页面

调试临时账户

云硬件

595535de17da16c07edb891b

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ewogICJpc3MiOiAidWNhc3QuY2MvYXBpIiwKICAiYXVkIjogInVjYXN0LmNjL2FwaSIsCiAgInN1YiI6ICI1OTU1MzVkZTE3ZGExNmMwN2VkYjg5MWIiLAogICJpYXQiOiAxNDk5MDE5MzU1LAogICJleHAiOiAxNTMwNTU1MzU1LAogICJqdGkiOiAiMTIzNDUiLAogICJwZXJtaXQiOiBbCiAgICAic2NlbmVzOlIiLAogICAgInVzZXJzLmZhY2U6UiIsCiAgICAiYnVzOkwiLAogICAgInNjcmVlbjpBIgogIF0KfQ.dxwfgFyFq5Two0RDHHPSLzfjiVyI9FzQzkmLnSmAY6g

  1. {
  2. "iss": "ucast.cc/api",
  3. "aud": "ucast.cc/api",
  4. "sub": "594f9a0817da16c07eda6ada",
  5. "iat": 1498389089,
  6. "exp": 1529925089,
  7. "jti": "594f9a0817da16c07eda6ada",
  8. "permit": [
  9. "scenes:R",
  10. "users.face:R",
  11. "bus:L"
  12. ]
  13. }

相关文档

deepstream react相关

https://deepstream.io/tutorials/integrations/frontend-react/

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注