prism

2014-09-30

iOS push notification

首先您必須到 https://developer.apple.com/ 去新增一個 App,一般就是你要用 push notification 的應用程式

設定好名字,還有 ID ,記得要把 Push Notifications 的服務打勾

我這裡說明就用中文,因為英文的說明有一堆了

接下來就可以打開您的 Mac / 應用程式 / 工具程式 / 鑰匙圈存取

我們選憑證輔助程式,從憑證授權要求憑證




把他存下來,我舉的例子就叫 PushMsg ,把檔名改成 PushMsg 所以你會得到 PushMsg.certSigningRequest 這一個 CSR ,待會要到 apple 網站上面產生憑證



產生後,到鑰匙圈存取 應用程式,選鑰匙的地方,你會看到有 PushMsg 的公鑰和密鑰,點選專用密鑰,按下滑鼠右鍵輸出憑證,輸出成 PushMsg.p12 待會用










這時候,請用剛剛的 PushMsg.certSigningRequest 到 Apple 開發者網站的 App 設定 notification 的地方去產生憑證,可以下載後,

開發模式,你會得到 aps_development.cer ,實際部署模式,請依此類推



我們現在有 PushMsg.certSigningRequest , PushMsg.p12 , 還有 aps_development.cer 接下來,我們來產生,Server 端程式需要的憑證格式

這裡的程式,我們用 Golang 的範例,其他用 Python , Node.js 或是其他語言的朋友請依此類推

產生 cert.pem


openssl x509 -in aps_development.cer -inform der -out cert.pem

產生 key.pem 由於我很懶,key.pem 不想加密碼,程式不想再判斷密碼部分,我用這樣,如果你要加 pass phrase 就不要加上 -nodes 即可

openssl pkcs12 -in PushMsg.p12 -out key.pem -nodes

最後就是用 Apple 文件上面的 openssl 測試即可,沒有錯誤,就是 OK 了

openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert cert.pem -key key.pem 

最後附上 golang 的測試程式,實際上已經有現成的 library 可以用 https://github.com/anachronistic/apns

只有連線的測試,有用 openssl 測試就可了,直接執行沒有錯誤,就是連線沒有問題了,送訊息可以直接用上面的 library


package main

import (
 "crypto/tls"
 "fmt"
 "net"
 "os"
)

func main() {

 // load 
 cert, err := tls.LoadX509KeyPair("./cert.pem", "./key.pem")
 if err != nil {
  fmt.Println("key error: ", err)
  os.Exit(1)
 }
 conf := &tls.Config{
  Certificates: []tls.Certificate{cert},
  ServerName:   "gateway.sandbox.push.apple.com",
 }

 // connect to APPLE 
 conn, err := net.Dial("tcp", "gateway.sandbox.push.apple.com:2195")

 if err != nil {
  fmt.Println("tcp error: ", err)
  os.Exit(1)
 }

 tlsconn := tls.Client(conn, conf)

        // be nice
 err = tlsconn.Handshake()
 if err != nil {
  fmt.Println("tls error: ", err)
  os.Exit(1)
 }

}




參考資料

http://www.raywenderlich.com/32960/apple-push-notification-services-in-ios-6-tutorial-part-1

https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html

http://bravenewmethod.com/2011/02/25/apple-push-notifications-with-go-language/

2014-09-16

groupcache

這一個 golang 裡面非常帥氣的 library ,作者是原 memcached 的作者之一,主要就是讓 cache 機制再簡化

集群的部署能力也還不錯,完全不用再管 server instance ,我對這種,以簡單為名的 library 最沒有招架能力了

https://github.com/golang/groupcache

使用上也是非常的帥氣,可以參考 OSCON 的簡報

http://talks.golang.org/2013/oscon-dl.slide#1

詳細的使用上可以參考, source code ,或是 test case,還有很多種用法

以下是我用的範例,您可以用在很多地方,像是外部 url fetch ,或是很重的 query 或是檔案 IO 之類的
就是平常,你 cache 怎麼用,就可以怎麼用,cache 只有支援 拿,和寫,

以下的例子用這樣拿資料,我的 cache key 大概到小時,就用自己算每小時不同的 key
FileInfoCache.Get(nil, cacheFileInfo, groupcache.AllocatingByteSliceSink(&data))

另外,FileInfoFetch 就是另外一個做很多 disk IO 的工作
dest.SetBytes(FileInfoFetch(path))



// Example for groupcache
// snip from my code

var (
        FileInfoCache  *groupcache.Group
)

func init(){

        //////////////////////////////////////////
        // init book query cache
        //cacheAddr := "127.0.0.1:55555"
        //peers := groupcache.NewHTTPPool("http://" + cacheAddr)
        // the cache key is compose with timestamp hour
        // 2006-01-02 15!!!url
        getter := groupcache.GetterFunc(func(ctx groupcache.Context, key string, dest groupcache.Sink) error {
                keys := strings.SplitN(key, "!!!", 2)
                //ts := keys[0]
                path := keys[1]
                dest.SetBytes(FileInfoFetch(path))
                return nil
        })


        if FileInfoCache == nil {
                // cache not been init
                // allocate 64 MB memory for groupcache
                FileInfoCache = groupcache.NewGroup("FileInfo", 64<<20, getter)
        }
        

}




你看,帥不帥氣,完全不需要另外跑,cache server daemon ,如果要組成 cluster 就直接在程式裡用 HTTPPool 的服務

bolt

記錄一下一些好用 golang library

blot 是一個純 golang 以簡單為美開發的 key value 資料庫,後來會用他,是因為一開始要存非常簡單的資料

想說就用 sqlite 來存就好了,反正欄位很少,資料結構簡單,開發環境是 Mac ,目標環境是 Linux ,部署的流程

就用 python 的 fabric 簡化,本地端編譯完 linux/amd64 的程式,複製到遠端 Linux,可是 github.com/mattn/go-sqlite3 有用到

CGO ,在 Mac 上面必須要用 gcc for linux 來編譯,編譯完後,到了目標機器上面又有 glibc 版本的問題,覺得這樣很花時間

不方便,另外就是 CGO 的編譯速度沒有很帥氣,立馬就決定找一個不依賴 CGO 的 key value store,目前覺得蠻合用了,這個專案的頁面的第一句話

就說服我了(我也太沒原則了吧) "Simple is the new beautiful."

https://github.com/boltdb/bolt

使用簡單,由於我的 server  主要還是用簡單 JSON 格式,所以就先不用 gob 來 Encode 資料


// Example for bolt
package main

import (
        "encoding/json"
        "fmt"

        "github.com/boltdb/bolt"
)

var (
        db         *bolt.DB
        dbpath     = "./user.db"
        userbucket = []byte("users")
)

func main() {

        db, _ = bolt.Open(dbpath, 0644, nil)

        key := []byte("unique_key_here")
        var value = struct {
                Name  string
                Title string
        }{"Somebody", "Gopher"}

        fmt.Println(key, value)

        // in write transaction
        err := db.Update(func(tx *bolt.Tx) error {
                bucket, err := tx.CreateBucketIfNotExists(userbucket)
                if err != nil {
                        return err
                }
                data, err := json.Marshal(value)

                fmt.Println("Please remember handle the error", err)

                if err == nil {
                        bucket.Put(key, data)
                }

                return nil
        })

        fmt.Println(err)
        // in read
        db.View(func(tx *bolt.Tx) error {
                bucket := tx.Bucket(userbucket)
                if bucket != nil {
                        // if have a struct to restore it
                        //json.Unmarshal(bucket.Get([]byte(key)), &user)
                        fmt.Println(bucket.Get(key))
                }

                return nil
        })

}


2014-09-05

品嘗姊姊的手工蛋黃酥

請假一天,把櫥櫃的中島桌面完成,小聚時

姊姊帶來手工今天剛做好的無糖豆沙蛋黃酥,只有食材的味道,正港台灣口味