Newer
Older
WebSocketSample / otp / otp.rb
@HIROSE Yuuji HIROSE Yuuji on 25 Oct 2022 3 KB Add some response patterns
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
# EM Intro. - http://keijinsonyaban.blogspot.jp/2010/12/eventmachine.html
# irb to EM - https://keyesberry.hatenadiary.org/entry/20110929/p1
#
# Browser Settings:
# Chrome: https://blog.hello-world.jp.net/node-js/1821/

require 'em-websocket'
require 'sqlite3'
require 'json'
require './userdb.rb'
PORT = 8889
MAILFROM = "admin@e.koeki-u.ac.jp"

clients = Hash.new	# 各クライアントの接続関連全情報を格納
			# キーにコネクションが入る

print("No clients yet...")
EM::WebSocket.start({:host => "0.0.0.0", :port => PORT}) do |ws_conn|
  userdb = UserDB.new
  # クライアント接続がある度にその情報が ws_conn に入って来る
  ws_conn.onopen do		# そのクライアントが接続開始してきたとき
    clients[ws_conn] = {}	# クライアントを集合に追加
    printf("%d guest(s)\n", clients.length)
  end
  ws_conn.onmessage do |message|	# クライアントから文字列が来たとき
    # messageは必ずJSONで送ってもらう
    p message
    given = JSON.parse(message)
    param=clients[ws_conn]		# クライアントの情報一覧
    user = param["user"]||given["user"]
    data = {}
    # 認証成功は2つの可能性:
    # 1つはtmpkeyとパスコードの組み合わせ
    # もう1つはブラウザlocalStorageに残っていたセッションキーを送ってくる
    if param["authok"]
      # 認証完了したクライアントとは自由に通信
      p "USER=#{user}"
      if given["note"]
        data["reply"] = userdb.notAI(given, user)
        param["last"] = Time.now
      end
    elsif given["tmpkey"]
      # tmpkeyとパスコードの組み合わせを送ってきたとき
      param["skey"] = userdb.authTmpKey(user, given["tmpkey"], given["passcode"])
      STDERR.puts "tmpKeyAuth= #{param['skey']}"
      if param["skey"]
        param["authok"] = true		# 認証完了!
        data["skey"] = param["skey"]
      end
    elsif given["skey"]
      # skeyを送ってきたとき
      param["user"] = given["user"]
      param["skey"] = userdb.authSkey(user, given["skey"])
      if param["skey"]			# 
        param["authok"] = true		# 認証完了!
        data["skey"] = param["skey"]
        param["last"] = Time.now
      end
    elsif given["user"]
      puts "Got: #{given['user']}"
      param["user"] = given["user"]
      data["tmpkey"] = userdb.genTmpkey(param["user"])
    else				# 何も情報がなければlogin
      # data["body"] = htmls["login"]
    end
    resp = JSON.pretty_generate(data)
    STDERR.puts "Sent: #{resp}"
    ws_conn.send(resp)
  end
  ws_conn.onclose do			# クライアントが切断したとき
    clients.delete(ws_conn)		# そのクライアントを集合から削除
    # p "bye"+ws_conn.inspect
    printf("%d GUEST(s)\n", clients.length)
  end
  EM::defer do				# 共通で実行するスレッド
    # Thread.new do のほうがいいかも
    puts "..captured!"
    Thread.new {			# 別スレッドを起こして並行動作させる
      loop do				# 無限ループ(末尾で5秒休憩)
        clients.each do |conn, hash|	# 全クライアントに対して繰り返す
          next unless hash["last"]	# 最終操作時刻未設定ならパス
          p Time.now - hash["last"]
          if Time.now - hash["last"] > 10
            # 10秒書き込み操作のないクライアントにメッセージを送る
            rep = %w(なんか喋り おーい おるんか? 暇だ ぬ ほぇ? 静寂 遅いわ
            どしたん話聞こか 打鍵が遅いのか? 帰ってよいか? つまらぬ).sample
            conn.send(JSON.generate({"reply"=>rep}))
            hash["last"] = Time.now	# 最終操作時刻を上書き
          end
        end
        sleep 5
      end
    }					# 別スレッドここまで
    loop do
      print("Enter message for all clients: ")
      line = gets
      puts("Sending")
      clients.keys.each{|conn|
        conn.send(JSON.generate({"reply"=>line.chomp}))
      }
    end
  end
end