2019年9月30日 星期一

Linux shell顯示git branch

在shell上直接顯示git branch是很方便的資訊
以下是在不同的shell上的設定
.bashrc
 parse_git_branch() {  
    git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'  
 }  
 export PS1="\u@\h \[\033[32m\]\w\[\033[33m\]\$(parse_git_branch)\[\033[00m\] $ "  

.zshrc
 setopt prompt_subst  
 autoload -Uz vcs_info  
 zstyle ':vcs_info:*' stagedstr 'M'   
 zstyle ':vcs_info:*' unstagedstr 'M'   
 zstyle ':vcs_info:*' check-for-changes true  
 zstyle ':vcs_info:*' actionformats '%F{5}[%F{2}%b%F{3}|%F{1}%a%F{5}]%f '  
 zstyle ':vcs_info:*' formats \  
  '%F{5}[%F{2}%b%F{5}] %F{2}%c%F{3}%u%f'<pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"><code>parse_git_branch() {  
    git branch 2&gt; /dev/null &#124; sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'  
 }  
 export PS1=&quot;\u@\h \[\033[32m\]\w\[\033[33m\]\$(parse_git_branch)\[\033[00m\] $ &quot;  
 </code></pre>  
 zstyle ':vcs_info:git*+set-message:*' hooks git-untracked  
 zstyle ':vcs_info:*' enable git   
 +vi-git-untracked() {  
  if [[ $(git rev-parse --is-inside-work-tree 2> /dev/null) == 'true' ]] && \  
  [[ $(git ls-files --other --directory --exclude-standard | sed q | wc -l | tr -d ' ') == 1 ]] ; then  
  hook_com[unstaged]+='%F{1}%f'  
 fi  
 }  
 precmd () { vcs_info }  
 PROMPT='%F{5}[%F{2}%n%F{5}] %F{3}%3~ ${vcs_info_msg_0_} %f%# '  

2019年9月27日 星期五

Linux 開發環境設定紀錄

開始在適應使用Linux mint作為開發系統
使用上除了桌面與觸控板手勢的操作沒有mac好用外
基本上都還算上手
建置web開發環境 與執行原本的專案
發現了專案內有一些require大小寫有誤的地方
在linux下都會跳出錯誤訊息確認修正
環境的設定上 部份的小問題處理
在這作個紀錄

開發的系統移到mint上

1.ruby compass 使用安裝問題
You need to have Ruby and Compass installed and in your system PATH
問題處理
 sudo apt-get install gcc ruby-dev rubygems  
 sudo gem install compass  

2.系統問題
Error: ENOSPC: System limit for number of file watchers reached
設定可watch數量
 vi /etc/sysctl.conf  
 fs.inotify.max_user_watches=524288  

3.shell切換使用
 執行 /bin/bash | zsh  
 設定 vi ~/.bashrc 或 .zshrc  
 應用 source ~/.bashrc  
 設定預設 chsh -s /bin/zsh  

4. Android Studio 問題
使用AVD 發生
/dev/kvm permission denied.錯誤
ubuntu18後需要
 1.sudo apt install qemu-kvm.  
 2.sudo adduser $USER kvm //將自己帳號加入到kvm群組內  
 3.重新啟動電腦 就可以用了  

5.升級node 10 gulp錯誤
錯誤 gulp[5761]: ../src/node_contextify.cc:635:static void node::contextify
執行 npm i natives 修正

6.JAVA_HOME
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64

2019年9月22日 星期日

在Linux上build Kitematic

最近開始將工作環境從mac搬到Linux上
之前在mac上使用docker會使用kitematic這個很方便的管理界面
到github官方站台上只有winodw與mac的release版本可以下載
Linux則是只有source code需要自己build 執行程式

下載source code 解開發現原來kitematic是一個electron應用程式
直接執行Makefile是有問題的,原因是makefile內引用的npm script有錯
只能選擇自己依照標準electron專案的步驟來build
所有需要的script都已經放在package.json內
只要依照順序執行即可
 npm install // 安裝專案需要的node module  
 npm install electron-packager // 因為需要打包成執行檔 需要安裝electron打包程式  
 npm run release:debian:x64 // 依照自己的作業系統 在package.json內找到適合的script執行  
打包好的程式就會產生在dist目錄下

注意 如果build好的kitematic 執行有錯誤

we can't find a native setup

只要改用sudo kitematic執行即可

2019年9月13日 星期五

中秋

騎著摩托車 載著妹妹 我們要去果園過中秋
沿著88快速道路下的車道 往潮洲騎去
妹妹 還是一路上 唱著歌

平常山上 大概都是老爸一個人在這
今年老媽提早一天來 要包粽子
小弟 也回來了
跟著大弟的車到山上
妹妹已經是 小孩裡的大姊姊
平常安靜的山上 除了收音機的歌聲
廚房做菜的聲音 小孩的吵鬧聲
還有我們兄弟 跟老爸聊天的聲響
4點多開始烤蕃薯 烤玉米
一直到8點多 放完煙火鞭炮
中秋 全家人可以團聚的快樂時光






2019年9月10日 星期二

sequelize 建立沒有primaryKey的 table model

當建立的 table model ,table並沒有任何欄位有設定primaryKey
model會預設建立一個id的欄位當作primary key
可能在做查詢時會因為這樣不存在的id而出錯
若建立的model 無pk存在 加入一段檢查
移除id attribute 即可

let havePK = false
fields.forEach(field => {
  if (field.primaryKey) havePK = true
})
const model = sequelize.define('tableName', fields, option)
if (!havePK) model.removeAttribute('id')

2019年9月8日 星期日

Side Project : node-graphql-api 後端資料服務

長期以來自己開發主要都著力都於前端
SPA的架構下,前後端是完全乾淨分離的開發模式
這架構下資料的來源 都仰賴API的服務提供

以前接案 後端的部分都是使用php寫API服務
之後技術發展移到nodejs上
剛好公司也因為沒有完整的API系統
自己也就跳下來使用nodejs建構一個基礎的架構方便使用
原本只是方便自己使用的架構
也衍生變成提供公司內多專案共通使用的API服務

在既有的包袱與人員的限制下
許多自己想要實作的部分 變的很難在現有專案上實作
因此才會以自己的side project
全新打造一個自己理想中的系統

project預期目標
1.提供可以多人共同開發的系統架構
  開發者只需關專於API的邏輯書寫,其他系統都會幫你搞定
2.標準Restful API資料服務
3.Graphql 資料服務
4.單元測試
   所有功能與api都透過單元測試確保穩定性與程式品質
5.封裝可執行檔
  可以執行檔做最簡單的部署到客戶端主機
6.提供通用資料查詢
  系統本身提供通用Restful API與 Graphql
  在安裝設定後,即可對資料庫table做CRUD處理

專案進行 持續維護中
node-api github位置
https://github.com/ozzysun/node-graphql-api






Side Project開發計畫

最近這段時間 開始在寫自己的side project
其實早該開始,只是一直以來總希望自己在技術想實作的部分
可以直接在公司的專案上可以實現
不過現實跟理想總有差距

為什麼會去寫side project?
有開發上的發想,不是就在公司的專案內實作就好了?
也許有些自己想玩的東西 不在公司計畫內,
亦或會有所限制 施展不開來,在自己的Side Project上
就可以百分之百 把自己的想法 想像都實作出來
利用自己的一點時間 把一些放在腦袋裡的想法
一個個的實作出來 也是蠻有趣的
有興趣的github連結在這
https://github.com/ozzysun

2019年9月6日 星期五

透過FCM API發送 firebase clound message(FCM) 推播訊息

最近在要使用FCM發送推播給客戶端
當然測試可以直接在firebase console上發送
不過最終的應用還是會希望在自己的後台程式在指定的時間
發送推播訊息給指定控制的設備

FCM 本身有提供 API可以執行
以下說明
1. api url:https://fcm.googleapis.com/fcm/send
2.驗證
  在heaer以Authorization 欄位帶入伺服器金鑰
  可以在firebase設定/cloudMessage/金鑰 或 舊版伺服器金鑰
  firebase每個帳戶可以開多個專案(project))每個專案有各自的伺服器金鑰
  每個專案下可以開多個應用程式,這些應用程式共用這專案下的資訊
2.傳送的目標
to 與registration_ids只能擇一使用
傳送給單一device使用to,一次傳送多個則使用registration_ids
其實是可以統一都使用一次傳送多個則使用registration_ids 即可

device的token 是在device在連上fcm service時可以取到
以此token用來辨識device

3.傳送訊息類型
notification背景接收的推播
  也就是app在背景或未被開啟時會接收到的訊息
  訊息有固定的格式
data前景接收
 推播傳送的資料可以自訂key-value方式設定



ex:
method: post
header:
  Content-Type:application/json
  Authorization: key= "" 這裏可以透過firebase設定/cloudMessage/金鑰 或 舊版伺服器金鑰
body
  "to": 要傳送的device Token,
  "registration_ids":[], // 當要傳送多個device
  "collapse_key" : "type_a",
  "data":{
      "user": "oz",
      "info": "test"
  },
  "notification" : {
      "body" : "test4!", 
      "title" : "test4",
      "icon" : ""
  }

2019年9月5日 星期四

sequelize-auto 建立json model

nodejs上ORM主要是以sequelize為最主要使用
sequelize-auto則是用來將現有的db table 轉成data model的工具
可建立 js module當作ORM操作時使用的model物件

最近因為除了拿來用data model使用外
還會需要利用 這取得table schehema做其他應用
像在graphql就可以拿來產生object type
希望除了輸出js module當作model物件使用外
還希望可以輸出json格式 做其他應用
原sequelize-auto並無這部分功能
這幾天改寫這部分
有需要者 歡迎取用
https://github.com/ozzysun/sequelize-auto
使用說明

建立js module
sequelize-auto -o "./models" -d dbName -h localhost -u username -p 3306 -x yourpassword -e mysql

建立json
sequelize-auto -o "./models" -d dbName -h localhost -u username -p 3306 -x yourpassword -e mysql -j

將產生的json轉成js module
const { getModel } = require('sequelize/lib/utils')
const model = await getModel(sequelize, jsonfilePath)

2019年9月4日 星期三

Graphql 巢狀結構查詢設計

要設計巢狀結構查詢
除了最上層會是建議query外 其他子結點都會是一個個的物件類型
query與物件的定義差別是
物件下並不會定義type而是有fields 來定義這個物件下包含的多個field定義
query下就會直接定義type 不會有fields的定義

多層次巢狀的物件結構 真正的資料操作可能只在某一層
但要注意的是 在巢狀結構下
上層的物件無論是否有作用 resolve一定要return
下層的物件才會被執行resolve
假設希望設計一隻通用的查詢功能
可以指定db主機,指定db,指定table做通用查詢的功能

1. table物件
fields即是完全對應到db table欄位
 tableObject {  
  name: table名稱,  
  fields: [  
   {  
    name: 欄位名稱1,  
    type: String|.. 對應欄位本身columnType  
   }..  
  ]  
 }  

2. db物件:
fields對應到db內所有的table
查詢取到的list 內容每一筆資料內容即是tableObj所定義的欄位
所以這裏的type會是tableObject 的list
這裏的resolve是真正執行db操作的地方
 DbObject {  
  name: db名稱  
  fields: [  
   {  
    name: tableName,  
    type: [tableObject]  
    resolve:() => {  
     真正執行的地方在這裡  
    }  
   }  
  ]  
 }  

3. host主機物件
fields內對應到主機內所有的db
每個field都是對應到一台db,所以類型會是dbType
 HostObject {  
  name: db名稱  
  fields: [  
   {  
    name: dbName,  
    type: DbObject,  
    resolve: async(parent, args, context, info) => {  
     // 這裡不需要做處理 但一定要回傳  
     return true  
    }  
   }  
  ]  
 }  

4.建立查詢
查詢即是這個程式的進入點type是主機物件
resolve沒有作用但必須要有return 才會往下解析
 mainQuery {  
  name: host,  
  type: HostObject,  
  resolve: () => {  
   return true  
  }  
 }  

2019年9月2日 星期一

graphql巢狀結構resolve處理

當schema有巢狀結構,需要在子元件上做resolve
例如 db/table/column 這樣的結構
ex:
db.js
{
  name: 'db',
  type: [table],
  resolve: async(parent, args, context, info) => {
    return 'xxxx'
  }
}
table.js
{
  name: 'table',
  type: [column],
  resolve: async(parent, args, context, info) => {
    // parent 是接收db resolve回傳的資料
    return 'yyyy'
  }
}
column.js
{
  name: 'column',
  type: String,
  resolve: async(parent, args, context, info) => {
    // parent 是接收table resolve回傳的資料
    // 真正執行程序
    return 'zzz'
  }
}

在每個type下都有自己的resolve做處理
巢狀結構會由最上層開始執行resolve
執行完的return內容會傳給子物件resolve內的parent接收
以上例子 真正的執行運算是在column上
即使上層物件不需要做任何resolve處理
也必須要有return值 否則子物件的resolve不會被觸發

pkg 動態require module

使用pkg可以封裝nodejs服務建立可執行應用程式
新版的pkg已經支援es6
不再需要如同舊版要先透過babel轉成es5才能封裝

封裝時會依照檔案內有require的module全部封裝進來
但如果是要需要動態require的部分
例如依照程式邏輯判斷需要require的檔案
這部分如果不例外處理 在runtime時無法判斷真正要require的檔案

這部分需要做以下幾點的處理
1.package.json內
加入提示pkg要動態載入的script目錄

"pkg": {
  "scripts": [
    "./src/routes/**/**/*.js",
    "./src/graphql/**/**/*.js"
  ],
  "targets": [
    "node10-macos-x64",
    "node10-win-x64"
  ]
}

2.不能直接引用require
需要把require method另外存放使用

ex:
global.requireExternal = require
就可以在要require動態模組時改用
global.requireExternal

3.注意檔案路徑
為確保在跑nodejs或封裝成應用程式
要require的模組路徑必須以__dirname組成正確完整路徑
ex: filePath = `${__dirname}/src/query`

4.sample code

global.require = require
files.forEach(filename => {
  const requirePath = `${__dirname}/folder/${filename}`
  const MyClass = global.require(requirePath)
  new MyClass()
})

2019年9月1日 星期日

以GraphqlSchema 建立Schema Object物件

在使用graphql 建立要使用的schema與resolve schema部分大多數都會以GraphQL schema language定義
// 使用GraphQL Schema Definition Language(SDL)定義schema
const typeDefs = gql`
  type Query {
    hello: String
  }
`;
// 建立resolve
const resolvers = {
  Query: {
    hello: () => 'Hello world!',
  },
};
// server運作使用
const server = new ApolloServer({ typeDefs, resolvers });
把定義好的typeDefs 與resolvers丟給server就可以跑了

但是如果建立schema的程序希望可以不要手寫SDL
可能是透過程序自動產生 就無法做到
ApolloServer 除了吃typeDefs, resolvers 參數外
直接產生好schema
透過
const server = new ApolloServer({ schema }); 執行
也是可以的

以下範例是說明完全利用Graphql.js來建立schma物件

const graphql = require('graphql')
const queryType = new GraphQLObjectType({
  name: 'Query', // 要建立的type名稱,整個graphql至少要有一個Query, 其他可以是自建類型名稱
  fields: {
    hello: { // 設定有一個hello的查詢
      type: graphql.GraphQLString, // 類型為基本scarla類型,可透過graphql取得
      args: { // 若這查詢可以提供輸入參數
        name: { //參數名稱
          type: graphql.GraphQLString, //參數類型
        },
        age: {
          type: graphql.GraphQLInt
        }
      },
      resolve: (parent, args, context, info) => { // 執行資料處理,args會拿到
        return `im....${args.name} age=${args.age}` 
      }
    },
    oz: {
      name: 'oz',
      type: graphql.GraphQLString
    }
  }
})
const schema = new GraphQLSchema({
  query: queryType
})
const server = new ApolloServer({ schema })
這樣就可以完全用js去建立產生schema運作

以上建立的查詢在client做以下查詢

{
  firstName(name: "oz")
  age
}
得到回應結果

{
  "data": {
    "firstName": "[oz]",
    "age": null
  }
}
api參考https://graphql.org/graphql-js/type/#graphqlobjecttype