commit 0f23ae0e9a2fbf4a6cab9702b92f56102ba82c92 Author: matst80 Date: Wed Nov 6 12:54:46 2024 +0100 first diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ec17698 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.tornberg.me/go-cart-actor + +go 1.22.4 diff --git a/main.go b/main.go new file mode 100644 index 0000000..3c908f7 --- /dev/null +++ b/main.go @@ -0,0 +1,143 @@ +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) + +}