From c37f07d1416b7e371db7b32799df53df39210aa6 Mon Sep 17 00:00:00 2001
From: Christian Pointner <equinox@helsinki.at>
Date: Wed, 30 Dec 2015 21:50:46 +0100
Subject: improved response handling at websocket interface


diff --git a/src/helsinki.at/rhimport/session_store.go b/src/helsinki.at/rhimport/session_store.go
index 7fe6585..0d149c6 100644
--- a/src/helsinki.at/rhimport/session_store.go
+++ b/src/helsinki.at/rhimport/session_store.go
@@ -58,6 +58,19 @@ type getSessionRequest struct {
 	response chan getSessionResponse
 }
 
+type listSessionsResponse struct {
+	sessions     map[string]string
+	responsecode int
+	errorstring  string
+}
+
+type listSessionsRequest struct {
+	user     string
+	password string
+	trusted  bool
+	response chan listSessionsResponse
+}
+
 type removeSessionResponse struct {
 	responsecode int
 	errorstring  string
@@ -80,6 +93,7 @@ type SessionStore struct {
 	done       chan bool
 	newChan    chan newSessionRequest
 	getChan    chan getSessionRequest
+	listChan   chan listSessionsRequest
 	removeChan chan removeSessionRequest
 }
 
@@ -134,6 +148,30 @@ func (self *SessionStore) get(user, id string) (resp getSessionResponse) {
 	return
 }
 
+func (self *SessionStore) list(user, password string, trusted bool) (resp listSessionsResponse) {
+	resp.responsecode = http.StatusOK
+	resp.errorstring = "OK"
+	// TODO: enable this check as soon as the session store handles the rddb itself
+	// if !trusted {
+	// 	if ok, err := self.rddb.CheckPassword(user, password); err != nil {
+	// 		resp.responsecode = http.StatusInternalServerError
+	// 		resp.errorstring = err.Error()
+	// 		return
+	// 	} else if !ok {
+	// 		resp.responsecode = http.StatusUnauthorized
+	// 		resp.errorstring = "invalid username and/or password"
+	// 		return
+	// 	}
+	// }
+	resp.sessions = make(map[string]string)
+	if sessions, exists := self.store[user]; exists {
+		for id, e := range sessions {
+			resp.sessions[id] = e.refId
+		}
+	}
+	return
+}
+
 func (self *SessionStore) remove(user, id string) (resp removeSessionResponse) {
 	resp.responsecode = http.StatusOK
 	resp.errorstring = "OK"
@@ -164,6 +202,8 @@ func (self *SessionStore) dispatchRequests() {
 			req.response <- self.new(req.ctx, req.refId)
 		case req := <-self.getChan:
 			req.response <- self.get(req.user, req.id)
+		case req := <-self.listChan:
+			req.response <- self.list(req.user, req.password, req.trusted)
 		case req := <-self.removeChan:
 			req.response <- self.remove(req.user, req.id)
 		}
@@ -176,6 +216,7 @@ func (self *SessionStore) dispatchRequests() {
 type SessionStoreChan struct {
 	newChan    chan<- newSessionRequest
 	getChan    chan<- getSessionRequest
+	listChan   chan listSessionsRequest
 	removeChan chan<- removeSessionRequest
 }
 
@@ -203,6 +244,19 @@ func (self *SessionStoreChan) Get(user, id string) (*SessionChan, string, int, s
 	return res.session, res.refId, res.responsecode, res.errorstring
 }
 
+func (self *SessionStoreChan) List(user, password string, trusted bool) (map[string]string, int, string) {
+	res_ch := make(chan listSessionsResponse)
+	req := listSessionsRequest{}
+	req.user = user
+	req.password = password
+	req.trusted = trusted
+	req.response = res_ch
+	self.listChan <- req
+
+	res := <-res_ch
+	return res.sessions, res.responsecode, res.errorstring
+}
+
 func (self *SessionStoreChan) Remove(user, id string) (int, string) {
 	res_ch := make(chan removeSessionResponse)
 	req := removeSessionRequest{}
@@ -219,6 +273,7 @@ func (self *SessionStore) GetInterface() *SessionStoreChan {
 	ch := &SessionStoreChan{}
 	ch.newChan = self.newChan
 	ch.getChan = self.getChan
+	ch.listChan = self.listChan
 	ch.removeChan = self.removeChan
 	return ch
 }
@@ -230,6 +285,7 @@ func (self *SessionStore) Cleanup() {
 	close(self.done)
 	close(self.newChan)
 	close(self.getChan)
+	close(self.listChan)
 	close(self.removeChan)
 }
 
@@ -241,6 +297,7 @@ func NewSessionStore(conf *Config) (store *SessionStore, err error) {
 	store.store = make(map[string]map[string]*SessionStoreElement)
 	store.newChan = make(chan newSessionRequest, 10)
 	store.getChan = make(chan getSessionRequest, 10)
+	store.listChan = make(chan listSessionsRequest, 10)
 	store.removeChan = make(chan removeSessionRequest, 10)
 
 	go store.dispatchRequests()
diff --git a/src/helsinki.at/rhimportd/ctrlWebSocket.go b/src/helsinki.at/rhimportd/ctrlWebSocket.go
index ea7bf24..ca1092c 100644
--- a/src/helsinki.at/rhimportd/ctrlWebSocket.go
+++ b/src/helsinki.at/rhimportd/ctrlWebSocket.go
@@ -75,27 +75,74 @@ func newWebSocketRequestData(conf *rhimport.Config) *webSocketRequestData {
 	return rd
 }
 
-type webSocketResponseData struct {
-	ResponseCode     int     `json:"RESPONSE_CODE"`
-	Type             string  `json:"TYPE"`
-	ErrorString      string  `json:"ERROR_STRING"`
-	Id               string  `json:"ID"`
-	RefId            string  `json:"REFERENCE_ID"`
-	ProgressStep     int     `json:"PROGRESS_STEP"`
-	ProgressStepName string  `json:"PROGRESS_STEP_NAME"`
-	Progress         float64 `json:"PROGRESS"`
-	Cart             uint    `json:"CART_NUMBER"`
-	Cut              uint    `json:"CUT_NUMBER"`
+type webSocketResponseBaseData struct {
+	ResponseCode int    `json:"RESPONSE_CODE"`
+	Type         string `json:"TYPE"`
+	ErrorString  string `json:"ERROR_STRING"`
+	Id           string `json:"ID"`
+	RefId        string `json:"REFERENCE_ID"`
 }
 
-func sendWebSocketResponse(ws *websocket.Conn, rd *webSocketResponseData) {
-	if err := ws.WriteJSON(*rd); err != nil {
+type webSocketResponseProgressData struct {
+	webSocketResponseBaseData
+	Step     int     `json:"PROGRESS_STEP"`
+	StepName string  `json:"PROGRESS_STEP_NAME"`
+	Progress float64 `json:"PROGRESS"`
+}
+
+type webSocketResponseDoneData struct {
+	webSocketResponseBaseData
+	Cart uint `json:"CART_NUMBER"`
+	Cut  uint `json:"CUT_NUMBER"`
+}
+
+func sendWebSocketResponse(ws *websocket.Conn, rd interface{}) {
+	if err := ws.WriteJSON(rd); err != nil {
 		rhdl.Println("WebScoket Client", ws.RemoteAddr(), "write error:", err)
 	}
 }
 
-func sendWebSocketErrorResponse(ws *websocket.Conn, id string, code int, err_str string) {
-	sendWebSocketResponse(ws, &webSocketResponseData{ResponseCode: code, Type: "ERROR", ErrorString: err_str, Id: id})
+func sendWebSocketAckResponse(ws *websocket.Conn, code int, err_str, id, refid string) {
+	rd := &webSocketResponseBaseData{}
+	rd.ResponseCode = code
+	rd.Type = "ACK"
+	rd.ErrorString = err_str
+	rd.Id = id
+	rd.RefId = refid
+	sendWebSocketResponse(ws, rd)
+}
+
+func sendWebSocketErrorResponse(ws *websocket.Conn, code int, err_str string) {
+	rd := &webSocketResponseBaseData{}
+	rd.ResponseCode = code
+	rd.Type = "ERROR"
+	rd.ErrorString = err_str
+	sendWebSocketResponse(ws, rd)
+}
+
+func sendWebSocketProgressResponse(ws *websocket.Conn, id, refid string, step int, step_name string, progress float64) {
+	rd := &webSocketResponseProgressData{}
+	rd.ResponseCode = http.StatusOK
+	rd.Type = "PROGRESS"
+	rd.ErrorString = "OK"
+	rd.Id = id
+	rd.RefId = refid
+	rd.Step = step
+	rd.StepName = step_name
+	rd.Progress = progress
+	sendWebSocketResponse(ws, rd)
+}
+
+func sendWebSocketDoneResponse(ws *websocket.Conn, code int, err_str, id, refid string, cart, cut uint) {
+	rd := &webSocketResponseDoneData{}
+	rd.ResponseCode = code
+	rd.Type = "DONE"
+	rd.ErrorString = err_str
+	rd.Id = id
+	rd.RefId = refid
+	rd.Cart = cart
+	rd.Cut = cut
+	sendWebSocketResponse(ws, rd)
 }
 
 type webSocketSession struct {
@@ -195,39 +242,39 @@ func webSocketSessionHandler(reqchan <-chan webSocketRequestData, ws *websocket.
 			switch reqdata.Command {
 			case "new":
 				if session.id != "" {
-					sendWebSocketErrorResponse(ws, "", http.StatusBadRequest, "This connection already handles a session")
+					sendWebSocketErrorResponse(ws, http.StatusBadRequest, "This connection already handles a session")
 				} else {
 					code, errstring := session.startNewSession(&reqdata, conf, rddb, sessions)
 					if code != http.StatusOK {
-						sendWebSocketErrorResponse(ws, "", code, errstring)
+						sendWebSocketErrorResponse(ws, code, errstring)
 					} else {
-						sendWebSocketResponse(ws, &webSocketResponseData{ResponseCode: code, Type: "ACK", Id: session.id, RefId: session.refId})
+						sendWebSocketAckResponse(ws, code, "OK", session.id, session.refId)
 					}
 				}
 			case "cancel":
 				if session.id == "" {
-					sendWebSocketErrorResponse(ws, "", http.StatusBadRequest, "This connection doesn't handle any session")
+					sendWebSocketErrorResponse(ws, http.StatusBadRequest, "This connection doesn't handle any session")
 				} else {
 					session.session.Cancel()
 				}
 			case "reconnect":
 				if session.id != "" {
-					sendWebSocketErrorResponse(ws, "", http.StatusBadRequest, "This connection already handles a session")
+					sendWebSocketErrorResponse(ws, http.StatusBadRequest, "This connection already handles a session")
 				} else {
 					code, errstring := session.reconnectSession(&reqdata, sessions)
 					if code != http.StatusOK {
-						sendWebSocketErrorResponse(ws, "", code, errstring)
+						sendWebSocketErrorResponse(ws, code, errstring)
 					} else {
-						sendWebSocketResponse(ws, &webSocketResponseData{ResponseCode: code, Type: "ACK", Id: session.id, RefId: session.refId})
+						sendWebSocketAckResponse(ws, code, "OK", session.id, session.refId)
 					}
 				}
 			default:
-				sendWebSocketErrorResponse(ws, "", http.StatusBadRequest, fmt.Sprintf("unknown command '%s'", reqdata.Command))
+				sendWebSocketErrorResponse(ws, http.StatusBadRequest, fmt.Sprintf("unknown command '%s'", reqdata.Command))
 			}
 		case p := <-session.progresschan:
-			sendWebSocketResponse(ws, &webSocketResponseData{http.StatusOK, "PROGRESS", "", session.id, session.refId, p.Step, p.StepName, p.Progress * 100, 0, 0})
+			sendWebSocketProgressResponse(ws, session.id, session.refId, p.Step, p.StepName, p.Progress*100)
 		case d := <-session.donechan:
-			sendWebSocketResponse(ws, &webSocketResponseData{d.ResponseCode, "DONE", d.ErrorString, session.id, session.refId, 0, "", 100.0, d.Cart, d.Cut})
+			sendWebSocketDoneResponse(ws, d.ResponseCode, d.ErrorString, session.id, session.refId, d.Cart, d.Cut)
 			// TODO: send close message at this point?
 		}
 	}
-- 
cgit v0.10.2