Skip to content

Instantly share code, notes, and snippets.

@zapkub
Created November 19, 2019 14:56
Show Gist options
  • Save zapkub/91fcac67992868a8ef3543cecb3a4c22 to your computer and use it in GitHub Desktop.
Save zapkub/91fcac67992868a8ef3543cecb3a4c22 to your computer and use it in GitHub Desktop.
package main
import (
"context"
"encoding/json"
"fmt"
"math/rand"
"net/http"
"strconv"
"time"
)
func HandleOperation(ctx context.Context, duplex *TransactionalDuplex) {
defer fmt.Println("end operation")
for {
select {
case operation := <-duplex.input:
// do the operation
switch o := operation.(type) {
case *OperationInputSubmit:
duplex.result <- &OperationResultSubmit{Message: "submit done" + o.Data}
case *OperationInputCommit:
// do commit and invalidate this func
fmt.Println("Commit")
return
case *OperationInputRollback:
// do rollback and invalidate this func
fmt.Println("Rollback")
return
default:
fmt.Println("operation handler created")
}
case <-ctx.Done():
return
}
}
}
type OperationInput interface{}
type OperationInputSubmit struct {
OperationInput
Data string
}
type OperationInputCommit struct {
OperationInput
}
type OperationInputRollback struct {
OperationInput
}
type OperationResult interface{}
type OperationResultSubmit struct {
Message string
}
type TransactionalDuplex struct {
input chan OperationInput
result chan OperationResult
}
func NewTransactionalDuplex() *TransactionalDuplex {
return &TransactionalDuplex{
input: make(chan OperationInput),
result: make(chan OperationResult),
}
}
type transactionCache map[string]*TransactionalDuplex
type TransactionalHandler struct {
session transactionCache
}
func (t TransactionalHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
switch req.URL.Path {
case "/tx":
// generate random transaction ID
tx := randomTx()
duplex := NewTransactionalDuplex()
t.session[tx] = duplex
// routine out this function
go func() {
// this routine gonna end after this function exit
ctx, _ := context.WithTimeout(context.Background(), time.Second*60)
HandleOperation(ctx, t.session[tx])
}()
w.WriteHeader(201)
_, _ = w.Write([]byte("transaction created! " + tx))
case "/tx/submit":
id := req.URL.Query().Get("id")
if id == "" {
w.WriteHeader(400)
_, _ = w.Write([]byte("invalid id"))
return
}
duplex := t.session[id]
duplex.input <- &OperationInputSubmit{Data: "random submit data"}
result := <-duplex.result
b, _ := json.Marshal(result)
_, _ = w.Write(b)
case "/tx/commit":
id := req.URL.Query().Get("id")
if id == "" {
w.WriteHeader(400)
_, _ = w.Write([]byte("invalid id"))
return
}
duplex := t.session[id]
duplex.input <- &OperationInputCommit{}
delete(t.session, id)
}
}
func main() {
err := http.ListenAndServe(":9901", &TransactionalHandler{
session: make(transactionCache),
})
if err != nil {
panic(err)
}
}
func randomTx() string {
return strconv.Itoa(rand.Int())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment