This commit is contained in:
matst80
2024-11-07 22:57:18 +01:00
parent 0f23ae0e9a
commit ae421674d2
9 changed files with 542 additions and 112 deletions

190
main.go
View File

@@ -1,143 +1,111 @@
package main
import (
"fmt"
"net"
"encoding/gob"
"encoding/json"
"log"
"net/http"
"net/rpc"
"os"
"time"
)
type GrainServer struct {
Host string
}
func spawn(id string) Grain {
type Grain interface {
HandleMessage(message *Message, reply *CartGrain) error
}
func NewServer(hostname string) *GrainServer {
return &GrainServer{
Host: hostname,
ret := &CartGrain{
Id: id,
Items: []CartItem{},
storageMessages: []Message{},
TotalPrice: 0,
}
}
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")
err := loadMessages(ret, id)
if err != nil {
log.Printf("Error loading messages for grain %s: %v\n", id, err)
}
return &addr, nil
return ret
}
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
func init() {
os.Mkdir("data", 0755)
gob.Register(CartItem{})
gob.Register(Message{})
}
type ServerPool interface {
GetOrSpawn(id string, ttl time.Time) (*string, error)
type App struct {
pool *GrainLocalPool
storage *DiskStorage
}
type WebServer struct {
ServerPool ServerPool
func (a *App) HandleGet(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
grain, err := a.pool.GetOrSpawn(id, spawn)
if err != nil {
w.WriteHeader(http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(grain)
}
type MemoryServerPool struct {
port int
local *GrainServer
pool map[string]*string
func (a *App) HandleAddSku(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
sku := r.PathValue("sku")
grain, err := a.pool.GetOrSpawn(id, spawn)
if err != nil {
w.WriteHeader(http.StatusNotFound)
return
}
message := &Message{
Type: "add",
Content: sku,
}
var reply CartGrain
err = grain.HandleMessage(message, false, &reply)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(reply)
}
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
func (a *App) Save() error {
for id, grain := range a.pool.GetGrains() {
err := a.storage.Store(id, grain)
if err != nil {
log.Printf("Error saving grain %s: %v\n", id, err)
}
//go http.Serve(l, nil)
a := fmt.Sprintf("localhost:%d", prt)
p.pool[id] = &a
addr = &a
}
return addr, nil
return a.storage.saveState()
}
func (a *App) HandleSave(w http.ResponseWriter, r *http.Request) {
err := a.Save()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
} else {
w.WriteHeader(http.StatusCreated)
}
}
func main() {
// Create a new instance of the server
pool := &MemoryServerPool{
port: 1337,
pool: make(map[string]*string),
local: NewServer("localhost"),
storage, err := NewDiskStorage("data/state.json")
if err != nil {
log.Printf("Error loading state: %v\n", err)
}
app := &App{
pool: NewGrainLocalPool(1000, 5*time.Minute),
storage: storage,
}
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)))
})
mux.HandleFunc("GET /{id}", app.HandleGet)
mux.HandleFunc("GET /{id}/add/{sku}", app.HandleAddSku)
mux.HandleFunc("GET /save", app.HandleSave)
http.ListenAndServe(":8080", mux)
}