Giter Site home page Giter Site logo

kudojp / chat-app-with-gomniauth-websocket Goto Github PK

View Code? Open in Web Editor NEW
0.0 1.0 0.0 6.84 MB

(現在進行中)このレポジトリは以下の写経から始まり、それを発展させて「認証機能つき」「データ永続化」されたチャットアプリを作る。http://wild-data-chase.com/index.php/2019/03/28/post-686/

Go 59.59% HTML 40.41%

chat-app-with-gomniauth-websocket's Introduction

chat-app-with-gomniauth-websocket

このプロジェクトはGO 言語で認証機能つきのチャットアプリを作ってみた。を参考にしている。最初はこのサイトの写経からはじめ、のちに不具合修正、機能追加と行った形で発展させていく。

実行方法

$ go run *.go

どのような設計か

ユーザが入室した時、ブラウザからの ws 通信は chatroom ハンドラで対処され、受信したユーザは join チャネルに入れる。これを go routine で走っている chatroom.run において対処する。

写経終了後に発展させられそうな点(バックログ)

  • Enter でメッセージを送れるようにする
  • 認証未完了の状態でも"/chat"ページへアクセスできてしまい、それがユーザとしてカウントされ、またメッセージを送れてしまう
  • チャットルーム内の各ユーザ一覧(と合計ユーザ数)を表示したい
  • ルームへのメンバーの入退室をリアルタイムでクライアントのユーザ一覧を更新する
  • サーバにデプロイする
  • ある一つメッセージを送ったらそのユーザはルームを自動的に退出することになる(リロードで再入室する)
  • データの永続化
  • chatroom を複数用意する

発展のログ

(200205)ある一つメッセージを送ったらそのユーザはルームを自動的に退出することになる(リロードで再入室する)

今回のチャットルームへのアクセスは chatroom 構造体の ServeHTTP メソッドによってハンドリングされる。この中で以下の三点で websocket の通信が切断されていたので、これらを取り除いた。

  • chatroom.ServeHTTP()におけるdefer func() {c.leave <- user}()
  • user.read()の最後のc.socket.Close()
  • user.write()の最後のc.socket.Close()

[のちに追記]以上は全くもって不必要でトンチンカンな処理であった。メッセージ送信時に自動退出してしまうことに関しては他のどこかが問題になっていたようだ。上記3つはのちに復活させた。

(200205)チャットルーム内の各ユーザのプロフィール(と合計ユーザ数)を表示したい

  • ユーザは入室時に現在入室中のユーザ情報が(サーバーサイドで既に)レンダリングされた html を取得する (ユーザが chatroom に入室するのは chat.html 取得時ではなく、html をブラウザが受信して WS 通信をはじめた時。したがってユーザの描写はこの WS 通信開設後しか不可能)
  • ユーザは WS 通信を開始時に WS 通信でユーザ一覧情報を受信し、DOM 操作でページを書き換える
  • ユーザが入室 or 退出した際にはその旨を_毎回 avator 一覧を_ WS でクライアントサイドに送信し、DOM 操作でページを書き換える

これを直す過程でまず以下を行った。

  • avatar の URL は message ではなく、user が持つべき
  • message 構造はどの user によるものなのかを持つべき
  • message 送信の際には user 情報は json に含めない。user 情報は WS 接続確率時にクッキーからサーバーサイドで取り出す。接続後のメッセージはサーバーサイドに置いて user 情報と紐づけた message 構造体を作る。

終了後、以下を実装した。

  • ユーザは WS 通信を開始時に WS 通信でユーザ一覧情報を受信し、DOM 操作でページを書き換える

ただし、これを実装したところ、以下の問題が生じた

  • WS 通信で受信するデータが現状で「入室時のルーム内のユーザ一覧」と「新規メッセージ」の二種類になる

これに対処するために、websocket で送信する json を以下のフォーマットに統一する

  • chatroom のメンバー一覧は{'member_avatars': ['url1', 'url2'] }
  • 新規メッセージは{'new_message': '新規メッセージ'}

なお、chatroom members に関しては、自分自身の avator は表示されない(される)。これは、user が chatroom.serveHTTP()における処理の順番が以下だからである。

  1. cookie からユーザ自身に相当するクライアント構造体の初期化
  2. user.send_members()で websocket 通信でメンバー一覧をブラウザに送信(取り除く)
  3. クライアント構造体を join チャネルに追加
  4. join チャネルに追加されたクライアント構造体を chatroom.users に追加(ここで user.send_members していることにのちに気づく)

(200206)ユーザがチャットルームに入室した時にはチャットルーム内の他のユーザに通知したい。具体的には Chatroom members の avator 一覧を更新したい

chatroom.run()内の無限ループにおいて、join チャネルと leave チャネルとのそれぞれで新しい user 要素が追加された時に、その user と同じ chatroom に所属する全ての user に対して user.send_members を実行することで実行可能である。

(200206)ユーザ認証機能をまともにする。

現状 現時点での google,github との連携では、これらのリソースサーバからユーザ名、アバター URL を取得し、これらをブラウザのクッキーに埋め込んでいるだけであり、実質サーバーサイド側にユーザ情報は全く保持していない。この結果、ユーザがログアウトを押して再び同じアカウントでログインしたとしても、これは以前のログイン時のユーザとは紐づけられない。これは後のデータの永続化の際のネックになりうる。

今後の方針(没)

アプリケーション側でusers テーブルと*sessions データベース(KV)*を作る

users テーブル(まずは sqlite3 で、いつかは MySQL に置換?)

外部認証で得られる user_id と、このアプリケーションが保持する user_id を紐づけるためのテーブル

column Type Description
id int ユーザ ID(PK)
name string NOT NULL
avatar_url string NOT NULL
provider_name string NOT NULL
provided_id string NOT NULL
  • ユーザが外部サービスを使い認証した際にはまずこのテーブルを参照する。(外部サービスのプロバイダ名, リソースサーバから取得した user_id)の組み合わせがこのテーブルに既存だった場合には、このテーブルに変更はなされない。もし存在しなかった場合には、その user がこのテーブルに insert される。

  • ユーザのプロフィール情報は認証のたびにリソースサーバに取りに行き、更新する。(これが一般的なやり方なのかはわからないが)

  • 同一セッションであってもリクエストのたびにこのテーブルは参照される。セッション情報は user_id と結びつけのみに使用され、user のプロフィールはセッション情報には保存しない。

以下に関しては今後の課題になる。

  • 同一 user が複数のサービスを使って認証した場合、それらは別々の user として見なされる、これに対処するにはリソースサーバにアクセスした時に email を取得し、上記 users テーブルに email カラムを追加して保持することである。これによって外部サービスでの認証時にすでにその user が別のサービスで認証していて同じ email を使っていた場合には検知ができ、認証を許さないようにできる。

sessions(Redis)

  • key が session_id, value が user_id。

今後の方針(改)

  • name, avatar_url は永続化せず、セッション情報として保持する。
    • セッションの開始時には毎回リソースサーバにアクセスすることになる。この際に毎回 name, avatar_url を取ってくる。これをセッションに保存する。
  • users テーブルは以下のようにする。
column Type Description
id int ユーザ ID(PK)
provider_name string NOT NULL
provided_id string NOT NULL
  • sessions 情報は gorilla/sessions を使って、(ブラウザではなく)サーバサイドの FileSystemStore に保存する。

chat-app-with-gomniauth-websocket's People

Contributors

kudojp avatar dependabot-preview[bot] avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.