Created
June 29, 2011 02:56
-
-
Save ts-3156/1052879 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.BufferedReader; | |
import java.io.FileInputStream; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import javax.servlet.http.HttpServlet; | |
import javax.servlet.http.HttpServletRequest; | |
import javax.servlet.http.HttpServletResponse; | |
import com.google.appengine.api.channel.ChannelMessage; | |
import com.google.appengine.api.channel.ChannelService; | |
import com.google.appengine.api.channel.ChannelServiceFactory; | |
@SuppressWarnings("serial") | |
public class ChannelAPITestServlet extends HttpServlet { | |
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { | |
// ゲームに割り当てられるIdとか、ログインしたユーザのIdとか自分で決めましょう | |
// ここではとりあえず時間を表す文字列にしてます | |
String userId = Long.toString(System.currentTimeMillis()); | |
String htmlSource = "http://channel3156.appspot.com/channel_api_test.htmlのHTMLをそのまま代入"; | |
StringBuilder strBuilder = new StringBuilder(); | |
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("channel_api_test.html"), "utf-8")); | |
String line = null; | |
while((line = br.readLine()) != null) | |
strBuilder.append(line + "\n"); | |
htmlSource = strBuilder.toString(); | |
htmlSource = htmlSource.replaceAll("--token--", getToken(userId)); | |
htmlSource = htmlSource.replaceAll("--userId--", userId); | |
resp.setContentType("text/html; charset=utf-8"); | |
resp.getWriter().write(htmlSource); | |
} | |
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { | |
String getToken = req.getParameter("getToken"); | |
// Token再取得要求 | |
if(getToken != null && getToken.equals("true")){ | |
String userId = Long.toString(System.currentTimeMillis()); | |
String token = getToken(userId); | |
String response = "{\"userId\": \"" + userId + "\", \"token\": \"" + token + "\"}"; | |
resp.setContentType("text/html; charset=utf-8"); | |
resp.getWriter().write(response); | |
return; | |
} | |
String userId = req.getParameter("userId"); | |
String message = req.getParameter("message"); | |
String sendTime = req.getParameter("time"); | |
long curTime = System.currentTimeMillis(); | |
String sendTimeStr = "" + (curTime - Long.parseLong(sendTime)); | |
// 受け取ったデータをそのまま返します | |
String response = "{\"text\": \"" + message + "を受け取ったよ! 送信: " + sendTimeStr + "ミリ秒" + "\", \"time\": \"" + curTime + "\"}"; | |
sendUpdateToUser(userId, response); | |
} | |
private void sendUpdateToUser(String userId, String message) { | |
ChannelService channelService = ChannelServiceFactory.getChannelService(); | |
channelService.sendMessage(new ChannelMessage(userId, message)); | |
} | |
private String getToken(String userId){ | |
ChannelService channelService = ChannelServiceFactory.getChannelService(); | |
// ゲームのパラメータとかユーザIdを元にして一意なIdを作りましょう | |
// ここでは簡易化のために、userIdをそのまま使っています | |
String token = channelService.createChannel(userId); | |
return token; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<meta http-equiv="content-type" content="text/html; charset=utf-8"> | |
<!-- headタグ内にこの行を入れる必要があるそうです --> | |
<!-- 他のスクリプトは全てbodyタグ内に入れる必要があるそうです --> | |
<script src='/_ah/channel/jsapi'></script> | |
<title>Channel API テスト</title> | |
</head> | |
<body onload="initialize()"> | |
<script type="text/javascript"> | |
// --token--、--userId--の部分は、サーバがこのhtmlを出力する段階で置換されます | |
var token = "--token--"; | |
var userId = "--userId--"; | |
var socket = ""; | |
var isInitialized = false; | |
var isConnected = false; | |
var gettingToken = false; | |
// 標準出力用の変数 | |
var texts = new Array(10); | |
for(var i = 0; i < texts.length; i++) | |
texts[i] = ""; | |
// 標準出力にtextを追加する | |
function addText(text){ | |
blankIndex = -1; | |
for(var i = 0; i < texts.length; i++){ | |
if(texts[i] == ""){ | |
blankIndex = i; | |
break; | |
} | |
} | |
if(blankIndex == -1){ | |
for(var i = 1; i < texts.length; i++) | |
texts[i - 1] = texts[i]; | |
texts[texts.length - 1] = ""; | |
} | |
for(var i = 0; i < texts.length; i++){ | |
if(texts[i] == ""){ | |
texts[i] = text; | |
break; | |
} | |
} | |
updateUI(); | |
} | |
//標準出力にtextを出力する | |
function printText(text){ | |
document.getElementById("stdOut").innerHTML = texts.join("\n"); | |
} | |
// 初期化です。最初にこの関数を実行する必要があります | |
function initialize(){ | |
if(isInitialized == true){ | |
//alert("既に初期化済みです"); | |
return; | |
} | |
if(isConnected == true){ | |
//alert("既に接続済みです"); | |
return; | |
} | |
channel = new goog.appengine.Channel(token); | |
socket = channel.open(); | |
socket.onopen = onOpened; | |
socket.onmessage = onMessage; | |
socket.onerror = onError; | |
socket.onclose = onClose; | |
isInitialized = true; | |
addText("初期化が完了しました。serverからの応答待ちです"); | |
} | |
// ソケットを閉じた後に別のソケットを開く関数 | |
function reOpen(){ | |
if(isConnected == true){ | |
//alert("既に接続済みです"); | |
return; | |
} | |
if(isInitialized == true){ | |
//alert("既に初期化済みです"); | |
return; | |
} | |
if(gettingToken == true){ | |
//alert("Token再取得を要求中です"); | |
return; | |
} | |
getNextToken(); | |
} | |
// 一度閉じたソケットを再度開く時に呼ぶ | |
function getNextToken(){ | |
gettingToken = true; | |
var http = new XMLHttpRequest(); | |
http.open('POST', '/channel_api_test?getToken=true', true); | |
//Tokenの受信時に呼ばれる関数 | |
http.onreadystatechange = function(){ | |
//4で受信完了 | |
if (http.readyState == 4){ | |
//Token再取得時のコールバック関数 | |
comeToken(http); | |
} | |
} | |
http.send(); | |
addText("Token再取得要求を送信しました"); | |
} | |
// Tokenが送られてきた時に呼ばれる | |
function comeToken(http){ | |
var json = eval("(" + http.responseText + ")"); | |
token = "" + json.token; | |
userId = "" + json.userId; | |
addText("serverからトークンを受け取りました"); | |
gettingToken = false; | |
initialize(); | |
} | |
// ソケットを閉じるときに呼ぶ関数 | |
// 正常に閉じられてもサーバからの応答はなし | |
// この関数を呼んだ時点で接続は終了したとみなす | |
function closeSocket(){ | |
if(socket == "" || isInitialized == false || isConnected == false){ | |
addText("まだ接続されていません"); | |
return; | |
} | |
socket.close(); | |
socket = ""; | |
isInitialized = false; | |
isConnected = false; | |
token = "--token--"; | |
userId = "--token--"; | |
bagu_taisaku(); | |
addText("接続を終了しました"); | |
} | |
// [2010/12/19]通信を切断した場合に謎のiframeが残ってしまうバグ対策 | |
// 詳細はこちら↓ | |
// http://d.hatena.ne.jp/furyu-tei/20101219 | |
function bagu_taisaku(){ | |
var iframes = document.getElementsByTagName('iframe'), wcs_iframes = []; | |
for (var ci = 0, len = iframes.length; ci < len; ci++) { | |
var iframe = iframes[ci]; | |
if (iframe.id == 'wcs-iframe' || iframe.name == 'wcs-iframe') | |
wcs_iframes[wcs_iframes.length] = iframe; | |
} | |
for (var ci = 0,len = wcs_iframes.length; ci < len; ci++) { | |
wcs_iframes[ci].parentNode.removeChild(wcs_iframes[ci]); | |
} | |
} | |
// serverにmessageを送るときに呼ばれる関数 | |
function sendMessage(path, message) { | |
if(isInitialized == false){ | |
reOpen(); | |
} | |
if(isInitialized == false){ | |
addText("初期化が終わっていないのでデータを送信できません。数秒後に再度送信してください"); | |
return; | |
} | |
if(isConnected == false){ | |
addText("接続が完了していないのでデータを送信できません。数秒後に再度送信してください"); | |
return; | |
} | |
if(token == ("--" + "token--") || userId == ("--" + "userId--")){ | |
addText("tokenまたはuserIdが不正です"); | |
return; | |
} | |
path += '?message=' + message + '&userId=' + userId + '&time=' + new Date().getTime(); | |
var http = new XMLHttpRequest(); | |
http.open('POST', path, true); | |
http.send(); | |
addText(message + "を送信しました"); | |
} | |
// serverからもらったデータを元にUIを更新する関数 | |
function updateUI(){ | |
printText(); | |
} | |
// onOpened、onMessage、onError、onCloseはcall back関数です。serverから呼ばれます | |
// socketがmessageを受け取る準備ができたときに呼ばれる関数 | |
function onOpened(){ | |
addText("接続が開始されました。データを送信できます"); | |
isConnected = true; | |
} | |
// socketがmessageを受け取ったときに呼ばれる関数 | |
function onMessage(message){ | |
var json = eval("(" + message.data + ")"); | |
var receiveTime = (new Date().getTime() - 0) - (json.time - 0); | |
var receiveTimeStr = receiveTime / 1000; | |
addText("serverから「" + json.text + ", 受信: " + receiveTime + "ミリ秒」を受け取りました"); | |
} | |
// socketでエラーが起きたときに呼ばれる関数 | |
// tokenは2時間で期限切れになります。期限切れになったtokenで接続しようとするとこの関数が呼ばれます | |
// その時は、再度新しいtokenを取得して接続します | |
function onError(error){ | |
addText("serverでエラーが起きました。description=" + error.description + "。code=" + error.code); | |
} | |
// socketが閉じられたときに呼ばれる関数 | |
// クライアントから閉じた時は呼ばれない | |
// サーバから閉じられた時だけ呼ばれる | |
function onClose(){ | |
addText("接続が正常に終了しました"); | |
isConnected = false; | |
isInitialized = false; | |
} | |
</script> | |
<div style="font-size: 12px;"> | |
Channel APIを使ってserverにデータを送信します。<br> | |
接続の初期化は自動で行います。<br> | |
serverからのデータは、call back関数を通して渡されます。<br> | |
クライアント側でポーリングをする必要はありません。<br> | |
※時間がおかしいのは仕様です。 | |
</div> | |
<div> | |
<textarea name="stdOut" id="stdOut" cols=80 rows=10 readonly> | |
標準出力です | |
</textarea> | |
</div> | |
<input id="message" type="text" name="message" value=""> | |
<input type="button" value="データを送信" onClick="sendMessage('/channel_api_test', document.getElementById('message').value)"> | |
<input type="button" value="接続を終了" onClick="closeSocket()"> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment