2014年2月23日日曜日

Golang Cafe #18を開催しました。

Golang Cafe #18を開催しました。

今回は、goauth2というライブラリを使って、GoogleのAPIを実行するというのが
テーマでした。

サンプルコードは、githubにありますので、そちらをごらんください。
(ディレクトリを別にしていて、goauth2sampleに入っています)

今回は、サンプルの解説と、installedAppsの認証を1回で完結させるというのをやりました。
installedAppsの認証を1回にするというのは、oauth2の認証(installedApps)では、最初にユーザに承認させることになっていて、承認後のコードをアプリケーションに教えてあげる必要があります。サンプルでは、引数で承認コードを指定するようにしていますが、その引数での指定をやめて、Webアプリのように承認後、継続する処理に変えるというのにチャレンジしました。

サンプルの解説からですが、まず、calendarsampleは、CalendarAPIを実行し、カレンダーリストを取得するサンプルです。

認証の設定をいれる

最初に、認証の設定を保持するConfig構造体にClientID、Secretなど必要な設定をいれます。
config := &oauth.Config{
       ClientId:     auth.ClientID,
       ClientSecret: auth.Secret,
       RedirectURL:  auth.RedirectUrl,
       Scope:        scope,
       AuthURL:      request_token_url,
       TokenURL:     auth_token_url,
       TokenCache:   oauth.CacheFile(cachefile),
}

ClientID、Secret、RedirectUrlはGoogle Developers Consoleでアプリケーションキーを取得したものを設定します。(私のサンプルはgithubにキーが上がってしまうと困るので、最初は入力させて、以降は、ファイルに保存したものを利用するコードになっています。)

ScopeはAPIによって指定するものが違うので、APIのドキュメントを参照して下さい。
TokenCacheは一度認証した時にキャッシュとしてファイルに保存され、ファイルがある間で、有効期限が過ぎていなければファイルの認証トークンを使ってAPIを実行するようになっています。

キャッシュから認証情報を取得する

次に、キャッシュからトークンを取得します。

    _, err = config.TokenCache.Token()
if err != nil {
    // キャッシュなし

    // 認証コードなし=>ブラウザで認証させるためにURLを出力
    if code == "" {
        url := config.AuthCodeURL("")
        fmt.Println("ブラウザで以下のURLにアクセスし、認証して下さい。")
        fmt.Println(url)
        return
    }

    // 認証トークンを取得する。(取得後、キャッシュへ)
    _, err = transport.Exchange(code)
    if err != nil {
        fmt.Println("Exchange: ", err)
        return
    }

}

キャッシュファイルがない場合は、errorが返されるので、認証コードを取得するURLを生成し、コードを取得します。(ここで、一度プログラムを終了させる。)
もし、引数で指定してあれば、transport.Exchange(コード)でExchangeし、認証トークンを取得します。

APIを実行する

APIを実行します。oauth2のパッケージで認証トークンを持っているので、何も考えずにGet()すれば、レスポンスが返ってきます。

// Calendar APIにアクセス
r, err := transport.Client().Get(request_url)

思ったよりも簡単だった。

やることがたくさんあるわけではなく、簡単にアクセスできることはわかりましたが、承認キーを渡してもらう部分を何とかしないと、installedAppsでは使えない気がします。(これをGAEのappcfg.pyは上手にやっているらしく、どうやっているのかソースを読んで解説して貰う必要がありそうです。+Ryuji IwataさんがPythonを知っているので今度読んで、解説してもらおうという話にもなりました。)
+Takanobu Haginoさんは、goroutineでWebサーバを起動(http.ListenAndServe())して、リダイレクト先をlocalhostにするという荒業を実現していました。私も挑戦したのですができなかったので、そのコードの解説はそちらに譲ることにします。)

次回は、2013の12個のベストプラクティスを読む予定です。

追記:
それから、今回無断欠席をされた方がいらっしゃったので、無断欠席に関する注意点を増やしました。申込をして、来られないのは仕方がないと思いますが、何の連絡も無いのはどうかと思いますので、次回から、そういう方は管理者権限で参加取り消しをする可能性があります。

2014年2月19日水曜日

Google Compute Engine(CentOS6)にGoのCI環境を作る

今日、少し時間があったので、Google Compute Engine(以下、GCE)上でJenkinsを動かしてビルドとテストを行う環境を作ってみました。
GCEは、DebianとCentOS6が選べるのですが、私はCentOS6を選びました。

GCEのインスタンスを起動するには、Google Cloud Consoleからインスタンスを起動するのですが、まず、前提として、「課金設定をする」必要があります。(課金設定をしないと、GCEの初期化が成功しない。)インスタンスを生成して、起動するところまでのメモは以前投稿しているのでそちらをごらんください。Google Cloud SDKもダウンロード済みだということにします。(私は忘れていたけど…)

ファイアウォールの設定


まず、GCEのファイアウォールの設定を行います。これは、iptablesではなく、GCEのインスタンスに対するファイアウォールの設定です。Cloud Consoleからでもできますが、以下のコマンドを実行しました。ポートを8888を許可する設定にしていますが、Jenkinsのデフォルトポートをそのまま使えると思うので、デフォルトのポートを使う場合は、tcp:8080にしてください。
$ gcutil addfirewall [インスタンス名] --description="Jenkins用のポート" --allowed="tcp:8888"

そして、sshでログインして、iptablesを切る。(GCEのファイアウォールに委ねるので。これに気がつくのに時間がかかってしまいました…。二重にブロックされるので結構うっとうしい…。)

$ sudo service iptables save
$ sudo service iptables stop
$ sudo chkconfig iptables off

次回の起動でiptablesが動いてくれると困るので、chkconfigでoffにしておきます。

Javaのインストール


Javaもyumで入れましたが、公式のものが入れられなかった(多分、ブラウザでアクセスして、利用規約に同意のチェックがいる?)のでopenjdkを入れました。Jenkinsが動けば問題は無いので、細かいことは無視しました。
$ sudo yum search jdk

java-1.7.0-openjdk.x86_64 : OpenJDK Runtime Environment
java-1.7.0-openjdk-demo.x86_64 : OpenJDK Demos
java-1.7.0-openjdk-devel.x86_64 : OpenJDK Development Environment
java-1.7.0-openjdk-javadoc.noarch : OpenJDK API Documentation
java-1.7.0-openjdk-src.x86_64 : OpenJDK Source Bundle
ldapjdk-javadoc.x86_64 : Javadoc for ldapjdk
icedtea-web.x86_64 : Additional Java components for OpenJDK - Java browser plug-in : and Web Start implementation
ldapjdk.x86_64 : The Mozilla LDAP Java SDK

$ sudo yum install java-1.7.0-openjdk-devel.x86_64

Jenkinsのインストール

Jenkinsをインストールします。Jenkinsのrpm版が提供されていたのでもしかしたら?と思ったら、yumでインストールも可能だったので、yumにKeyを登録してインストールしています。

$ sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo

$ sudo rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key

$ sudo yum install jenkins

Jenkinsの設定とサービスの登録

PORTを8888に変更する。(デフォルトが8080なので、そのままでもいいと思いますが)
$ sudo vi /etc/sysconfig/jenkins
JENKINS_PORT="8888"

Jenkinsのchkconfigをon
$ sudo chkconfig jenkins on

Jenkinsを起動させる。(初回だけ)
$ sudo service jenkins start

Jenkinsの起動確認


ブラウザで、http://[VM InstanceのEXTERNAL ADDRSSのipアドレス]:8888/
にアクセスしてJenkinsが表示されれば、成功です。

Gitも忘れずにインストールしておきましょう
Gitのインストール

$ sudo yum install git


Goをソースからインストールする。

私はこれしかしたことがないので(?)、今回もソースからGoをインストールしました。
Goをコンパイルするために、gccとmakeを、ソースコードをダウンロードするためにmercurialをインストールしました。

$ sudo yum install mercurial-hgk.x86_64

$ sudo yum install gcc

$ sudo yum install make

$ hg clone -u release https://code.google.com/p/go

$ cd go/src

$ ./all.bash

GCE上でGoのコンパイルをしてみたのですが、意外と早くて、1分30秒程度で終わったような気がします。そこからtestが始まりましたが、testはもう少しかかったかも?
で、喜んでいたら、一般ユーザのディレクトリでビルドしてしまったので、Jenkinsからコマンドを実行しようと思うと、Permissionで弾かれてしまいますから、これも良くないのですが、/home/ユーザのディレクトリにchmod o+rxしてしまいました。
次回以降は気をつけようと思います。基本は/usr/local以下ですかね。

Jenkinsのプロジェクト設定

Jenkinsにgitプラグインを入れたのですが、よく考えると、Goの場合は、go getでダウンロードしてからgo testですので、gitプラグインは無くても大丈夫です。
したがって、ビルドの設定の「シェルの実行」のところに、コマンドをいくつか書きました。

export GOPATH=${WORKSPACE}
/home/yokoyama/go/bin/go get github.com/taknb2nch/go-pop3

cd ${WORKSPACE}/
/home/yokoyama/go/bin/go test 

ポイントは、GOPATH変数を都度exportしているところでしょうか。go get/go testコマンドを実行しようと思うと、GOPATHに入れておかないといけませんからこのような形になります。
リポジトリは、+Takanobu Haginoさんが作られた、POP3のライブラリを対象にしてみました。(私のリポジトリにしようかと思いましたが、私のはどれもレガシーコードですので…w)

結果


ちゃんと、PASSの文字が輝いております。
Started by user anonymous
Building in workspace /var/lib/jenkins/jobs/Sample/workspace
[workspace] $ /bin/sh -xe /tmp/hudson5366985436882835859.sh
+ export GOPATH=/var/lib/jenkins/jobs/Sample/workspace
+ GOPATH=/var/lib/jenkins/jobs/Sample/workspace
+ /home/yokoyama/go/bin/go get github.com/taknb2nch/go-pop3
+ cd /var/lib/jenkins/jobs/Sample/workspace/
+ /home/yokoyama/go/bin/go test
PASS
ok   _/var/lib/jenkins/jobs/Sample/workspace 0.003s
Finished: SUCCESS

今回は、「手動実行」まででとどめました。常時起動するほどテストをすることがないということと、課金の問題があるので、無駄に起動しておくのはまずい。ということが大きな理由です。これで、GCEについてのノウハウが少しずつ貯めていけそうです。

参考サイト

https://developers.google.com/compute/docs/quickstart#centos
http://d.hatena.ne.jp/katsuren/20121030/1351569655
http://d.hatena.ne.jp/okinaka/20120404/1333524730

2014年2月17日月曜日

Golang Cafe #17を開催しました。

Golang Cafe #17を開催しました。
今回のサンプルコードはgithubにおいてありますのでごらんください。

今回は、os/exec、os/signal、os/userパッケージを見ていきました。
その中で、Windows版だと、動かない現象があったので、メモを残しておきます。
(来週の土曜日まで残しておくと、記憶が薄れそうなので)

サンプルコードのコメントにも書きましたが、syscall.Kill()がWindowsでは、定義されていないため、コンパイルエラーになります。こういうOSの仕組みがまったく異なっていることによるソースコードの差分でしょうが、以前の"return -1"ではなく、定義さえもされないということで、signalsample2.goはWindowsではコンパイルもできないということになります。
(今後、こういう問題は改善されるのだろうか…?)

execパッケージのポイント


Command構造体


execパッケージのサンプルのポイントは、Command構造体で、execするプロセスを管理するのですが、標準入力、標準出力、標準エラー出力にPipeを使って、アクセスすることができます。
それぞれ、StdoutPipe()StdinPipe()StderrPipe()を使ってio.ReadCloser()、io.WriteCloser()を受け取り、io/ioutilパッケージを利用するなどして読み取ります。

Start()でプロセスの起動、Wait()でプロセスの終了を待つ


exec.Command("コマンド名", パラメータ...)でCommand構造体を生成し、cmd.Start()でプロセスが起動します。Pipeで標準出力などにアクセスする場合は、必ず、Start()の呼び出しよりも前にStdoutPipe()を呼び出しておく必要があります。Start()の後に、呼び出すと、errorが返されてしまい、アクセスすることはできません。また、Start()を呼び出さずに、Wait()だけを呼び出してしまっても、無限待ちになってしまいますのでStart()→Wait()の順番は守るようにして下さい。
Start()はブロックするわけではなく、そのまま処理を続行します。もし、プロセスの終了をその場で待ちたい場合は、cmd.Run()を呼び出すと、内部でStart()→Run()の順番で呼び出しますので、ブロックされます。

ブロックして、標準出力を得るのであれば、Output()


コマンドの終了を待ち、しかも出力結果も受け取りたい場合は、
exec.Command().Output()とすると、戻り値に[]byteとして、標準出力の結果を受け取ることができます。また、exec.Command().CombinedOutput()にすると、
標準出力と、標準エラー出力がマージされた状態(恐らく、出力された順番)で[]byteを受け取ることができます。
この辺りは、実行して監視するコマンドによって使い分けが必要でしょう。

Signalは受け取るのみ可能

os/signalパッケージは、Notify()とStop()だけが定義されています。Notify()は外部からSignalを受け取った時に、引数で指定した、Channelに対して、受け取ったSignal構造体を送信します。Channelに送信されるSignalは同じく、引数で指定したSignalのみとなります。(サンプルコードでどんなものか、確認してみてください)

Stop()はChannelに格納されているSignal構造体を全てキャンセルする関数で、何もなければ、すぐに終了します。したがって、「Signalが送られていないことを保証する」事ができます。プログラムを終了するときなどに呼び出すもの。と思えばいいと思います。

Windows版はAPIに依存しているos/userパッケージ


user.Current()は実行ユーザを取得、user.Lookup("アカウント")は指定したユーザを取得、user.LookupId(uid)はユーザIDからユーザを取得します。
Mac/Linuxは、この説明で問題はないのですが、Windows版はkernel32.dllをLoadlibrary()した挙句に、Win32API(?)をコールしてAPIの動作に依存したコードになっています。(DLLの読み込みなどは、cgoが使われています。unsafeパッケージの使い方などは、いい勉強になるかも知れません)
(システムに依存しているのでどうにもならないと思いますが…。今後大丈夫なんだろうか…?)

実際User構造体はuid、gid、アカウント名、ホームディレクトリ、ユーザのフルネームなどが格納されますが、uid、gidは、GetTokenInformation()を使って、SIDを取得しています。uidの方は、TokenUserで指定し、gidはTokenPrimaryGroupで指定した結果を受け取ってそれぞれ設定していました。
ホームディレクトリは、GetUserProfileDirectory()が使われていました。
ユーザ名とフルネームについては、(Golang Cafeの最中には途中でやめたのですが、せっかくなので読みました。)ドメイン/ワークグループに参加しているかどうかを、NetGetJoinInformation()を呼び出し、結果が取得できるかどうかを確認しています。
ActiveDirectoryとかそういうのに参加している場合はこのAPIがエラーを返すのでしょう…。恐らく。
ドメイン/ワークグループに参加している場合は、TranslateName()を呼び出し、情報を取得します。ActiveDirectoryの場合は、NetUserGetInfo()を呼び出し情報を取得します。
その結果から、フルネームとユーザ名を取得し、UsernameとNameにセットされるという流れになります。

結果として、Windows版は大丈夫か?と言いたくなる程度にはWin32APIに依存しています。今後、.NETFrameworkの機能しか提供されなくなったらかなりまずそうです…。

ということで、Golangの標準パッケージを使うというのもひと通り見たなということで、
次回は、goauth2パッケージを使ってGoogle Apps APIを叩くという内容になります。

サンプルコードで挙動を確認するという段階は十分やったと思うので、今後は、実際に
コードを書き、"Goらしいコードの書き方"というのを追求できたらと思っています。

2014年2月15日土曜日

Golang Cafe #16を開催しました。

Golang Cafe #16を開催しました。

今回は、net/mailパッケージとnet/smtpパッケージを使って、メールを送信するサンプルを動かしました。

ソースコードはgithubにありますので、そちらをごらんください。

net/mailパッケージは、主にメールの解析に使います。

例えば、Barry Gibbs <bg@example.com>というサンプルで、mail.ParseAddress()を呼び出すと、
Barry Gibbsとbg@example.comをそれぞれ、メンバに格納するという事をします。メールアドレスの書式がおかしい(例えば、@が2個あるとか。)と、エラーが返り、不正なメールアドレスだということになります。

某携帯キャリアメールのアドレスに"."(ピリオド)が3つとか付いて仕様から外れるメールアドレスがあるということで、確認してみたところ、@の後ろにある場合はエラーになりますが、@の前にある場合は、エラーにはならないようです。

mail.ReadMessage()は、メール本文を読み取ると、メールヘッダ、宛先、BODYなどに分離して格納します。これにより、どんなヘッダがあるか、宛先メールアドレスなどが取得できます。multipartのメールを受信したい場合は、mime/multipartパッケージの関数を使うと、ファイルの解析などもできます。
で、詳細は+Takanobu Haginoさんが、解析されていたので、blogを見たほうがいいかもしれません。

net/smtpパッケージはパッケージ名からわかるようにメールの送信用の関数が定義されています。
smtp.SendMail()を使ってメールを送信するのですが、メールサーバの設定によって、コードを書き換える必要があります。今回のサンプルはGmailを利用してメール送信を実現しましたが、接続しているプロバイダのアドレスを使ってメールを送信する場合や、自前サーバからの送信の場合は、サンプルのままで動作するかどうかはわかりません。
(例えば、pop over smtpのように先にpop3のサーバと認証しておくというシーケンスになる場合など)
Gmailの場合は、認証がありますので、認証用のオブジェクトを生成しておいて、SendMail関数の引数に指定しています。認証が無ければ、nilを指定すれば良いと思います。

最近、Golang Cafe関係のblogの内容が薄い(後日の動作検証などができていない)ので改善しないといけないなと思うものの、VBAと格闘しています…。
ちょっと本格的にがんばろう。

2014年2月11日火曜日

第23回GDG中国勉強会@岡山を開催しました。

第23回勉強会@岡山を開催しました。

今回は、Dart Flight Schoolということで、DartのハンズオンとAngularDartのハンズオン、それから、Dartのテストの方法を紹介しました。

資料は、この後、GDG中国のサイトで公開しようと思います。

最初のDartのTutorialを進めて行きました。
こちらは、差分表示があったので、スケルトンから進める事ができて良かったかな?と
思います。いくつか、Dart固有の書き方なども出てきたので、それも説明できたので、個人的には満足していますが、参加者の方はいかがでしょうか。

次に、AngularDartのTutorialを進めていきましたが、Dartのハンズオンで時間を使ってしまったので、説明ベースのものになってしまいましたが、これに関しては、AngularJSをある程度やっている前提でないと辛いのかな?と思いました。
(実際聞いていると、やってない人もいらっしゃったし、Tutorialを少し…。という方もいらした。)
また、講師を務めた私も勉強不足だったように思いました。(最近、こういう「事前の調査」が足りない気がするので、少し考えないとダメかも…)

最後に、Dartのテストについて、少し紹介しました。時間が少ないのと、事前の練習不足もあって、結果は出たものの、しっかり伝えられたかは”?”がつくかもしれません。

フィードバックとしては、JavaScriptに変換した時に6000行ぐらい出力されるという結果を教えてもらったので、mobileでは使えないかも知れない(ロードに時間がかかる)ということと、速度面でどれくらい早いのか?が疑問ということも言われました。
(1.0→1.1で25%の速度UPがされていますが、「当社比」なので、他との比較結果が欲しいというご意見も…)
導入しようにも、「環境が整わないと」という意見もあったので、DartVMがChrome(リリース版)に入るとか、Chrome Packaged Appで使えるという方向に進んでくれたら良いのにな。とも思ったりしています。

全体的に、Dart Editorの挙動が怪しくて、いまいち、動きを確認するのに手間取ったり、JavaScriptの変換とか、pub getコマンドが動かなかったりと、Dart Editorの品質がもう少し上がってくれると非常にうれしいんだけど…。

このイベントはDartのスタートなので、今後もDartを触ってみていただけたらと思います。
重い(ロードに時間がかかる)とはいえ、一応、(JavaScriptに変換すれば)本番導入もできますので…w

後は、少し懇親会で情報交換を行ったりもしたので、今後の課題の洗い出しは、またゆっくりやろうと思います。

2014年2月7日金曜日

Golang Cafe #15を開催しました。

Golang Cafe #15を開催しました。

今回はnetパッケージを使ったsocket通信でした。
サンプルコードはgithubにあります。
netパッケージは、tcp、udp、unixsocketを同じインターフェイスで扱える
きれいな設計になっています。

まず、サーバ側のプログラムのポイントから。
C言語だと、bind()→listen()→accept()の順番で関数を呼び出しますが、Goの場合は、bind()はありません。
したがって、以下のようにListen()とAccept()の順番で呼び出せばいいです。

 // Listenはtcp/tcp4/tcp6/unix/unixpacketでなければエラーになる。
 // エラーを繰り返すと、指定したアドレス名のファイルができる?(for MacOSX)
 listener, err := net.Listen("tcp", "localhost:22000")
 if err != nil {
  log.Fatalln(err)
 }

 for {
  conn, err := listener.Accept()
  if err != nil {
   log.Printf("Accept: %v\n", err)
   continue
  }

  go receiveGoroutine(conn)
 }

Accept()の戻り値でnet.Connインターフェイスのインスタンスが受け取れますので、Read()、Write()を使って、クライアント側に受信、送信します。
(実際の型は、net.TCPConnなので、Type Assertionすれば型変換ができます。
タイムアウトの設定は、net.Connからはできないので、net.TCPConnに変換してから、設定する必要があります)
Read()とWrite()の処理はos.Fileの時と変わりませんので、説明は省略します。

UnixSocketを使う場合も同様に、net.Listen("tcp", アドレス)を、net.Listen("unix", アドレス)に変更すれば、net.UnixConnが返されるのでTCPConnと同じように扱えます。

今回のサンプルはAccept()後、goroutineを使って別スレッドで送受信するようにしていますので、たくさんのクライアントからの接続があっても、同じ挙動をします。もし、1対1の通信であれば、goroutineにしなくても良いです。(そのようなサーバプログラムを書くことは無いかもしれませんが…。)

net.Connはio.Reader、io.Writer、io.Closerなどのインターフェイスは持っていますので、ioパッケージ周りの便利関数群は使えます。
また、encoding/binaryパッケージを利用して、エンディアンを考慮したデータ構造を作る処理も入れてあります。
encoding/binaryは便利ですが、引数で使える型の制約があるので、(int32とかだと、errorが返される)符号がない、uint32などを利用しなければいけません。

クライアント側のポイントは、Connect()の代わりにDial()を使うことです。

 var recvData uint32

 // net.Dial() タイムアウトがないConnect
 // net.DialTimeout() タイムアウト検知するConnect
 // -5とかだとi/o timeoutと出るが…。
 // Dialerからtimeoutを設定する方法もあるが…。

 conn, err := net.DialTimeout("tcp", "192.168.0.6:8888", 5 * time.Second)
 // conn, err := net.Dial("tcp", "localhost:22000")
 // dialer := net.Dialer{Timeout: 10 * time.Second}
 // conn, err := dialer.Dial("tcp", "localhost:22000")
 if err != nil {
  log.Fatalln(err)
 }

 for i := 0; i < 2; i++ {
  err = binary.Read(conn, binary.LittleEndian, &recvData)
  if err != nil {
   log.Printf("Receive: %s\n", err)
   break
  }
  log.Printf("Receive From Server %v\n", recvData)

  log.Printf("Send To Server %d\n", recvData + 1)
  sendData := uint32(recvData + 1)

  err = binary.Write(conn, binary.BigEndian, sendData)
  if err != nil {
   log.Printf("Send: %v\n", err)
   break
  }
 }

 if err = conn.Close(); err != nil {
  log.Printf("Close: %v\n", err)
 }

サンプルのコードは、タイムアウトの検証をしようと思った途中のところだったので、net.DialTimeout()を使っていますが、net.Dial()で接続開始します。

net.Dial()の戻り値もnet.Connなので、サーバ側と同様の通信処理を実装すれば通信可能です。

本番の時に、「UDPだけは、うまく動作しない」状態だったのですが、私がUDPのプログラムを作ったことがなかっただけのようで、本番時に送受信ができるようになりました。
ただ、TCP/Unixsocketとは違って、コツがいるのでメモを残しておきます。

UDPのListenは、udpConn, err := net.ListenUDP("udp", udpAddr)を使います。
関数が違いますので注意して下さい。

func receiveGoroutine(conn *net.UDPConn, ch chan<- int) {
 var count uint32 = 1

 for i := 0; i < 2; i++ {
  var data [1024]byte

  _, addr, err := conn.ReadFrom(data[:])
  if err != nil {
   log.Printf("Recv: %v", err)
  }

  buf := bytes.NewBuffer(data[:])
  err = binary.Read(buf, binary.BigEndian, &count)
  if err != nil {
   log.Printf("Buffer: %v\n", err)
   break
  }
  log.Printf("Receive From Client %d\n", count)

  count++

  log.Printf("Send To Client %d\n", count)
  bufW := new(bytes.Buffer)
  err = binary.Write(bufW, binary.LittleEndian, count)
  if err != nil {
   log.Printf("Buffer: %v\n", err)
  }
  _, err = conn.WriteTo(bufW.Bytes(), addr)
  if err != nil {
   log.Printf("Send: %v\n", err)
   break
  }

 }

 if err := conn.Close(); err != nil {
  log.Printf("Close: %v\n", err)
 }

 ch <- 1
}

受信の処理は、ReadFrom()、送信の処理はWriteTo()を呼び出すようにしなければ、クライアントとキャッチボールができません。(これに気がつくのに時間がかかってしまいました)
また、TCPのサンプルは「わざと」接続後にサーバ側から送信させるようにしましたが、UDPだと、そのシーケンスは不可能(?)ということになります。理由は、ReadFrom()で受け取った、Addrインターフェイスの情報をWriteTo()の引数に設定しなければいけないので、最初は必ず受信ということになってしまいます。
(そういうものなの?って感じはするが…。)

次回は、メール関連(net/mail、net.smtpパッケージ)の予定です。

2014年2月2日日曜日

オープンセミナー2014@広島に参加しました。

久しぶりに、GDGではないイベントに参加してきました。

オープンセミナー2014@広島
http://osh-web.doorkeeper.jp/events/7534

今回のテーマは「TDD…そして Be Agile」ということで、チームで協力するという
方向性が主に語られていたように思います。

私は、2/11(火祝)のためにほぼすべての時間を”内職”(=Dart)に使ってしまいました。
和田さんの話の中で、「レフトウイング」と「ライトウイング」という単語を使って
ソフトウェア開発のプロジェクトの重要な要素を紹介されていました。

レフトウイング=管理手法的な面の内容
ライトウイング=技術面の内容
(実際はどちらでもいいし、左も右も関係なくて、どちらも無いとうまく回らない)

個人的にはすくすくスクラム瀬戸内の阿部さんが話していた内容とほぼ同じだったので
技術面の要素がもう少し欲しかった気もします。というか、実践が足りないだけなのかもしれませんが…。
他にも以前から聞いてみたかった、「導入事例」的なものも聞けて少し満足しました。
ただ、私は開発現場から離れてしまっているけれど…。

今回は、久しぶりに広島の技術者や、GDG中国のスタッフ、イベントへの参加者などとのコミュニケーションを目的にしていたので、オープンセミナー2014@広島の事はここまで。

1月〜3月まではフリーランスとしてGoogle技術を使ったり、広めたりしてきたのだけど、その頃は、「仕事がない」→「そろそろ来るのかな?」と感じていた所で、転職(?)してしまったので、もう手出しできないけど、Google AppsやAppEngineなどの、クラウド技術を使った要求が広島にもある(結構、喫緊の課題って感じで)ようで、直接協力できないのが非常に残念に思いました。
それと同時に、中国地方で技術者を見つけるか育てるかしないといけないなとも思いました。
(なかなか、Google Apps関連は難しい。。for Businessは有料だし…。無料版は機能制限があったり…。Active Directoryとか環境がないし…。私はWindows関連のスキルはあまりない…。)

少し、具体的な話もしてきたので、そのあたりで、無茶ぶりスキルを発揮してアクションが起こせるかもしれませんね。

得意ではないLTをやってみました。今回は5分ぶった斬りではなかったので言いたいことをとにかく突っ込んでおきました。やっぱりLTは難しい。あとは、資料に後付けを繰り返すのも良くないなと思いました。(全体的に流れがおかしくなった気がする)
資料は公開するようなものでもないので、非公開です。
OSC2013広島の時は、少ない資料でゆっくり話す感じにして失敗したのですが、
話しやすいのは、薄い内容のページが多く、切替をたくさんやる感じの方かもしれないです。コツはしっかり話すことを整理するということでしょうか。

そして、


今回は、こういうことになりまして、今は広島駅前のインターネットカフェに駐屯しています。Golang Cafeの終わった後の夕食の時に、「また行ってみたい」と言っていたらこんな形で実現するとは思いませんでした。
私も学生時代にバイトをしていたのですが、その頃の事を少し思い出します。
広島から岡山方面の終電は22時台までしかないようです。今度からまた車で来るようにしようかな…。
(しっかりコミュニケーションを図ったら、21時とかだと時間が足りない…。)

で、インターネットカフェで3時間程度は寝られたと思いますが、妙に目が覚めたので
blogを書いて、始発を待っています。6:00発があるので、それに乗ってみる予定です。

広島の方にも進められたのですが、ここのフラットはおすすめです。170cm前後の方なら十分寝ることができます。助かりました。