パスワードを忘れた? アカウント作成
163659 journal

fslashtの日記: [GO] CentOSに「Go言語」をインストールしてtwitter投稿スクリプトを作る

日記 by fslasht

 先日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コマンドで、正しく設定されているか確認

● リポジトリからソースを取得

$ 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.
8l is a modified version of the Plan 9 linker. ※ Plan9はtypo?

 8gと8lが、x86用のコンパイラとリンカーのようです。

● サンプルソースを入力してみる

 適当な作業用のディレクトリを掘って移動します。
(僕は、~/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()」ってしないとだめですよ。あたりまえか。

BASE64エンコード

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"));
        (以下省略)

 これはわかっちゃえば簡単ですね。

Twitter投稿スクリプト「twpost.go」

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に回収されるときにはクローズされるのだろうか・・・

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
typodupeerror

※ただしPHPを除く -- あるAdmin

読み込み中...