418 lines
9.9 KiB
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) {
|
|
|
|
// }
|