Based on https://github.com/nnevatie/capnwebcpp
at main 186 lines 4.7 kB view raw
1package main 2 3import ( 4 "encoding/json" 5 "fmt" 6 "log" 7 "os" 8 9 "github.com/gocapnweb" 10) 11 12// User represents a user object. 13type User struct { 14 ID string `json:"id"` 15 Name string `json:"name"` 16} 17 18// Profile represents a user profile. 19type Profile struct { 20 ID string `json:"id"` 21 Bio string `json:"bio"` 22} 23 24// UserServer implements RPC methods for user operations with pipelining support. 25type UserServer struct { 26 *gocapnweb.BaseRpcTarget 27 users map[string]User // session token -> user 28 profiles map[string]Profile // user ID -> profile 29 notifications map[string][]string // user ID -> notifications 30} 31 32// NewUserServer creates a new UserServer instance with sample data. 33func NewUserServer() *UserServer { 34 server := &UserServer{ 35 BaseRpcTarget: gocapnweb.NewBaseRpcTarget(), 36 users: make(map[string]User), 37 profiles: make(map[string]Profile), 38 notifications: make(map[string][]string), 39 } 40 41 // Initialize sample data 42 server.initializeData() 43 44 // Register RPC methods 45 server.Method("authenticate", server.authenticate) 46 server.Method("getUserProfile", server.getUserProfile) 47 server.Method("getNotifications", server.getNotifications) 48 49 return server 50} 51 52func (s *UserServer) initializeData() { 53 // Initialize users (session token -> user object) 54 s.users["cookie-123"] = User{ 55 ID: "u_1", 56 Name: "Ada Lovelace", 57 } 58 s.users["cookie-456"] = User{ 59 ID: "u_2", 60 Name: "Alan Turing", 61 } 62 63 // Initialize profiles (user ID -> profile object) 64 s.profiles["u_1"] = Profile{ 65 ID: "u_1", 66 Bio: "Mathematician & first programmer", 67 } 68 s.profiles["u_2"] = Profile{ 69 ID: "u_2", 70 Bio: "Mathematician & computer science pioneer", 71 } 72 73 // Initialize notifications (user ID -> array of notifications) 74 s.notifications["u_1"] = []string{ 75 "Welcome to jsrpc!", 76 "You have 2 new followers", 77 } 78 s.notifications["u_2"] = []string{ 79 "New feature: pipelining!", 80 "Security tips for your account", 81 } 82} 83 84func (s *UserServer) authenticate(args json.RawMessage) (interface{}, error) { 85 // Extract session token from arguments 86 var sessionToken string 87 88 // Try to parse as array first 89 var argArray []string 90 if err := json.Unmarshal(args, &argArray); err == nil && len(argArray) > 0 { 91 sessionToken = argArray[0] 92 } else { 93 // Try to parse as string 94 if err := json.Unmarshal(args, &sessionToken); err != nil { 95 return nil, err 96 } 97 } 98 99 // Look up user by session token 100 user, exists := s.users[sessionToken] 101 if !exists { 102 return nil, fmt.Errorf("invalid session") 103 } 104 105 return user, nil 106} 107 108func (s *UserServer) getUserProfile(args json.RawMessage) (interface{}, error) { 109 // Extract user ID from arguments 110 var userID string 111 112 // Try to parse as array first 113 var argArray []string 114 if err := json.Unmarshal(args, &argArray); err == nil && len(argArray) > 0 { 115 userID = argArray[0] 116 } else { 117 // Try to parse as string 118 if err := json.Unmarshal(args, &userID); err != nil { 119 return nil, err 120 } 121 } 122 123 // Look up profile by user ID 124 profile, exists := s.profiles[userID] 125 if !exists { 126 return nil, fmt.Errorf("no such user") 127 } 128 129 return profile, nil 130} 131 132func (s *UserServer) getNotifications(args json.RawMessage) (interface{}, error) { 133 // Extract user ID from arguments 134 var userID string 135 136 // Try to parse as array first 137 var argArray []string 138 if err := json.Unmarshal(args, &argArray); err == nil && len(argArray) > 0 { 139 userID = argArray[0] 140 } else { 141 // Try to parse as string 142 if err := json.Unmarshal(args, &userID); err != nil { 143 return nil, err 144 } 145 } 146 147 // Look up notifications by user ID 148 notifications, exists := s.notifications[userID] 149 if !exists { 150 return []string{}, nil // Return empty array if no notifications 151 } 152 153 return notifications, nil 154} 155 156func main() { 157 // Default to serving static files from the examples/static directory 158 staticPath := "/static" 159 if len(os.Args) >= 2 { 160 staticPath = os.Args[1] 161 } 162 163 port := ":8000" 164 165 // Create Echo server with middleware 166 e := gocapnweb.SetupEchoServer() 167 168 // Setup RPC endpoint 169 server := NewUserServer() 170 gocapnweb.SetupRpcEndpoint(e, "/rpc", server) 171 172 // Setup static file endpoint 173 gocapnweb.SetupFileEndpoint(e, "/static", staticPath) 174 175 log.Printf("🚀 Batch Pipelining Go Server (Echo) starting on port %s", port) 176 log.Printf("🔌 HTTP Batch RPC endpoint: http://localhost%s/rpc", port) 177 log.Printf("🌐 Demo URL: http://localhost:3000 (available once you start the Svelte development server)") 178 log.Println() 179 log.Println("Sample data:") 180 log.Println(" Session tokens: cookie-123, cookie-456") 181 log.Println(" Users: u_1 (Ada Lovelace), u_2 (Alan Turing)") 182 183 if err := e.Start(port); err != nil { 184 log.Fatal("Failed to start server:", err) 185 } 186}