Compute EngineのインスタンスにGUIを追加

実現したいこと

GCEのインスタンスGUIをインストールして、ローカルPCからGUIで操作する

やり方

  • デスクトップ環境のGnomeをインストー

GCEにSSHしてから、コマンド実行

$ sudo apt-get update
$ sudo apt-get install gnome-core
sudo apt-get install gnome-panel
sudo apt-get install vnc4server

tcp:5901のポートを開ける

Finder → 移動 → サーバーへ接続 → vnc://IPAdress:5901を入力して接続する

VNCの解像度変更

sudo vi /usr/bin/vncserver して、$geometry = "1280x800";の値を変更。

gnomeのショートカット変更

defaultの設定だと、s,hなどキーがショートカットになるため、文字入力ができない。

gnomeのショートカットキーの修正
export DISPLAY=:1
gsettings set org.gnome.desktop.wm.keybindings show-desktop "['<Shift><Alt>F1']";
gsettings set org.gnome.desktop.wm.keybindings maximize "['<Primary><Super>Up','<Alt>KP_5']";
gsettings set org.gnome.desktop.wm.keybindings panel-main-menu "['<Alt>F1']";
gsettings set org.gnome.desktop.wm.keybindings minimize "['<Primary><Super>Down','<Alt>F5']";

Google Cloud Platform タスクキューの利用

タスクキューは色々便利。

タスクはApp Engineのアプリとして動作する。

利用イメージ

  • 時間のかかる処理をタスクとしてタスクキューに登録する。
  • タスクキューはタスク(API)を呼ぶ。
  • タスクが処理される。

利点

  • 非同期処理が可能。
  • リトライが可能。

go言語の指针 & *

Go语言保留着C中值和指针的区别,但是对于指针繁琐用法进行了大量的简化,引入引用的概念。所以在Go语言中,你几乎不用担心会因为直接操作内寸而引起各式各样的错误。Go语言的指针,基本上只剩下用于区分 byref 和 byval 语义。

运算符就是简单的 & 和 * 一个取地址、一个解析地址。

 
package main
 
import(
    "fmt"
)
 
func main(){
    var i int // i 的类型是int型
    i=1 // i 的值为 1;
    var p *int // p 的类型是[int型的指针]
    p=&i         // p 的值为 [i的地址]
 
    fmt.Printf("i=%d;p=%d;*p=%d\n",i,p,*p)
 
    *p=2 // *p 的值为 [[i的地址]的指针] (其实就是i嘛),这行代码也就等价于 i = 2
    fmt.Printf("i=%d;p=%d;*p=%d\n",i,p,*p)
 
    i=3 // 验证想法
    fmt.Printf("i=%d;p=%d;*p=%d\n",i,p,*p)
}
这段代码执行结果:

i=1;p=0x4212f100;*p=1

i=2;p=0x4212f100;*p=2

i=3;p=0x4212f100;*p=3

函数的参数传递可以看下面例子:
 
package main
 
import "fmt"
 
type abc struct{
    v int
}
 
func (a abc)aaaa(){ //传入的是值,而不是引用
    a.v=1
    fmt.Printf("1:%d\n",a.v)
}
 
func (a *abc)bbbb(){ //传入的是引用,而不是值
    fmt.Printf("2:%d\n",a.v)
    a.v=2
    fmt.Printf("3:%d\n",a.v)
}
 
func (a *abc)cccc(){ //传入的是引用,而不是值
    fmt.Printf("4:%d\n",a.v)
}
 
func main(){
    aobj:=abc{}  //new(abc);
    aobj.aaaa()
    aobj.bbbb()
    aobj.cccc()
}
输出结果:
 

1:1

2:0

3:2

4:2

传值与传指针
当我们传一个参数值到被调用函数里面时,实际上是传了这个值的一份copy,当在被调用函数中修改参数值的时候,调用函数中相应实参不会发生任何变化,因为数值变化只作用在copy上。

传指针比较轻量级 (8bytes),只是传内存地址,我们可以用指针传递体积大的结构体。如果用参数值传递的话, 在每次copy上面就会花费相对较多的系统开销(内存和时间)。所以当你要传递大的结构体的时候,用指针是一个明智的选择。

Go语言中string,slice,map这三种类型的实现机制类似指针,所以可以直接传递,而不用取地址后传递指针。(注:若函数需改变slice的长度,则仍需要取地址传递指针)

要访问指针 p 指向的结构体中某个元素 x,不需要显式地使用 * 运算,可以直接 p.x ;

 

一个稍微复杂的例子
 
package main
 
import "fmt"
 
type S map[string][]string
 
func Summary(paramstring)(s*S){
    s=&S{
        "name":[]string{param},
        "profession":[]string{"Javaprogrammer","ProjectManager"},
        "interest(lang)":[]string{"Clojure","Python","Go"},
        "focus(project)":[]string{"UE","AgileMethodology","SoftwareEngineering"},
        "hobby(life)":[]string{"Basketball","Movies","Travel"},
    }
    return s
}
 
func main(){
    s:=Summary("Harry")
    fmt.Printf("Summary(address):%v\r\n",s)
    fmt.Printf("Summary(content):%v\r\n",*s)
}
 
 
输出:
Summary(address): 0x42131100

Summary(content): map[profession:[Java programmer Project Manager] interest(lang):[Clojure Python Go] hobby(life):[Basketball Movies Travel] name:[Harry] focus(project):[UE Agile Methodology Software Engineering]]

exit code 0, process exited normally.


 

参考资料:

使用Go语言一段时间的感受
http://blog.jobbole.com/14386/

[Go 语言] 指针,地址,形参,实参
http://my.oschina.net/nalan/blog/77373

从例子中学习 go 语言 —— 数据结构、指针
http://ilovers.sinaapp.com/drupal/node/33

Google App EngineにGoのWebAppをデプロイするために、いろいろ調査

Users API

Users Go API Overview  |  App Engine standard environment for Go  |  Google Cloud Platform

Users APIで何ができる?

  • ログイン中のuserを確認する
  • 認証用のページへユーザを誘導。(redirect)
  • Googleアカウントを持ってないユーザに新しいアカウントを作ってもらったり。

ユーザ認証

認証済の場合、ログアウト用のURLを取得し、ページに表示させる。 未認証の場合、ログイン用のURLを取得し、ページに表示させる。

import (
        "fmt"
        "net/http"

        "google.golang.org/appengine"
        "google.golang.org/appengine/user"
)

func welcome(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-type", "text/html; charset=utf-8")
        ctx := appengine.NewContext(r)
        u := user.Current(ctx)
        if u == nil {
                url, _ := user.LoginURL(ctx, "/")
                fmt.Fprintf(w, `<a href="%s">Sign in or register</a>`, url)
                return
        }
        url, _ := user.LogoutURL(ctx, "/")
        fmt.Fprintf(w, `Welcome, %s! (<a href="%s">sign out</a>)`, u, url)
}

管理者としての登録を強制させる

登録必須のページが存在する場合、app.yamlを利用して、ユーザに強制登録してもらうことが可能。
必要なロールなどを設定に任せば、認証メカニズムを独自に実装しなて済む。
詳細はyamlの設定を参照。

app.yaml Reference  |  App Engine standard environment for Go  |  Google Cloud Platform

OAuthの利用

標準ユーザ認証以外に、OAuthを利用することも可能。
※OAuthは認証プロトコルで、ユーザは第三者(アプリケーション)に許可を与えることで第三者がユーザの情報にアクセスできる。

import (
        "fmt"
        "net/http"

        "google.golang.org/appengine"
        "google.golang.org/appengine/user"
)

func welcomeOAuth(w http.ResponseWriter, r *http.Request) {
        ctx := appengine.NewContext(r)
        u, err := user.CurrentOAuth(ctx, "")
        if err != nil {
                http.Error(w, "OAuth Authorization header required", http.StatusUnauthorized)
                return
        }
        if !u.Admin {
                http.Error(w, "Admin login only", http.StatusUnauthorized)
                return
        }
        fmt.Fprintf(w, `Welcome, admin user %s!`, u)
}

認証のoptions

認証方法を選択することも可能。(設定変更することで)以下の方法がある。

Googleアカウントと開発サーバー

開発サーバーのシミュレーターはダミーの認証を提供する。これを利用すればユーザ認証、管理者認証のテストが容易にできる。

Android GridViewのItemの背景を変える

簡単かと思ったが、やってみたらけっこうはまった。

やり方

ArryAdapterにitemのlayoutを設定、itemのbackgroundにtextViewの背景を変更するselectorを設定。

ハマったところ

selected状態に色を変えたくて、android:state_selectedを設定してもぜんぜん効かない。 なんと、android:state_activatedに変えたらいけた。

ソース

ArrayAdapter<RoomBean> adapter = new ArrayAdapter<>(getApplicationContext(), R.layout.grid_room_item, result);
                gridView.setAdapter(adapter);
                gridView.setChoiceMode(GridView.CHOICE_MODE_SINGLE);
                gridView.setItemChecked(0, true);
<GridView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="0.17"
            android:id="@+id/gridViewRoom"
            android:numColumns="3"
            android:layout_marginTop="10dp"
            android:verticalSpacing="10dp"
            android:horizontalSpacing="10dp"
            android:padding="10dp"
            android:background="#999999"
            android:listSelector="@android:drawable/list_selector_background">
        </GridView>
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"

    android:id="@+id/textView1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:textSize="30sp"
    android:padding="20dp"
    android:background="@drawable/item_room_selector"
    android:text="TextView" />
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:state_activated="true" >
        <shape android:shape="rectangle">
            <solid
                android:color="@color/LightBlue"
                />
        </shape>
    </item>
    <item
        android:state_pressed="true" >
        <shape android:shape="rectangle">
            <solid
                android:color="@color/LightBlue"
                />
        </shape>
    </item>
    <item>
        <shape android:shape="rectangle">
            <solid
                android:color="@color/White"
                />
        </shape>
    </item>

</selector>

LinearLayoutの中のボタンをbottomに表示させる

androidのlayoutを理解してないまま、gravityとかでやってみたが、 だめだった。

結局、開けたいスペースにSpaceを入れて高さがいっぱいまで設定したらうまくいった。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <!-- Other views -->
    <Space
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <!-- Target view below -->
    <View
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

</LinearLayout>