1
0

chat_room.py 4.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. """
  2. Online chat room
  3. ^^^^^^^^^^^^^^^^^^^
  4. Chat with everyone currently online
  5. :demo_host:`Demo </chat_room>`, `Source code <https://github.com/wang0618/PyWebIO/blob/dev/demos/chat_room.py>`_
  6. * Use coroutine-based sessions
  7. * Use `run_async() <pywebio.session.run_async>` to start background coroutine
  8. """
  9. import asyncio
  10. from pywebio import start_server
  11. from pywebio.input import *
  12. from pywebio.output import *
  13. from pywebio.session import defer_call, info as session_info, run_async
  14. # 最大消息记录保存
  15. MAX_MESSAGES_CNT = 10 ** 4
  16. chat_msgs = [] # 聊天记录 (name, msg)
  17. online_users = set() # 在线用户
  18. def t(eng, chinese):
  19. """return English or Chinese text according to the user's browser language"""
  20. return chinese if 'zh' in session_info.user_language else eng
  21. async def refresh_msg(my_name, msg_box):
  22. """send new message to current session"""
  23. global chat_msgs
  24. last_idx = len(chat_msgs)
  25. while True:
  26. await asyncio.sleep(0.5)
  27. for m in chat_msgs[last_idx:]:
  28. if m[0] != my_name: # only refresh message that not sent by current user
  29. msg_box.append(put_markdown('`%s`: %s' % m, sanitize=True))
  30. # remove expired message
  31. if len(chat_msgs) > MAX_MESSAGES_CNT:
  32. chat_msgs = chat_msgs[len(chat_msgs) // 2:]
  33. last_idx = len(chat_msgs)
  34. async def main():
  35. """PyWebIO chat room
  36. You can chat with everyone currently online.
  37. 和当前所有在线的人聊天
  38. """
  39. global chat_msgs
  40. put_markdown(t("## PyWebIO chat room\nWelcome to the chat room, you can chat with all the people currently online. You can open this page in multiple tabs of your browser to simulate a multi-user environment. This application uses less than 90 lines of code, the source code is [here](https://github.com/wang0618/PyWebIO/blob/dev/demos/chat_room.py)", "## PyWebIO聊天室\n欢迎来到聊天室,你可以和当前所有在线的人聊天。你可以在浏览器的多个标签页中打开本页面来测试聊天效果。本应用使用不到90行代码实现,源代码[链接](https://github.com/wang0618/PyWebIO/blob/dev/demos/chat_room.py)"), lstrip=True)
  41. msg_box = output()
  42. put_scrollable(msg_box, height=300, keep_bottom=True)
  43. nickname = await input(t("Your nickname", "请输入你的昵称"), required=True, validate=lambda n: t('This name is already been used', '昵称已被使用') if n in online_users or n == '📢' else None)
  44. online_users.add(nickname)
  45. chat_msgs.append(('📢', '`%s` joins the room. %s users currently online' % (nickname, len(online_users))))
  46. msg_box.append(put_markdown('`📢`: `%s` join the room. %s users currently online' % (nickname, len(online_users)), sanitize=True))
  47. @defer_call
  48. def on_close():
  49. online_users.remove(nickname)
  50. chat_msgs.append(('📢', '`%s` leaves the room. %s users currently online' % (nickname, len(online_users))))
  51. refresh_task = run_async(refresh_msg(nickname, msg_box))
  52. while True:
  53. data = await input_group(t('Send message', '发送消息'), [
  54. input(name='msg', help_text=t('Message content supports inline Markdown syntax', '消息内容支持行内Markdown语法')),
  55. actions(name='cmd', buttons=[t('Send', '发送'), t('Multiline Input', '多行输入'), {'label': t('Exit', '退出'), 'type': 'cancel'}])
  56. ], validate=lambda d: ('msg', 'Message content cannot be empty') if d['cmd'] == t('Send', '发送') and not d['msg'] else None)
  57. if data is None:
  58. break
  59. if data['cmd'] == t('Multiline Input', '多行输入'):
  60. data['msg'] = '\n' + await textarea('Message content', help_text=t('Message content supports Markdown syntax', '消息内容支持Markdown语法'))
  61. msg_box.append(put_markdown('`%s`: %s' % (nickname, data['msg']), sanitize=True))
  62. chat_msgs.append((nickname, data['msg']))
  63. refresh_task.close()
  64. toast("You have left the chat room")
  65. if __name__ == '__main__':
  66. start_server(main, debug=True, port=8080, cdn=False)