144 lines
2.9 KiB
Go
144 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"net/rpc"
|
|
"time"
|
|
)
|
|
|
|
type GrainServer struct {
|
|
Host string
|
|
}
|
|
|
|
type Grain interface {
|
|
HandleMessage(message *Message, reply *CartGrain) error
|
|
}
|
|
|
|
func NewServer(hostname string) *GrainServer {
|
|
return &GrainServer{
|
|
Host: hostname,
|
|
}
|
|
}
|
|
|
|
func (s *GrainServer) Start(port int, instance Grain) (net.Listener, error) {
|
|
rpc.Register(instance)
|
|
rpc.HandleHTTP()
|
|
return net.Listen("tcp", fmt.Sprintf(":%d", port))
|
|
}
|
|
|
|
type CartGrain struct {
|
|
Skus []string
|
|
}
|
|
|
|
type Message struct {
|
|
Type string
|
|
Content string
|
|
}
|
|
|
|
type Registry interface {
|
|
Register(address string, id string) error
|
|
Get(id string) (*string, error)
|
|
}
|
|
|
|
type MemoryRegistry struct {
|
|
registry map[string]string
|
|
}
|
|
|
|
func (r *MemoryRegistry) Register(address string, id string) error {
|
|
r.registry[id] = address
|
|
return nil
|
|
}
|
|
|
|
func (r *MemoryRegistry) Get(id string) (*string, error) {
|
|
addr, ok := r.registry[id]
|
|
if !ok {
|
|
return nil, fmt.Errorf("id not found")
|
|
}
|
|
return &addr, nil
|
|
}
|
|
|
|
func (c *CartGrain) HandleMessage(message *Message, reply *CartGrain) error {
|
|
fmt.Println("CartGrain received message: ", message)
|
|
c.Skus = append(c.Skus, message.Content)
|
|
*reply = *c
|
|
return nil
|
|
}
|
|
|
|
type ServerPool interface {
|
|
GetOrSpawn(id string, ttl time.Time) (*string, error)
|
|
}
|
|
|
|
type WebServer struct {
|
|
ServerPool ServerPool
|
|
}
|
|
|
|
type MemoryServerPool struct {
|
|
port int
|
|
local *GrainServer
|
|
pool map[string]*string
|
|
}
|
|
|
|
func (p *MemoryServerPool) GetOrSpawn(id string, ttl time.Duration) (*string, error) {
|
|
addr, ok := p.pool[id]
|
|
if !ok {
|
|
prt := p.port
|
|
p.port++
|
|
s := NewServer("localhost")
|
|
_, e := s.Start(prt, &CartGrain{})
|
|
if e != nil {
|
|
return nil, e
|
|
}
|
|
//go http.Serve(l, nil)
|
|
a := fmt.Sprintf("localhost:%d", prt)
|
|
p.pool[id] = &a
|
|
addr = &a
|
|
}
|
|
return addr, nil
|
|
}
|
|
|
|
func main() {
|
|
// Create a new instance of the server
|
|
pool := &MemoryServerPool{
|
|
port: 1337,
|
|
pool: make(map[string]*string),
|
|
local: NewServer("localhost"),
|
|
}
|
|
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("GET /{id}", func(w http.ResponseWriter, r *http.Request) {
|
|
id := r.PathValue("id")
|
|
addr, err := pool.GetOrSpawn(id, time.Hour*1)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write([]byte(*addr))
|
|
})
|
|
mux.HandleFunc("GET /add/{id}", func(w http.ResponseWriter, r *http.Request) {
|
|
id := r.PathValue("id")
|
|
addr, err := pool.GetOrSpawn(id, time.Hour*1)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
var cart CartGrain
|
|
client, err := rpc.DialHTTP("tcp", *addr)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
err = client.Call("CartGrain.HandleMessage", &Message{Type: "add", Content: "123"}, &cart)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
w.Write([]byte(fmt.Sprintf("Cart: %v", cart.Skus)))
|
|
})
|
|
http.ListenAndServe(":8080", mux)
|
|
|
|
}
|