parse-server 架設小記

花了一些時間簡單的架設 parse-server,把過程紀錄一下。

  1. 安裝 docker 與 docker-compose
  2. git clone https://github.com/parse-community/parse-server.git
  3. 建立 docker image:
    cd parse-server && docker build --tag parse-server .
  4. git clone https://github.com/parse-community/parse-dashboard.git
  5. 建立 docker image:
    docker build --tag parse-dashboard .
  6. 建立 config.json,your-ip 要填你瀏覽器可以存取到的 IP ,而不是用 docker container 的 ip ,我本來是填 http://parse:1337/parse (請看 docker-compose.yml 裡的 links),但這樣 parse-dashboard 會說無法連到伺服器。
    {
      "apps": [
        {
          "serverURL": "http://<your-ip>:1337/parse",
          "appId": "APPLICATION_ID",
          "masterKey": "MASTER_KEY",
          "appName": "MyApp",
          "production": false
        }
      ],
      "users": [
        {
          "user": "user",
          "pass": "pass"
        }
      ]
    }
    
  7. 建立 docker-compose.yml
    ---
    version: '3'
    services:
      mongodb:
        image: mongo:3.4
    
      parse:
        image: parse-server:latest
        environment:
          FOO: bar
        command: --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://mongodb/test
        links:
          - mongodb
        ports:
          - "1337:1337"
      parse-board:
        image: parse-dashboard:latest
        environment:
          PARSE_DASHBOARD_ALLOW_INSECURE_HTTP: "yes"
        links:
          - parse
        ports:
          - "4040:4040"
        volumes:
          - ./config.json:/src/Parse-Dashboard/parse-dashboard-config.json
    
  8. docker-compose up

要啟用 push notification ,得調整 docker-compose.yml 裡 parse service 的 command,加入 push notification 的相關選項。從選項可以看出,parse 仍是利用 GCM/APNs 來發送通知。

LiveQuery 在佈署到 AWS 時,要用 ALB,因為 ELB 不支援 WebSocket。

在正式環境裡,要記得把 PARSE_DASHBOARD_ALLOW_INSECURE_HTTP 設為 “no” ,並且加上 SSL 。也可以參考 parse-server github 網頁上對於佈署的說明,有蠻多佈署到平台上的現成範例可參考。

參考資料:

webui-aria2-git

aria2 的 web UI,紀錄一下怎麼使用。

  1. 安裝:yaourt -S webui-aria2-git
  2. 啟動 aria2d:放在 /usr/lib/systemd/user/ 下的 service 檔案,需要額外加上 –user 參數,所以要啟動得用 systemctl –user start aria2d 。要確定是否有啟動,可以用 netstat 檢查 port 6800 是否在 listening 狀態。
  3. Web UI 部份的啟動:主要是靜態 HTML,所以只要調整 Web server 的設定,指向 /usr/share/webui-aria2/ 就可以了。

提高安全性:

  1. 修改 /usr/lib/systemd/user/aria2d.service ,在 ExecStart 那行後面加上 –rpc-secret=<your_token> ,–rpc-secret 是加上 token。
  2. 打開網頁時,在連線設定裡填入步驟 1 的 token 。

參考資料:

ultisnips/vim-snippets

本來是打算用 snipmate 的,但看到這篇 UltiSnips 让 Vim 飞起来 – 吕小荣 ,馬上轉投 UltiSnips 。XD

安裝與設定上沒什麼困難。

" Install ultisnips using Vundle
Plugin 'SirVer/ultisnips'
Plugin 'honza/vim-snippets'

裝好以後,輸入特定的關鍵字 (關鍵字要自己去挖 vim-snippets 下的 UltiSnips/snippets 資料夾裡的檔案),再按 tab ,就會自動出現 snippet,如果 snippet 有指定 ${1:pass} 之類的,可以在輸入完畢以後,用 ctrl + j 或 ctrl + k 來切到上一個或下一個位置。

我卡到的問題是自訂的 snippets 沒被載入。找了半天,才發現我把 UltiSnips 資料夾放錯位置。(把我的時間還來!!)

UltiSnips 的 python docstring 可以自訂,看格式是要用 google, sphinx, doxygen, numpy 還是 jedi 的格式。在 .vimrc 裡放下面這行就可以了:

let g:ultisnips_python_style="google"

Jenkins EnvInject

Jenkins 裡能用的環境變數可以參考:

  1. Jenkins 架設好以後的 /env-vars.html/
  2. https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project#Buildingasoftwareproject-JenkinsSetEnvironmentVariables

但是有時候,就是覺得少了那麼一些。我們可以使用 EnvInject plugin 在建置時,插入需要的環境變數,讓後續的建置步驟使用。

使用方法:

  1. 在 EnvInject 之前的步驟產生出類似這樣格式的檔案 key=value ,假設檔名是 build.properties
  2. 加入 EnvInject,在 Properties File Path 這欄位放入步驟 1 產出的檔名 build.properties ;Properties Content 不填。
  3. 在 EnvInject 之後的步驟欄位裡,就可以使用 ${key} 了。

參考資料:

docker daemon socket

dockerd 預設只使用 /var/run/docker.sock,如果需要讓其他的 host 去管理,就需要額外設定。

在 Ubuntu trusty 裡,要編輯 /etc/default/docker,加入

DOCKER_OPTS="-H 0.0.0.0:2375"

然後重新啟動就可以了。

不過這樣設定以後,就等於任何人都可以透過這個 port 去控制你這台機器裡的所有 container ,官方建議加上 TLS 來保障連線的安全,晚點再來研究怎麼加上 TLS 。

參考資料:

docker-compose.yml 裡的相依性與啟動順序

簡單的說,depends_on 跟 links 只保證相依的 container 有啟動,但不保證裏面的服務已經啟動完畢,可以接受服務了。

我找到的解決方法,是利用 wait-for-it 這個 bash script 來測試 container 的 port 是否開啟。docker-compose v3 好像有要試圖解決這問題,不過還沒正式釋出。也是有一些其他的解法,不過,我覺得不是很直覺,就先放著了。

參考資料:

 

docker-machine 的 port forwarding

最近在 Windows 試 docker-toolbox,想讓外部連線連到 host 時,其實是連接到 在 VM 裡服務的 docker container,所以查了看怎麼做。

結果比想像中還要簡單,就是利用 vboxmanage controlvm 去設定 port forwarding 就可以了。

/c/Program\ Files/Oracle/VirtualBox/VBoxManage.exe controlvm vm_name natpf1 "rule1,tcp,,80,,80"

那要刪除掉這條 port forwarding 的規則,用

/c/Program\ Files/Oracle/VirtualBox/VBoxManage.exe controlvm vm_name natpf1 delete rule1

即可。

那在 linux 下也可以用同樣的方式來做 port forwarding,唯一的限制是非 root 用戶,沒辦法做 port 1024 以下的 port forwarding。

說明:

  • docker-toolbox 其實是把 docker, docker-machine, docker-compose, virtualbox 等工具包裝起來的一個便捷安裝包
  • vm_name 可以用 vboxmanage list vms 取得
  • 也可以開啟 VirtualBox ,在左側選到虛擬機,再進設定去改動。

參考資料:

TypeScript 學習筆記(6) – Classes

主要看這篇:Classes

大致用法跟 C#/Java 差不多,幾個特別的地方:

  1. readonly :成員可以加上 readonly 來修飾,表示是唯讀。
  2. 有 getter/setter:可以用 get/set 這兩組 accessor 讓 method 變成屬性。
    class Employee {
        private _fullName: string;
    
        get fullName(): string {
            return this._fullName;
        }
    
        set fullName(newName: string) {
            this._fullName = newName;
        }
    }
    
  3. static:類似 java/c# 那樣的用法,原本 javascript 是沒有的。
  4. abstract 修飾:可以加在 class 前面,也可以加在 method 前面,用法跟 java/C# 相似。

後面提到的 constructor functions 是一個進階技巧,不過感覺上用到機會不大。

TypeScript 學習筆記(5) – Interface

今天是看這篇:Interfaces

TypeScript 有 anonymous interface ,就像下面的程式一樣:

// 有點 anonymous interface 的味道
function printLabel1(labelledObj: { label: string }) {
    console.log(labelledObj.label);
}

// 也可以明確的用 interface 寫
interface LabelledValue {
    label: string;
}

function printLabel2(labelledObj: LabelledValue) {
    console.log(labelledObj.label);
}

 

在宣告成員時,如果加入 ? ,表示可有可無,這個寫法應該是參考了 Ruby 的作法

interface SquareConfig {
    color?: string;
    width?: number;
}

 

用 readonly 修飾詞則是表示唯讀

interface Point {
    readonly x: number;
    readonly y: number;
}

 

如果要需告一個唯讀的陣列,可以用 ReadonlyArray

let ro: ReadonlyArray = a;

 

我覺得 Function types 比較不是那麼直覺,不容易看懂

interface SearchFunc {
    (source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
    let result = source.search(subString);
    return result > -1;
}

大抵來說就是 python 的 __call__ 或是 c++ 的 operator()。

Indexable type 也是不太直覺

interface StringArray {
    [index: number]: string;
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];

let myStr: string = myArray[0];

大抵來說就是 python 的 __item__ 或是 c++ 的 operator[]。

要讓類別實作介面是用 implements 關鍵字

interface ClockInterface {
    currentTime: Date;
}

class Clock implements ClockInterface {
    currentTime: Date;
    constructor(h: number, m: number) { }
}

 

下面這例子是想要限定 ClockInterface 裡的 constructor 必須符合 ClockConstructor 規範的作法,第一眼不太容易看懂。

interface ClockConstructor {
    new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
    tick();
}

// 傳進來的 ctor 必須符合 ClockConstructor 的規範,要有 hour 跟 minute 這兩個 number 型別的參數。
function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
    return new ctor(hour, minute);
}

class DigitalClock implements ClockInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("beep beep");
    }
}
class AnalogClock implements ClockInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("tick tock");
    }
}

let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);

 

介面也可以繼承,跟類別一樣,是用 extends,而且允許繼承多個

interface Shape {
    color: string;
}
interface PenStroke {
    penWidth: number;
}
interface Square extends Shape, PenStroke {
    sideLength: number;
}

 

蠻令我驚訝的是,Interface 可以繼承 class … @_@

TypeScript 學習筆記(4) – 變數

JavaScript 提出了兩個新的關鍵字:let 與 const。使用 let 可以避免使用 var 的一些奇妙現象;而 const 就是跟 C 的 const 一樣,避免再次指定值給這個變數。

Variable Declarations 裡提了許多 JavaScript 使用 var 宣告變數時的奇妙現象,然後解說為什麼要改用 let。這部份我偷懶跳過去了,我的想法是,就都改用 let 吧。

另外有提到 Destructuring,就是類似 Python 的 unpack :

// JavaScript/TypeScript
let input = [1, 2];
let [first, second] = input;

Python 則是:

# Python
first, second = (1, 2)

也跟 Python 3 一樣,有取 remain items 的效果:

let [first, ...rest] = [1, 2, 3, 4];
console.log(first); // outputs 1
console.log(rest); // outputs [ 2, 3, 4 ]

Object destructuring 是個比較特別的東西,意思跟 destructuring 差不多,但對象是 object,也就是可以將 object 的某幾個屬性放到變數裡。

let o = {
    a: "foo",
    b: 12,
    c: "bar"
}
let { a, b } = o;
({ a, b } = { a: "baz", b: 101 });  // 這樣也可

也支援 remaining items 的方法:

let { a, ...passthrough } = o;

Object destructuring 還支援 default values,意思是如果 wholeObject 沒有 b 屬性時,就把 b 指定為 1001:

function keepWholeObject(wholeObject: { a: string, b?: number }) {
    let { a, b = 1001 } = wholeObject;
}

也可以應用到 function 上,我覺得這個例子比較清楚,可以應用在只取物件的某幾個屬性來使用時:

function f({ a, b } = { a: "", b: 0 }): void {
    // ...
}
f(); // ok, default to { a: "", b: 0 }

Spread 算是陣列相加的一個 syntax sugar,可以把 first, second 塞到 bothPlus 這陣列裡去:

let first = [1, 2];
let second = [3, 4];
let bothPlus = [0, ...first, ...second, 5];

也可以應用在 object 上,目前想到可以用來做 object proxy 或是 composite 之類的,不過不適合也不一定。

let defaults = { food: "spicy", price: "$$", ambiance: "noisy" };
let search = { food: "rich", ...defaults };