Created
August 11, 2016 10:42
-
-
Save NanXiao/e5ce9fc2b4a632de03041d4b05b61a83 to your computer and use it in GitHub Desktop.
server.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"log" | |
"net/http" | |
"github.com/gorilla/mux" | |
"encoding/json" | |
"strconv" | |
"sync" | |
) | |
const ( | |
statusOK = "ok" | |
statusNoSpecifiedID = "Can't find the specified transaction ID" | |
statusTransactionEncodingError = "Transaction encoidng is error" | |
statusNoSpecifiedType = "Can't find the specified type" | |
) | |
type transactionID uint64 | |
type Transaction struct { | |
Amount float64 `json:"amount"` | |
TransType string `json:"type"` | |
ParentID transactionID `json:"parent_id,omitempty"` | |
} | |
type TransactionSum struct { | |
Sum float64 `json:"sum"` | |
} | |
type TransactionStatus struct { | |
Status string `json:"status"` | |
} | |
var transactionTable map[transactionID]*Transaction | |
var typeTable map[string][]transactionID | |
var sumTable map[transactionID]*TransactionSum | |
var transactionTableLock sync.RWMutex | |
var typeTableLock sync.RWMutex | |
var sumTableLock sync.RWMutex | |
type routeMethod struct { | |
method string | |
pattern string | |
handlerFunc http.HandlerFunc | |
} | |
var routeMethods = []routeMethod { | |
{method: "PUT", pattern: "/transaction/{transaction_id}", handlerFunc: putTransactionHandler}, | |
{method: "GET", pattern: "/transaction/{transaction_id}", handlerFunc: getTransactionHandler}, | |
{method: "GET", pattern: "/types/{type}", handlerFunc: getTypeHandler}, | |
{method: "GET", pattern: "/sum/{transaction_id}", handlerFunc: getSumHandler}, | |
} | |
func convertTransactionID(s string) (transactionID, error) { | |
v, err := strconv.ParseUint(s, 10, 64) | |
return transactionID(v), err | |
} | |
func sendStatus(w http.ResponseWriter, status string) { | |
if err := json.NewEncoder(w).Encode(TransactionStatus{Status:status}); err != nil { | |
http.Error(w, err.Error(), http.StatusInternalServerError) | |
return | |
} | |
} | |
func putTransactionHandler(w http.ResponseWriter, r *http.Request) { | |
var trans Transaction | |
id, err := convertTransactionID(mux.Vars(r)["transaction_id"]) | |
if err != nil { | |
sendStatus(w, statusNoSpecifiedID) | |
return | |
} | |
if err = json.NewDecoder(r.Body).Decode(&trans); err != nil { | |
sendStatus(w, statusTransactionEncodingError) | |
return | |
} | |
transactionTableLock.Lock() | |
transactionTable[id] = &trans | |
transactionTableLock.Unlock() | |
typeTableLock.Lock() | |
typeTable[trans.TransType] = append(typeTable[trans.TransType], id) | |
typeTableLock.Unlock() | |
sumTableLock.Lock() | |
if trans.ParentID != 0 { | |
if _, ok := sumTable[trans.ParentID]; ok { | |
sumTable[trans.ParentID].Sum += trans.Amount | |
} else { | |
sumTable[trans.ParentID] = &TransactionSum{Sum:trans.Amount} | |
} | |
} else { | |
sumTable[id] = &TransactionSum{Sum:trans.Amount} | |
} | |
sumTableLock.Unlock() | |
sendStatus(w, statusOK) | |
} | |
func getTransactionHandler(w http.ResponseWriter, r *http.Request) { | |
id, err := convertTransactionID(mux.Vars(r)["transaction_id"]) | |
if err != nil { | |
sendStatus(w, statusNoSpecifiedID) | |
return | |
} | |
transactionTableLock.RLock() | |
defer transactionTableLock.RUnlock() | |
trans, ok := transactionTable[id] | |
if !ok { | |
sendStatus(w, statusNoSpecifiedID) | |
return | |
} else { | |
err = json.NewEncoder(w).Encode(trans) | |
if err != nil { | |
http.Error(w, err.Error(), http.StatusInternalServerError) | |
return | |
} | |
} | |
} | |
func getTypeHandler(w http.ResponseWriter, r *http.Request) { | |
typeTableLock.RLock() | |
defer typeTableLock.RUnlock() | |
transIDs, ok := typeTable[mux.Vars(r)["type"]] | |
if !ok { | |
sendStatus(w, statusNoSpecifiedType) | |
return | |
} else { | |
if err := json.NewEncoder(w).Encode(transIDs); err != nil { | |
http.Error(w, err.Error(), http.StatusInternalServerError) | |
return | |
} | |
} | |
} | |
func getSumHandler(w http.ResponseWriter, r *http.Request) { | |
id, err := convertTransactionID(mux.Vars(r)["transaction_id"]) | |
if err != nil { | |
sendStatus(w, statusNoSpecifiedID) | |
return | |
} | |
sumTableLock.RLock() | |
tranSum, ok := sumTable[id] | |
if ok { | |
err = json.NewEncoder(w).Encode(tranSum) | |
if err != nil { | |
http.Error(w, err.Error(), http.StatusInternalServerError) | |
} | |
sumTableLock.RUnlock() | |
return | |
} | |
sumTableLock.RUnlock() | |
transactionTableLock.RLock() | |
trans, ok := transactionTable[id] | |
if ok{ | |
err = json.NewEncoder(w).Encode(TransactionSum{Sum:trans.Amount}) | |
if err != nil { | |
http.Error(w, err.Error(), http.StatusInternalServerError) | |
} | |
transactionTableLock.RUnlock() | |
return | |
} | |
transactionTableLock.RUnlock() | |
sendStatus(w, statusNoSpecifiedID) | |
} | |
func main() { | |
transactionTable = make(map[transactionID]*Transaction) | |
typeTable = make(map[string][]transactionID) | |
sumTable = make(map[transactionID]*TransactionSum) | |
router := mux.NewRouter().PathPrefix("/transactionservice").Subrouter().StrictSlash(true) | |
for _, v := range routeMethods { | |
router.Methods(v.method).Path(v.pattern).HandlerFunc(v.handlerFunc) | |
} | |
log.Fatal(http.ListenAndServe("localhost:8080", router)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment