Skip to content

Instantly share code, notes, and snippets.

@NanXiao
Created August 11, 2016 10:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NanXiao/e5ce9fc2b4a632de03041d4b05b61a83 to your computer and use it in GitHub Desktop.
Save NanXiao/e5ce9fc2b4a632de03041d4b05b61a83 to your computer and use it in GitHub Desktop.
server.go
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