#!/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