6 Star 89 Fork 21

imboy.pub / imboy

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
design_thinking.md 7.70 KB
一键复制 编辑 原始数据 按行查看 历史
leeyi 提交于 2024-02-17 10:26 . # 0.3.3

记录一些功能的设计思考权衡过程

客户端服务端通讯安全(以实现)

  • API 使用 HTTPS;
  • 基于JWT的权限验证;
  • 基于客户端版本号的签名密钥管理,有利于密钥更新;
  • 配置在 option 和 open 里面的路由不需要做JWT认证,其他的都需要做JWT认证;
  • 小部分open路由不需要做签名验证,其他所有路由都需要签名验证;
  • 用户获取公钥数据的路由 /init 响应的数据通过基于版本号管的密钥的AES算法加密
  • 用户注册登录密码通过公钥做 RSA 算法加密传输,通过 hmac_sha512 算法加盐存储;
  • 发送到客户端的用户ID都要经过 hashids 算法混淆;

数据库存储(以实现)

选择强大的关系型数据库 PostgreSQL 15 ;

使用了它的一些扩展

  • fuzzystrmatch postgresql 内置的,提供多个函数来判断字符串之间的相似性和距离。
  • pg_trgm postgresql 内置的,三元索引增强全文检索
  • plpgsql postgresql 内置的,可载入的过程语言。
  • pg_jieba 用户在线搜索
  • postgis 附件的人功能,postgis的基本核心功能,仅支持地理图形(矢量要素)
  • pgrouting PgRouting是基于开源空间数据库PostGIS用于网络分析的扩展模块,最初它被称作pgDijkstra,因为它只是利用Dijkstra算法实现最短路径搜索,之后慢慢添加了其他的路径分析算法,如A算法,双向A算法,Dijkstra算法,双向Dijkstra算法,tsp货郎担算法等,然后被更名为pgRouting
  • postgis_tiger_geocoder
  • postgis_topology 拓扑功能的支持
  • pgcrypto 单聊、群聊等离线消息加密存储; 用户收藏资料加密存储
  • pg_stat_statements 运维相关的
  • timescaledb 暂无用例 (计划用于群聊消息存储)
  • pgroonga 暂无用例
  • pgcrypto
  • vector Postgres 的开源向量相似度搜索
  • roaringbitmap

GEO 方案 (以实现)

通过对比选择使用强大的 postgis

全文索引 方案 (以实现)

通过对比选择使用强大的 pg_jieba + pgroonga

缓存方案 (以实现)

刻意规避使用Redis,使用 erlang 的 depcache

数据库连接池方案 (以实现)

使用 epgsql + pooler

附件资源存储方案

选择了 Go-FastDFS ,基于golang实现的自建服务,功能基本够用

消息确认机制 QoS

https://blog.csdn.net/Jessechanrui/article/details/88399012

socket 数据粘包问题、拆包问题

消息投递机制 (以实现)

  1. 判断用户是否在线,如果用户离线,直接存储离线消息
  2. 用户在线(or 用户上线),判断 erlang is_process_alive(Pid) 马上投递一次
  3. 没有收到消息之前, 2 S -> 5 S -> 7S -> 11 S 投递4次
  4. 如果收到消息 清理定时器,清理数据库消息
  5. 4次投递都未确认消息,待用户下次登录再投递

以上消息确认重复机制,可以确保消息不丢失

WebSocket 链接token校验机制 (以实现)

为提升用户体验,在“WebSocket 链接”的时候,即使token过期也响应成功;

为安全,补救措施如下:

  • 在校验token过期有,给客户端发送S2C消息,要求客户端在8秒内([0,3000,5000])刷新本token,告知服务端结果
  • 在确认刷新token成功后,取消计时器;
  • 否则直接给特定链接踢下线

下面是服务端调试代码

Uid = 513242,
DID = <<"C5931370-BDCC-55FE-AB9C-8E2B39DC5018">>,
MsgId = <<"please_refresh_token">>,
ToUid = imboy_hashids:uid_encode(Uid),
Msg = message_ds:assemble_msg(
    <<"S2C">>, <<>>, ToUid
    , [{<<"msg_type">>, MsgId}]
    , MsgId),
Msg2 = jsone:encode(Msg, [native_utf8]).

Fun = fun() ->
    Li = imboy_session:list_by_uid(Uid),
    [Pid ! {close, 4006, <<"token invalid, please login again.">>} || {Pid, {_DType1, DID1}} <- Li, DID1 == DID]
end.

message_ds:send_next(Uid, MsgId, Msg2, [3000, 5000, Fun], [DID], true).

用户通过WS服务链接成功(以实现)

  • ./apps/imapi/src/websocket_handler.erl
    • line 70 user_logic:online/4
  • ./apps/imapi/src/user_logic.erl
    • line 28 syn:join/4
    • line 33 user_server:cast_online/3

用户所有的在线设备,用户所有加入的群组,一个用户只有一个WS链接;

附件资源的安全验证(以实现)

  • s=open 的资源做安全认证的时候不做过期校验
  • 其他资源做过期校验

用户收藏 (以实现)

一个类似”微信里面的收藏“功能,收藏聊天的是发布的图片、视频、文件等用户觉得重要的信息。

收藏记录已经在 postgresql 里面已做AES加密存储

调整收藏方案:清除 收藏专有的存储服务,改用定时任务扫描,在判断资源配如果没收藏嘞,就不删除;否则,过期删除之

  • 需求:
    • 用户在聊天中参数的图片、视频、文件数据按特定目录、特定时间存储在 Go-FastDFS 存( String savePath = "/$prefix/${dt.year}${dt.month}/${dt.day}_${dt.hour}/";),我计划定期删除超过半年或者一年的 savePath 里面的文件。
  • 设想:
    • 用户在收藏摸个附件的时候,我就上述 savePath 对应的原始文件 copy一份到 "collect_${savePath}" 目录,让后我就可以定期的放心删除半年或者一年以上的 savePath 下面的文件了。
  • 目前实现方案
    • 假设两个 Go-FastDFS 服务(需要两个二级域名 c.imboy.pub 用于收藏; a.imboy.pub 用于聊天等零时附件存储);
    • 数据库新建 attachment 表,最收藏的资源做引用计数管理,当计算器为0的时候,可以删除对应资源;
    • a.imboy.pub 服务的资源,可以按时间戳定时直接清理;
    • 该方案有缺陷:从a.imboy.pub copy 附件到 c.imboy.pub 比较耗时(解决耗时问题需要调整 Go-FastDFS 服务)

用户注销

  • 通知当前用户所有设备已注销
  • 通知用户所有朋友,该用户已经注销
  • 清理所有用户相关数据,写入 时序数据库
  • 用户注销以后,用户的所有好友和群组关系需要解除

流程参考 https://blog.51cto.com/u_15069441/4323079

APP端 sqflite3 数据库升降级功能(以实现,待测试)

APP端使用 sqflite 包的 onCreate/2 onUpgrade/3 onDowngrade/3 触发服务端接口(/app_ddl/get?type=[upgrade|downgrade|create],实现可控的升降级功能

  • 基于“一个初始版的DDL + 若干升级DDL” 或 “一个初始版的DDL - 若干升级DDL”
  • 后端可控,有升降级记录

基于jieba 分成 和 AC自动机的敏感词过滤系统 (未实现)

  • 按敏感词分类创建 tree A1 = aho_corasick:build_tree(["BC","ABCD"]). 缓存到 内存
  • 对用户数文本 InputTxt 使用jieba分词 应该自动过滤的无效词
  • 比较零时生成的分词集合 是否 预 特定分类的敏感词分词集合是否有交集
  • 有交集,循环分词结果,调用 aho_corasick:match(Word1, A1). 找出分词,api响应警告
  • 无交集,api 响应pass
  • https://wudeng.github.io/2018/04/13/wordfilter/

sensitive_word

基于地理位置的文学阅读APP (未实现)

基于postgis,做一个一带一路的沿途文化介绍的地图功能

时间判断的问题

前提条件1 服务端用erlang生产的 JWT 里面的过期时间是 erlang:system_time(millisecond) 获取的(假设服务器设置的时区是utc+8), 前提条件2 APP端 的用户(加速用户时区是utc+1)是通过dart语言的 DateTime.now().millisecondsSinceEpoch 获取的毫秒数

后置结果: 客户端通过 (jwt.claims['exp'] ?? 0) - 1500 > DateTime.now().millisecondsSinceEpoch ? true : false;

问题: 上面的方法判断token是否过期,会不会受到时区影响?

答: 会影响 解决办法: 获取时区差,统一用utc+0时区的时间戳计算,以避免影响

More

Erlang
1
https://gitee.com/imboy-pub/imboy.git
git@gitee.com:imboy-pub/imboy.git
imboy-pub
imboy
imboy
main

搜索帮助