ETRI_SMARTFARM_POC/router/route.go

418 lines
9.9 KiB
Go

package router
import (
"encoding/json"
"etrismartfarmpoc/containermgmt"
"etrismartfarmpoc/model"
"fmt"
"io"
"log"
"net/http"
"strings"
"sync"
"time"
"github.com/google/uuid"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
"github.com/urfave/negroni"
)
type Notification struct {
Msg string `json:msg`
}
var db model.DBHandler
func init() {
var err error
db, err = model.NewDBHandler("postgres", "dump.db")
if err != nil {
panic(err)
}
}
// var rd *render.Render = render.New()
func NewRouter() http.Handler {
mux := mux.NewRouter()
mux.HandleFunc("/noti", GetNotification).Methods("GET")
mux.HandleFunc("/controllers", GetControllerList).Methods("GET")
mux.HandleFunc("/controllers", PostController).Methods("POST")
mux.HandleFunc("/services", GetServices).Methods("GET")
mux.HandleFunc("/services", PostService).Methods("POST")
mux.HandleFunc("/services", PutServices).Methods("PUT")
mux.HandleFunc("/devices", PostDevice).Methods("POST")
mux.HandleFunc("/devices", GetDevices).Methods("GET")
mux.HandleFunc("/devices", PutDevice).Methods("PUT", "OPTIONS")
mux.HandleFunc("/discover", GetDiscoveredDevices).Methods("GET")
mux.PathPrefix("/services/").HandlerFunc(RouteRequestToService)
n := negroni.Classic() // 파일 서버 및 로그기능을 제공함
n.UseHandler(mux)
return n
}
func EchoRoute(w http.ResponseWriter, r *http.Request) {
// w.Write([]byte(r.RequestURI))
// token := strings.Split(r.RequestURI, "/")
l := len([]rune("/services/"))
idx := strings.Index(r.RequestURI[l:], "/")
id := r.RequestURI[l : l+idx]
url := r.RequestURI[l+idx:]
m := make(map[string]string)
m["id"] = id
m["url"] = url
encoder := json.NewEncoder(w)
encoder.Encode(m)
}
func GetControllerList(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
list, err := db.GetControllers()
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
}
fmt.Println(list)
encoder := json.NewEncoder(w)
err = encoder.Encode(list)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
}
}
func PostController(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
controller, err := db.AddController(r.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
}
encoder := json.NewEncoder(w)
err = encoder.Encode(controller)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
}
sendNotification(&Notification{Msg: "Added Controller"})
}
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool { return true },
}
var notifications []chan *Notification
func sendNotification(noti *Notification) {
for _, ch := range notifications {
ch <- noti
}
}
func removeNotification(noti chan *Notification) {
for i, e := range notifications {
if e == noti {
discoveredDevices[i] = discoveredDevices[len(discoveredDevices)-1]
discoveredDevices = discoveredDevices[:len(discoveredDevices)-1]
}
}
}
func GetNotification(w http.ResponseWriter, r *http.Request) {
notiChan := make(chan *Notification, 1)
notifications = append(notifications, notiChan)
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
}
for {
notification := <-notiChan
// fmt.Println("Write!!", discoveredDevices)
if conn.WriteJSON(notification) != nil {
log.Println(err)
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
removeNotification(notiChan)
notiChan = nil
return
}
}
}
func GetDiscoveredDevices(w http.ResponseWriter, r *http.Request) {
noti := make(chan string, 1)
discoveredNotifications = append(discoveredNotifications, noti)
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
}
for {
<-noti
// fmt.Println("Write!!", discoveredDevices)
if conn.WriteJSON(discoveredDevices) != nil {
log.Println(err)
return
}
}
}
var waitPermission = map[string]chan bool{}
var mutex sync.Mutex
var discoveredDevices []*model.Device
var discoveredNotifications []chan string
func removeDevice(device *model.Device) {
for i, e := range discoveredDevices {
if e == device {
discoveredDevices[i] = discoveredDevices[len(discoveredDevices)-1]
discoveredDevices = discoveredDevices[:len(discoveredDevices)-1]
}
}
}
func GetDevices(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
devices, _, err := db.GetDevices()
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
encoder := json.NewEncoder(w)
encoder.Encode(devices)
}
// PostDevice : Handle for Receiving discovery message
func PostDevice(w http.ResponseWriter, r *http.Request) {
var device = &model.Device{}
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(device)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
if !db.IsExistController(device.CID) {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Wrong Controller ID"))
return
}
device.DID = uuid.NewString()
mutex.Lock()
waitPermission[device.DID] = make(chan bool)
discoveredDevices = append(discoveredDevices, device)
mutex.Unlock()
for _, noti := range discoveredNotifications {
noti <- device.DID
}
timer := time.NewTimer(3 * time.Second)
select {
case <-timer.C:
mutex.Lock()
delete(waitPermission, device.DID)
removeDevice(device)
mutex.Unlock()
for _, noti := range discoveredNotifications {
noti <- device.DID
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("This operation is not permitted"))
case b := <-waitPermission[device.DID]:
if b {
// 디바이스 등록 절차 수행
db.AddDevice(device)
db.AddService(device.SName)
// 디바이스 등록 알림
w.WriteHeader(http.StatusCreated)
sendNotification(&Notification{Msg: "Added Device"})
mutex.Lock()
delete(waitPermission, device.DID)
removeDevice(device)
mutex.Unlock()
for _, noti := range discoveredNotifications {
noti <- device.DID
}
} else {
mutex.Lock()
delete(waitPermission, device.DID)
removeDevice(device)
mutex.Unlock()
for _, noti := range discoveredNotifications {
noti <- device.DID
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("This operation is not permitted"))
}
}
}
func PutDevice(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
msg := map[string]string{}
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&msg)
fmt.Println("msg[did]: ", msg["did"])
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
}
ch, ok := waitPermission[msg["did"]]
if !ok {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Wrong Device ID is Sended"))
return
}
ch <- true
w.WriteHeader(http.StatusOK)
}
func GetServices(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
l, err := db.GetServices()
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
err = json.NewEncoder(w).Encode(l)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
}
func PutServices(w http.ResponseWriter, r *http.Request) {
var obj = map[string]string{}
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&obj)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
s, err := db.UpdateService(obj["name"], obj["addr"])
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
sendNotification(&Notification{Msg: "Update Service"})
err = json.NewEncoder(w).Encode(s)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
}
// func GetServiceList(w http.ResponseWriter, r *http.Request) {
// result := containermgmt.GetContainers(context.Background())
// b := result.Value(containermgmt.ReturnKey).([]byte)
// w.Write(b)
// }
func PostService(w http.ResponseWriter, r *http.Request) {
var obj = map[string]string{}
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&obj)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
err = containermgmt.CreateContainer(obj["name"])
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
w.WriteHeader(http.StatusCreated)
// result := containermgmt.CreateContainer(context.Background(), cont)
// b := result.Value(containermgmt.ReturnKey).([]byte)
}
func RouteRequestToService(w http.ResponseWriter, r *http.Request) {
l := len([]rune("/services/"))
var id string
var url string
idx := strings.Index(r.RequestURI[l:], "/")
if idx == -1 {
id = r.RequestURI[l:]
url = "/"
} else {
id = r.RequestURI[l : l+idx]
if len([]rune(r.RequestURI)) <= l+idx {
url = "/"
} else {
url = r.RequestURI[l+idx:]
}
}
// w.Write([]byte(vars["url"]))
host, err := db.GetAddr(id)
if err != nil {
w.WriteHeader(http.StatusNotFound)
return
}
log.Println("Route to", host+"/"+url)
req, err := http.NewRequest(r.Method, "http://"+host+"/"+url, r.Body)
if err != nil {
// 잘못된 메시지 포맷이 전달된 경우
w.WriteHeader(http.StatusBadRequest)
fmt.Fprint(w, err)
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
// 잘못된 메시지 포맷이 전달된 경우
w.WriteHeader(http.StatusBadRequest)
fmt.Fprint(w, err)
return
}
io.Copy(w, resp.Body)
}
// func mapService(urls []string) {
// }