วันอังคารที่ 30 มิถุนายน พ.ศ. 2563

การติดตั้ง Node.js บน Linux หรือ Rasberry

  •  เปิด Terminal  (Ctrl + Alt + T)

  • ใช้คำสั่ง เพื่อเช็คว่าเป็น ARMv7 ขึ้นไปหรือไม่ ถ้าไม่จะไม่สามารถลงได้

        uname -m

  • อัพเดทและอับเกรดระบบ

  • พิมพ์คำสั่ง

       sudo apt-get update
       sudo apt-get upgrade

  • พิมพ์คำสั่ง

      โหลด Version 8.x
      curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
      โหลด Version 9.x
      curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash -
      โหลด Version 10.x
      curl -sL https://deb.nodesource.com/setup_10.x | sudo bash -

  • ติดตั้ง nodejs

        sudo apt install nodejs

  • เช็ค version nodjs

       node -v หรือ
       node –version

  • ทดสอบ

      node
     > 1 + 3
        4
     >  # We can hit Ctrl-C twice to exit the REPL and get back to the bash (shell) prompt.

  • ติดตั้ง npm

       sudo apt install npm
  • เช็ค version npm

       npm -v หรือ
       npm –version

  • โหลด nvm

       curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash

  • ให้ อยู่ current terminal session โดยใช้คำสั่ง

       source ~/.bashrc
  • เช็ค version nvm

        nvm --version

  • ติดตั้ง nodejs ล่าสุด

        nvm install --lts

  • ติดตั้ง nodejs version 8.9.4

        nvm install 8.9.4

  • เช็ค ลิส version

       nvm ls

  • คำสั่งใช้ version

        nvm use 10.16.0

  • คำสั่ง check version current

        nvm current

  • เซต defaut version

        nvm alias default 10.16.0

  • Install development tools

To be able to compile and install native add-ons from the npm registry you need to install the development tools:

sudo apt install build-essential


  • Uninstall Node.js

If for some reasons you want to uninstall Node.js package, you can use the following command:

sudo apt remove nodejs

  • ติดตั้ง MongoDB

       sudo apt-get install mongodb-server
       sudo reboot

You can now start-up MongoDB:
service mongodb start

and check status:
service mongodb status
you can stop with:
service mongodb stop
If you want to run MongoDB utilities from another computer with the “target” being a DB on the R-Pi 3.  Make sure you enable remote connections on the R-Pi.  Edit the /etc/mongodb.conf file and change the “bind-ip” to:
bind_ip = 0.0.0.0
This will enable connections from any IP address. For example, my R-Pi has the IP address of 10.0.0.187.  I could restore a DB “dump” directory from my Macintosh running MongoDB 3.6 via:
mongorestore --host 10.0.0.187
You can import a JSON DB from your local host to the R-Pi via:
mongoimport --host 10.0.0.187 --db bldata --collection images --file bl_images.json 
The “mongo” shell works well and I have not experienced any issues:
$ mongo
MongoDB shell version v3.4.18
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.18
Welcome to the MongoDB shell.
> show databases;
ProdLogs  0.002GB
bldata    0.560GB
local     0.000GB
> use bldata;
switched to db bldata
> show collections;
images
> db.stats();
{
"db" : "bldata",
"collections" : 1,
"objects" : 1637919,
"avgObjSize" : 977.5499405037734,
"dataSize" : 1601147621,
"storageSize" : 584765440,
"numExtents" : 0,
"indexes" : 1,
"indexSize" : 16314368,
"ok" : 1
}
>


ติดตั้ง ExpressJS Framework
mkdir myapp cd myappnpm init แล้วใส่ข้อมูลที่จำเป็น entry point: (app.js)npm install express --save
ทดลองการสร้างเว็ปด้วย ExpressJS
  1. สร้างไฟล์ชื่อ app.js ในโฟลเดอร์ myapp
  1. พิมพ์โค๊ดดังนี้
const express = require(‘express’)ว const app = express() app.get(‘/’, (req, res) => res.send(‘Hello World!’)) app.listen(3000, () => console.log(‘Example app listening on port 3000!’))
3. Run ด้วยคำสั่ง
node app.js
4. ลองเข้า Browser เปิดเว็บไซต์จะพบข้อความ Hello World!
http://192.168.1.101:3000
ติดตั้ง MQTT ของ Node.js
npm install mqtt -g
ข้อมูลเพิ่มเติมที่ https://www.npmjs.com/package/mqtt

วันอาทิตย์ที่ 26 เมษายน พ.ศ. 2563

วิธีเปิดโหมดนักพัฒนา ( Developer Option )บนมือถือ andriod


วิธีเปิดโหมดนักพัฒนา ( Developer Option )บนมือถือ andriod

วิธีง่าย ๆ ตามขั้นตอนนี้
1. ไปที่ Setting 
2. เลือก About เมนูล่างสุด

3. ไปยัง Software information

4. กดคลิกไปที่ Build Number ประมาณ 3 รอบติดกัน ก็จะมีเมนู Developer Options ขึ้นมาค่ะ เท่านี้ก็สามารถใช้โหมดนักพัฒนาได้แล้ว
Stay awake
เป็นโหมดให้ที่เวลาเราชาร์ตไฟแล้วไฟหน้าจอจะไม่ดับ
USB debugging
เมื่อเราติ๊กถูกตรงนนี้จะเป็นการเชื่อมต่อโดยตรง และจะไม่เรียกใช้งานข้อมูลตัวเครื่องโทรศัพท์ผ่านทางโปรแกรมเฉพาะบน PC ส่วนใหญ่ใช้เวลาแฟลชรอมครับซึ่งถ้าไม่ได้ทำอะไรแบบนั้นก็ไม่ต้องเลือกก็ได้
Allow mock locations
ใช้ทดสอบ location สำหรับการ develop application ผ่าน debugging
Show touches
อันนี้ก็เป็นการแสดงตำแหน่งการสัมผัสบนหน้าจอแต่จะไม่ระเอียดเหมือน Pointer location
Pointer location
เป็นการแสดงตำแหน่งของการสัมพัสของหน้าจ มีบอกตัวเลขตำแหน่งเส้นที่เราลากนิ้วไป
Show Surface updates
เป็นการแสดงแสง Flash บนหน้าจอของเราเวลาที่มีการอัพเด (เวลาเรากดหน้าจอจัมีแสงแว๊บๆบนจอดูเหมือนเครื่องพังเลยทีเดียวเชียว)
Show Layout bounddaries
สำหรับดู layout ของวัตถุต่างๆในแอพ (เหมาะสำหรับคนที่ดีไซน์หน้าตาแอพ)
Show CPU usage
แสดงว่าตอนนี้ CPU กำลังทำงานอะไรอยู่
Force GPU rendering
ใช้ในการเพิ่มประสิทธิภาพฮาร์ดแวร์ 2d ในแอพพลิเคชั่น ไปหาข้อมูลมาเค้าบอกว่าเวลาเจอเกมส์หรือแอพอะไรที่เป็น 2D อะไรกระตุกๆก็ลองเลือกดูจ้า
Don’t keep activities
เคยเจอไหมเวลาเราเล่นเกมอะไรอยู่แล้วต้องการจะเลิกเล่นก็กดปุ่ม Home แต่พอกลับเข้าไปในเกมมันก็ยังทำงานอยู่ตรงนี้แหละถ้าเลือกไม่ว่าเราจะออกจะแอพอะไรก็ตามไม่ว่าด้วยวิธีไหนมันจะปิดแอพให้โดยสมบูรณ์
Background process limit
จำกัดการทำงานของแอพเบื้อหลัง แอพเบื้องหลังคืออะไรแอพที่ทำงานอยู่แล้วเราเรียกแอพใหม่ขึ้นมาใช้และสลับไปมาเพื่อดูเข้าออกจากโปรแกรมนั้นไปโดยไม่ได้ปิด เช่น เล่นเกมอยู่แล้วสลับไปดูเว็บ

วันจันทร์ที่ 20 เมษายน พ.ศ. 2563

ทำระบบ Realtime บน Web

ทำระบบ Realtime บน Web

ถ้าต้องทำระบบ chat, dashboard, กราฟ ที่ต้องการให้ข้อมูล update เอง จะทำยังไงดี ?
ระบบ Realtime ที่ส่วนใหญ่นิยมใช้ใน web มี
  1. Short Polling
  2. Long Polling
  3. Websocket
  4. Server-Sent Event (SSE)

Short Polling

คือการที่เราตั้งเวลาให้ไปดึงข้อมูลทุก ๆ n วินาที

ข้อดีของ Short Polling

  • เป็นวิธีทำระบบ realtime ที่ง่ายที่สุด
  • รันที่ไหนก็ได้ เพราะเป็นการเรียก HTTP ธรรมดา

ข้อเสียของ Short Polling

  • เปลือง resource มาก เพราะถึงข้อมูลไม่เปลี่ยน ก็จะมีการส่งข้อมูลตลอดเวลา

ตัวอย่างการทำ Short Polling

ฝั่ง Server ไม่ต้องทำอะไรเลย (ง่ายไหม 🙈)
func getDataShortPolling(w http.ResponseWriter, r *http.Request) {
    data := getData()

    w.Write(data)
}
ฝั่ง Browser ทำได้ง่าย ๆ 2 วิธี
  1. setInterval - เขียนง่าย แต่ถ้า server ช้าจะโดนยิง
     setInterval(fetchData, 3000) // ดึงข้อมูลทุก 3 วินาที
    
  2. setTimeout - ยังเขียนง่ายอยู่
     async function startPolling () {
         await fetchData() // รอให้ดึงข้อมูลเสร็จก่อน ค่อยรออีก 3 วินาที
         setTimeout(startPolling, 3000)
     }
    
     startPolling()
    

Long Polling

คล้าย ๆ Short Polling แบบที่ 2 แต่ไม่ต้องมี setTimeout และให้ Server รอจนกว่าข้อมูลเปลี่ยนค่อยตอบ api กลับมา

ข้อดีของ Long Polling

  • ประหยัด resource กว่า Short Polling
  • รันที่ไหนก็ได้ เพราะเป็นการเรียก HTTP ธรรมดา

ข้อเสียของ Long Polling

  • มีโอกาสโดน timeout บ่อย
  • อาจจะมีถ้าเขียนแบบง่าย ๆ อาจจะมีช่วงที่ไม่ได้ข้อมูลล่าสุด (api ตอบ response กลับไป แล้วมี data change ก่อนที่ client จะยิง api เข้ามาอีกรอบ)

ตัวอย่างการทำ Long Polling

ฝั่ง Server ต้องรอให้ Data เปลี่ยนก่อน ค่อยตอบกลับไป
func getDataLongPolling(w http.ResponseWriter, r *http.Request) {
    if r.URL.Query().Get("long") != "1" {
        getDataShortPolling(w, r)
        return
    }

    select {
    case <-untilNewDataReceived():
    case <-r.Context().Done():
        // client close connection
        return
    }


    data := getData()

    w.Write(data)
}
ฝั่ง Browser ยังเขียนง่ายอยู่
async function startLongPolling () {
    await fetchDataLongPolling()
    startLongPolling()
}

fetchDataShortPolling() // ดึง data มาแสดงตอนเปิดเว็บก่อน
startLongPolling() // หลังจากนั้นค่อยใช้ long Polling รอ data ใหม่
ปัญหาของ Long Polling แบบนี้คือ ถ้า data เปลี่ยนระหว่าง request เราจะไม่ได้ data นั้น เช่น
           poll  poll
Client: ----|-----|-----
Server: -----|--|--|----
             1  2  wait
จะเห็นว่าถ้า data เปลี่ยนจาก 1 เป็น 2 ระหว่างที่ไม่ได้ poll อยู่ client จะไม่ได้ data
วิธีแก้คือ อาจจะต้องส่ง token (เช่น timestamp) ของ data ล่าสุดไป แล้วเวลา poll ให้เอา token นั้นส่งกลับไปหา server

Web Socket

Web Socket เป็น full-duplex communication คือ client กับ server สามารถส่งข้อมูลไปกลับได้ผ่าน connection เดียว

ข้อดีของ Web Socket

  • ประหยัด resource ไม่มี overhead ของ http, เปิด connection ทิ้งไว้ สามารถส่ง data ไปกลับได้
  • มี library ครบ แทบทุกภาษา

ข้อเสียของ Web Socket

  • ทำงานบน Layer 4 (TCP) ถ้ามี middleware ที่ไม่รองรับ HTTP Upgrade ก็จะไม่สามารถใช้ได้ (เช่น Cloud Run)
  • มีโอกาสโดน timeout ถ้า set middleware ไม่ดี (เช่น reverse proxy, load balancer, cdn)

Server-Sent Event (SSE)

คล้าย ๆ Web Socket แต่ server push data หา client ได้ทางเดียว

ข้อดีของ Server-Sent Event

  • รันที่ไหนก็ได้ เพราะทำงานบน HTTP ธรรมดา
  • ประหยัด resource กว่า Short/Long Polling
  • เขียนง่าย ไม่ต้องมี library

ข้อเสียของ Server-Sent Event

  • IE ใช้ไม่ได้ 🤨
  • ถ้าเขียนเองต้องมีความรู้เรื่อง HTTP ในระดับนึง

ตัวอย่างการทำ Server-Sent Event

หน้าตาของ sse event
: บรรทัดที่ขึ้นต้นด้วย : คือ comment

: เราสามารถกำหนดชื่อ event ได้
event: add
data: 1

event: remove
data: 1

: ถ้าไม่กำหนดชื่อ event default คือ event: message
data: hello, sse

: ถ้า data มี 2 บรรทัด
data: hello,
data: sse
Server เขียนไม่ยากมาก แต่ต้องรู้ว่าจะส่งข้อมูลยังไง
func getDataWithSSESupport(w http.ResponseWriter, r *http.Request) {
    // ถ้าไม่ส่ง ?sse=1 มา ถือว่ายิงมาแบบ api ธรรมดา
    // จะได้ทำ api เดียว รองรับทั้ง api ธรรมดา ทั้ง sse
    if r.URL.Query().Get("sse") != "1" {
        getDataShortPolling(w, r)
        return
    }

    w.Header().Set("Content-Type", "text/event-stream")
    w.Header().Set("Cache-Control", "no-cache") // ไม่ให้ cache
    w.WriteHeader(http.StatusOK)

    for {
        data := getData()
        fmt.Fprintf(w, "data: %s\n\n", data)
        w.(http.Flusher).Flush()

        select {
        case <-untilNewDataReceived():
        case <-r.Context().Done():
            return
        }
    }
}
Browser ยิ่งง่าย
const source = new EventSource('/data')

source.addEventListener('add', (ev) => {
    //
})

source.addEventListener('remove', (ev) => {
    //
})

source.addEventListener('message', (ev) => {
    //
})

// หรือจะรับ ทุก event มาเลย
source.onmessage = (ev) => {
  console.log(ev)
}
ลองเอาไปรันเล่น ๆ
package main

import (
	"fmt"
	"net/http"
	"time"
)

func main() {
	http.ListenAndServe(":8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/" {
			w.Write([]byte(`<!doctype html>
<div id=app></div>
<script>
const $app = document.getElementById('app')
const source = new EventSource('/data')
source.addEventListener('message', (ev) => {
	console.log(ev)
    app.innerHTML += ev.data + "<br>"
})
</script>`))
		}

		if r.URL.Path == "/data" {
			w.Header().Set("Content-Type", "text/event-stream")
			w.Header().Set("Cache-Control", "no-cache")
			w.WriteHeader(http.StatusOK)

			for {
				data := time.Now().Format(time.RFC3339)
				fmt.Fprintf(w, "data: %s\n\n", data)
				w.(http.Flusher).Flush()

				select {
				case <-time.After(time.Second):
				case <-r.Context().Done():
					return
				}
			}
		}
	}))
}

สรุป

  • ใช้ Server-Sent Event 🙈🙈🙈🙈🙈🙈
นอกจาก
  • ไม่อยากแก้ code server
  • คนใช้ไม่เยอะ
  • data ไม่จำเป็นต้อง realtime มาก
ให้ใช้ Short Polling

Note

  • Web socket ค่อนข้างมีปัญหาเวลา deploy เพราะบางที reverse proxy ไม่ support http upgrade แต่ library บางตัวจะ fallback ไปใช้ short/long Polling มีโอกาสที่ server จะโดน request ยิงรัว ๆ ยิ่งถ้าใช้ service ที่คิดตังตามจำนวน request ก็จะโดนค่าตรงนี้เยอะมาก อาจจะหลายล้าน request ต่อวัน
  • ถ้าจะ support IE ค่อยใช้ Long Polling ถ้าไม่ support IE ไปใช้ SSE ดีกว่า
  • หรือจะทำ Short Polling ไปก่อนก็ได้ แล้วคนใช้เยอะค่อยให้ api เดิม support SSE แก้ code เพิ่มไม่เยอะ
ที่มา https://acoshift.me/2019/0012-realtime-web.html

Set MongoDB in the windows path environment

  Let’s set MongoDB in the windows environment in just a few steps. Step 1: First download a suitable MongoDB version according to your mach...