muzigram

山椒は小粒でもピリリと辛い

2013/03/25

[go] 一瞬でtype T に対するfunc(t T) とfunc(t *T)の違いを理解する #golang

自分が一瞬 うん?となることがあるのでメモ
一瞬は言い過ぎか。

■ code

package main

import (
 "fmt"
)

type T struct{ a, b int }

func (t T) addRef() {
 t.a++
 t.b++
 fmt.Printf("t.a + t.b=%v\n", t.a+t.b)
 return
}

func (t *T) add() {
 t.a++
 t.b++
 fmt.Printf("*t.a+*t.b=%v\n", t.a+t.b)
 return
}

func main() {
 var t *T = new(T)
 var t2 *T = new(T)
 t.a = 1
 t2.a = 1
 t.b = 2
 t2.b = 2

 t.add()
 fmt.Printf(" *T  result=%v\n", t)

 t2.addRef()
 fmt.Printf("  T  result=%v\n", t2)
}

■ result

go run main.go
*t.a+*t.b=5
*T result=&{2 3}
t.a + t.b=5
T result=&{1 2}

参照か、実体か。一度理解すれば問題無いんですけどね。

2013/03/18

channelAPIで/_ah/channel/connect/とか/disconnect/が帰ってこない…(ように書いていた #golang

問題というか、自分がミスっていただけなんだけど。

exampleを参考にchannelAPIの動作を確認してた所。

接続時に
/_ah/channel/connect/
終了時に
/_ah/channel/disconnect/ が叩かれる。というので試して見てたんだけど、

INFO 2013-03-18 12:39:24,099 dev_appserver.py:3103] "POST /_ah/channel/connected/ HTTP/1.1" 302 -
となって叩かれない…

で、302、転送でピコンときたのは、app.yamlの記述。
すべてのページをlogin: requiredにしていたけど、これだと、サーバー内から叩かれる。connected等の
アクセスにも適用されてしまうため、ログイン画面に転送されてしまう。

と、いうことで、githubのサンプルを更新
https://github.com/mogeta/golang_channelAPI_example
一件落着。

社内LTの代役でeve onlineの話した。

オーパーツをテーマに何か話せ。
というお題目を仰せつかったのでやってみました。
eve onlineというゲームは是非、ソーシャルゲームにハマっている人も
ソーシャルゲームを作っている人も一度は遊んでみて欲しいゲームです。
http://www.slideshare.net/mogetta/eveonline

2013/03/12

go + dartでchannelAPIを動作させてみた #dartlang #dartlangjp

http://muzigram.muzigen.net/2013/03/gaegochannelapi-golang.html の続き

■ 今回のプロジェクト

https://github.com/mogeta/golang_channelAPI_example_dart

■ GAEのchannelAPIをdartで動かしてみよう。

面白そうだから

see also

  • http://pub.dartlang.org/
  • http://pub.dartlang.org/packages/appengine_channel
  • https://code.google.com/p/gae-channel-api-dart/
と思って調べてみたら、google codeの方にどんぴしゃりなライブラリが
あったのでやってみた。つか用意されてるのかよ。

■ pub install

pubspec.yaml
name: channelDart
dependencies:
  appengine_channel: any
  js: any

依存関係のあるライブラリを
pub install
と叩くだけで取ってきてくれる。

■ js.scoped

dartはjs libraryを使って javascriptと連携を取ることができる。
js libraryはproxyと呼ばれるオブジェクト経由でdartとやり取りするんだけど
まぁ、とりあえず動かすところまで行ってしまおう。

  js.scoped(() {
     token  = js.context.token;
     meID   = js.context.me;
     gameID = js.context.game_key;
   });
js.scoped()内で値を取得しましょう。
scope外でやると

Exception: Cannot get JavaScript context out of scope.

と怒られます。

■ HTML

特筆する部分は以下
channel-dart.jsを読み込んでおきましょう。
    <script>
     var token    = "{{.token}}"
     var me       = "{{.me}}"
     var game_key = "{{.game_key}}"
    </script> 
    <script type="text/javascript" src="/_ah/channel/jsapi"></script>
    <script type="text/javascript" src="/js/channel-dart.js"></script> 
    <script type="application/dart" src="/dart/hello.dart"></script>

■ Screen Shot

出来上がったものがこちら、見た目は変わらんねー。dartiumで見ないと意味ないですよん。 スクリーンショット 13 03 12 17 28

■ source code

hello.dart
import 'package:js/js.dart' as js;
import 'package:appengine_channel/appengine_channel.dart' as ch;
import 'dart:html';

void main() {
  
  String token;
  String meID;
  String gameID;
  
  js.scoped(() {
     token  = js.context.token;
     meID   = js.context.me;
     gameID = js.context.game_key;
   });
  
  openChannel(token);
  setButtonListner(meID,gameID);
  
}

void openChannel(String token) {
  Element element = document.query("#area");
  ch.Channel channel = new ch.Channel(token);
  ch.Socket   socket = channel.open()
    ..onOpen    = (() => print("open"))
    ..onClose   = (() => print("close"))
    ..onMessage = ((m){
      element.innerHtml = "${element.innerHtml}${m}
"; print("${m}"); }) ..onError = ((code, desc) => print("error: $code $desc")); } void setButtonListner(String meID,String gameID){ var btn; btn = document.query("#button_id"); btn.onClick.listen((e){ var httpRequest; httpRequest = new HttpRequest(); httpRequest.open('POST', '/receive?g=${meID}${gameID}', true); httpRequest.send(); }); }

2013/03/04

GAE(Go)でChannelAPIを動作させてみた。 #golang

このエントリーをはてなブックマークに追加

■ 環境

release: "1.7.4"
timestamp: 1352314290
api_versions: ['go1']

■ 概要

■今回作成したプロジェクト
https://github.com/mogeta/golang_channelAPI_example

■ドキュメント
https://developers.google.com/appengine/docs/go/channel/

を試してみようと思ったのですが、コードの中に微妙な間違い
(×:ParseFile ◯:ParseFileshttp://golang.org/pkg/html/template/
等があったりし、思ったよりも四苦八苦したので
最もシンプルな形で動作するサンプルを書いてみました。
とりあえず、ローカルで動いたので一旦commit

■ ChannelAPIとは

GAEが提供している機能の一つでWebsocketのような機能を提供してくれます。
ポーリング等をせずとも、いわゆるリアルタイムな通信を可能にしてくれます。
たとえば、チャットや、ネットゲーム等で使うことができるのではないでしょうか。

■ Github

プロジェクトは一式、Githubの方に展開致しました。
シンプルに動作確認することだけを目指したので、ChannelAPIで接続し、
自分にメッセージを返すだけの簡単なアプリケーションになっています
https://github.com/mogeta/golang_channelAPI_example

■ スクリーンショット

スクリーンショット 13 03 04 17 32 ボタンを押すとGo側の関数を経由してdivタグ内を編集します。

■ 説明

Go側のチャネル作成
tok, err := channel.Create(c, u.ID+key)
チャネルを作成します。「u.ID+key」によって個人を識別するkeyを作成しています。

javascript側のチャネル作成
var channel = new goog.appengine.Channel( {{.token}} );
javascript側はGolangのテンプレートモジュールによって埋め込まれた{{.token}}からチャネルトークンを受け取り channelオブジェクトを作成しています。

ボタンを押した際、javascript側から/receiveを叩きに行き、
go側はfunc receive(w http.ResponseWriter, r *http.Request)でそれを受け取り
channel.Sendを叩く。という形になっています。

以下、ソースコード(2013/03/05) channel.go
package channelExample

import (
 "html/template"
 "net/http"
 "time"

 "appengine"
 "appengine/channel"
 "appengine/user"
)

func init() {
 http.HandleFunc("/", main)
 http.HandleFunc("/receive", receive)
}

var mainTemplate = template.Must(template.ParseFiles("channel/main.html"))

func main(w http.ResponseWriter, r *http.Request) {
 c := appengine.NewContext(r)
 u := user.Current(c) // assumes 'login: required' set in app.yaml
 key := r.FormValue("gamekey")
 tok, err := channel.Create(c, u.ID+key)
 if err != nil {
  http.Error(w, "Couldn't create Channel", http.StatusInternalServerError)
  c.Errorf("channel.Create: %v", err)
  return
 }

 err = mainTemplate.Execute(w, map[string]string{
  "token":    tok,
  "me":       u.ID,
  "game_key": key,
 })
 if err != nil {
  c.Errorf("mainTemplate: %v", err)
 }
}

func receive(w http.ResponseWriter, r *http.Request) {
 c := appengine.NewContext(r)
 key := r.FormValue("g")
 channel.Send(c, key, "go receive!"+time.Now().String())
}
main.html
<html>
<body>

 <form action="#">
 <input type="button" value="OK" onclick="return exe()">
 </form>
 <div id="area"></div>

 <script type="text/javascript" src="/_ah/channel/jsapi"></script>
  <script>

 var channel = new goog.appengine.Channel( {{.token}} );
 var socket = channel.open({
 onopen : function(){
  document.getElementById("area").innerHTML+="{{.token}} ::: onopen<br />"; 
 }
 , onmessage : function(message) {
  document.getElementById("area").innerHTML+="onmessage::"+message.data+"<br />"; 
 }
 , onerror : function(error) {
  document.getElementById("area").innerHTML+="onerror<br />"; 
 }
 , onclose : function(){
     document.getElementById("area").innerHTML+="onclose<br />"; 
 }
 });
  </script>
  <script>
 function exe() {
  var path = '/receive?g=' +  {{.me}} + {{.game_key}} ;
  var xhr = new XMLHttpRequest();
    xhr.open('POST', path, true);
    xhr.send();
 }
  </script>
</body>
</html>