CentOSに「Go言語」をインストールしてtwitter投稿スクリプトを作る
先日Googleが新言語「Go」を発表しました。
→The Go Programming Language (公式サイト)
→シンプルで高速、Googleの新プログラミング言語「Go」 (マイコミジャーナル)
Googleの開発チームが新たに提案するプログラミング言語、それが「Go」だ。
Goのオフィシャルサイトの記述によれば、シンプルで高速、安全、そして並列処理が可能な点が特徴として挙げられている。C言語風の記述形式ながら異なる文法体系を持ち、ポインタが利用可能なものの、バッファオーバーフローの遠因となる複雑なポインタ演算を排除。文法体系はシンプルで、ガベージコレクションが用意されているほか、並列実行を考慮して軽量なプロセス間通信を行う手段が提供され、簡易なプログラミングで大規模処理が可能なシステムが構築できるという。
現状、Linux版とMacOSX版があり、Lixnu版はx86だけではなくてARM版もあります。
NetWalkerでお勉強できるかも。
とりあえず、サーバのCentOS(x86)にインストールしてみます。
環境はこんな感じです。
$ cat /etc/redhat-release
CentOS release 5.4 (Final)
$ uname -a
Linux www.dokokano.net 2.6.18-164.6.1.el5 #1 SMP Tue Nov 3 16:18:27 EST 2009 i686 i686 i386 GNU/Linux
では、順を追って作業していきましょう。
(参考:Installing Go)
● ビルドに必要なソフトをインストール
バージョン管理システムは、Mercurialなのでクライアントをインストールする。(実行ファイルは、hg です。水銀です。)
(rootで作業)
# yum install mercurial
あと、ビルドで必要になるので bisonもはいってなければインストールする。
(rootで作業)
# yum install bison
● 環境変数を設定する
.bashrc を編集
vi .bashrc以下の行を追加
export GOROOT=~/go環境変数の意味は・・・
export GOOS=linux
export GOARCH=386
export GOBIN=~/go/bin
export PATH=$PATH:$GOBIN
$GOROOT go関連のルートディレクトリ(ここでは、ホーム直下の go )
$GOOS 実行するOS (linux,darwin,naclのいずれか)
$GOARCH アーキテクチャ CPUの種類(386,amd64,armのいずれか)
$GOBIN 実行ファイル格納場所(ここでは、go/bin とした)
※ 実行ファイルにあらかじめPATHを通しておかないと、ビルドも失敗するので注意
setコマンドで、正しく設定されているか確認
※ ログインしなおすか、sourceコマンド使って、.bashrcにへの変更を反映させるのをお忘れなく
● リポジトリからソースを取得
$ hg clone -r release https://go.googlecode.com/hg/ $GOROOT
● ビルド
バイナリ生成先のディレクトリ作成
$ mkdir $GOBIN
ソースフォルダへ移動
$ cd $GOROOT/src
ビルド
$ ./all.bash問題なければ数分で完了
● コンパイラはどれ?
アーキテクチャによって、コンパイラのファイル名が異なるようです。
Command Documentationによると・・・
8g is the version of the gc compiler for the x86.8gと8lが、x86用のコンパイラとリンカーのようです。
8l is a modified version of the Plan 9 linker. ※ Plan9はtypo?
● サンプルソースを入力してみる
適当な作業用のディレクトリを掘って移動します。
(僕は、~/work/gotest/ を作りました)
ソースを入力します。(ソースは、Installing Goを引用)
ファイル名「hello.go」で作成してみます。
$ vi hello.go以下のソースを入力してください。
package main
import "fmt"
func main() {
fmt.Printf("hello, world. 日本からこんにちは!\n")
}
● コンパイル→リンク→実行
$ 8g hello.go
「hello.8」が生成されます。
リンク
$ 8l hello.8「8.out」ができました!
実行
$ ./8.out
hello, world. 日本からこんにちは!
じゃーん、無事「hello, world. 日本からこんにちは!」と表示されました。
これで、野望に一歩近づいた!
● vimでgoのsyntaxハイライトを使う設定
vimのsyntax定義ファイルをコピー(コピー先は、環境に合わせて読み替えてください)
$ cp $GOROOT/misc/vim/go.vim /usr/share/vim/vim70/syntax/
vimの設定を編集
# vi ~/.vimrc以下の行を追加
au BufNewFile,BufRead *.go set ft=go※ ホントは /usr/share/vim/vim70/scripts.vim を編集したほうがいいかな
● Twitter投稿アプリを作ろう・・・手探りなう
Xでキャラがぐりぐり動くのつくろうと思ったけど、GUI用のパッケージはなさげなのでhttpパッケージで、twitterクライアントでも作ることにしました。
コマンドラインから投稿できるようになってれば、なんとなく実用性もあるんじゃないかな。
base64(BASIC認証のため)とhttpパッケージの使い方がわかればなんとかなるはず。
なるはずだけど・・・
パッケージのドキュメント読んでもいまいち使い方がわからない・・・
$GOHOME/src/pkg/ にあるソースのテストコードを見て使い方をがんばって把握するる。
たとえば、base64だったら、$GOHOME/src/pkg/encoding/base64/base64_test.go を読めばなんとなくわかる。
ここで、はまったのは、テストコードのなかで、「NewEncoder()」とか呼び出している部分は、自分のパッケージ(mainとか)の中からは「base64.NewEncoder()」ってしないとだめですよ。あたりまえか。
import "encoding/base64";
(中略)
s := "Good Morning!"; // 元の文字列
bb := &bytes.Buffer{}; // エンコード先のバッファ
encoder := base64.NewEncoder(base64.StdEncoding, bb); // エンコーダーを生成
encoder.Write(strings.Bytes(s)); // エンコーダーに文字列を渡す(その際、Byte配列に変換)
encoder.Close(); // エンコーダー終了
b := bb.String(); // BASE64エンコード後の文字列を取得
つぎはHTTPパッケージで送信
・・・が、ぜんぜんうまくいかない・・・
requestオブジェクトを組み立てるところまではうまくいったんだっけどなあ
しかたがないので、netパッケージをつかってみました。
$GOHOME/src/pkg/net/net.go が参考になりました。
TCPでなにか送信
これはわかっちゃえば簡単ですね。
var conn net.Conn;
var err os.Error;
conn , err = net.Dial("tcp","",sHOST + ":80" );
if err!=nil {
fmt.Printf("err=%s\n",err);
}
conn.Write( strings.Bytes(sREQ + "\r\n"));
(以下省略)
package main
import (
"fmt";
"flag";
"bytes";
"strings";
"encoding/base64";
"os";
"net";
"http";
)
func main() {
// コマンドラインパラメーター取得 sUser := flag.Arg(0);
sPass := flag.Arg(1);
sStat := flag.Arg(2);
// BASIC認証用にID/PassをBASE64エンコード
sAuthSrc := sUser + ":" + sPass;
bb := &bytes.Buffer{};
encoder := base64.NewEncoder(base64.StdEncoding, bb);
encoder.Write(strings.Bytes(sAuthSrc));
encoder.Close();
sAuthEnc := bb.String();
// 送信本文をURLエンコード
sStatURL := http.URLEscape(sStat);// リクエスト情報作成
sHOST := "twitter.com";
sREQ := "POST /statuses/update.json?status="+sStatURL+" HTTP/1.1";
sClient := "fslasht's Go exsample.";
sClientVer := "0.1";
// 接続&データ送信
var conn net.Conn;
var err os.Error;
conn , err = net.Dial("tcp","",sHOST + ":80" );
if err!=nil {
fmt.Printf("err=%s\n",err);
}
conn.Write( strings.Bytes(sREQ + "\r\n"));
conn.Write( strings.Bytes("Host: " + sHOST + "\r\n"));
conn.Write( strings.Bytes("Authorization: Basic " + sAuthEnc + "\r\n"));
conn.Write( strings.Bytes("User-Agent: " + sClient + "\r\n"));
conn.Write( strings.Bytes("X-Twitter-Client: " + sClient + "\r\n"));
conn.Write( strings.Bytes("X-Twitter-Client-Version: " + sClientVer + "\r\n"));
conn.Write( strings.Bytes("\r\n"));
conn.Write( strings.Bytes("status=" + sStat +"\r\n")); // なんかこれ効いてない
}
$ 8g twpost.go
$ 8l -o twpost twpost.8
実行時の書式
$./twpost <ユーザー名> <パスワード> <本文>実行例
$./twpost fslasht himitsu "いけいけごーごーじゃんぷ"
結果例→これ
※ X-Twitter-Client指定してるのに反映されませんね・・・→申請しないといけないらしい
● おわりに
なんとかtwitterクライアントができました。
Goで検索しても全然情報みつからないので激しく手探りでした。Processingやioの教訓は・・・
いきなりパッケージ使って作っちゃいましたが、肝心のGoならではの言語仕様を活用してない><
そのへんが一番面白いところなので使えるしたい。
ある程度かけるようになったら、C言語で書いたコードをリンクすることもできるのでSDL呼び出して使いたいなあ。
/
その他
・使ってないパッケージをimportしてたり、参照されない変数を定義しているとコンパイル時にエラーになる。Warningくらいにしてくれるオプションがあるかな。
・今回のコードはエラー処理とかしてません。あと、TCPのコネクションをクローズしてないけど、GCに回収されるときにはクローズされるのだろうか・・・