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) }