main.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. package main
  2. import (
  3. "log"
  4. "math/rand"
  5. "net/http"
  6. "strings"
  7. ws "git.alfi.li/gamelang/frontend/webserver"
  8. gamelangpb "git.alfi.li/gamelang/protobuf/gamelang"
  9. um "git.alfi.li/gamelang/systems/usermanager"
  10. wm "git.alfi.li/gamelang/systems/worldmanager"
  11. "github.com/labstack/echo/v4"
  12. gcfg "gopkg.in/gcfg.v1"
  13. )
  14. type ExampleConfig struct {
  15. Http struct {
  16. Listen string // ip:port
  17. }
  18. Kafka struct {
  19. Enabled bool
  20. UserManagerBroker string
  21. WorldManagerBroker string
  22. }
  23. }
  24. func DefaultConfig() ExampleConfig {
  25. config := ExampleConfig{}
  26. config.Http.Listen = "0.0.0.0:8080"
  27. config.Kafka.Enabled = false
  28. return config
  29. }
  30. type exampleWebServer struct {
  31. webserver ws.Webserver
  32. usermanager um.UserManager
  33. worldmanager wm.WorldManager
  34. }
  35. func (ews exampleWebServer) RenderEndpoints() []ws.Endpoint {
  36. endpoints := []ws.Endpoint{}
  37. endpoints = append(endpoints, ws.Endpoint{"GET", "/",
  38. func(ctx echo.Context) error {
  39. log.Print("/: get")
  40. ok, user := ews.webserver.CheckSess(ctx)
  41. if !ok {
  42. log.Print("/: not found")
  43. return ctx.Redirect(301, "/login")
  44. }
  45. data := struct {
  46. Username string
  47. Worlds []gamelangpb.World
  48. Items []string
  49. }{
  50. Username: user.Name,
  51. Worlds: ews.worldmanager.List(),
  52. Items: []string{
  53. "user",
  54. "world",
  55. },
  56. }
  57. log.Printf("/: user \"%v\" found", user.Name)
  58. return ctx.Render(http.StatusOK, "index", data)
  59. }})
  60. endpoints = append(endpoints, ws.Endpoint{"GET", "/user", func(ctx echo.Context) error {
  61. log.Print("/user: get")
  62. log.Print("/user: sending register form")
  63. return ctx.Render(http.StatusOK, "registerform", "")
  64. }})
  65. // POST to /user creates a user
  66. endpoints = append(endpoints, ws.Endpoint{"POST", "/user", func(ctx echo.Context) error {
  67. username := ctx.FormValue("username")
  68. password := ctx.FormValue("password")
  69. log.Printf("new user request: %v", username)
  70. user, err := ews.usermanager.Create(rand.Uint32(), username, password)
  71. if err != nil {
  72. return ctx.String(501, "user creation failed")
  73. }
  74. ews.webserver.NewSession(user, ctx)
  75. log.Printf("new user created: %v", username)
  76. return ctx.Redirect(302, "/")
  77. }})
  78. endpoints = append(endpoints, ws.Endpoint{"GET", "/login", func(ctx echo.Context) error {
  79. log.Print("/login: get")
  80. // check if the login page was called with failed parameter (set by /login POST)
  81. failedBefore := false
  82. if value := ctx.FormValue("failed"); value == "1" {
  83. failedBefore = true
  84. }
  85. ok, user := ews.webserver.CheckSess(ctx)
  86. if ok {
  87. // logged in
  88. log.Printf("/login: user %v logged in", user.Name)
  89. return ctx.String(http.StatusOK, "hello, "+user.Name+"\nyou are logged in.")
  90. }
  91. // not logged in
  92. log.Print("/login: not logged in")
  93. return ctx.Render(http.StatusOK, "loginform", failedBefore)
  94. }})
  95. endpoints = append(endpoints, ws.Endpoint{"POST", "/login", func(ctx echo.Context) error {
  96. username := ctx.FormValue("username")
  97. password := ctx.FormValue("password")
  98. // if the session is already set, the user is already logged in
  99. ok, _ := ews.webserver.CheckSess(ctx)
  100. if ok {
  101. return ctx.String(http.StatusOK, "you are already logged in.")
  102. }
  103. log.Printf("user login attempt: %v", username)
  104. user := gamelangpb.User{}
  105. user, ok = ews.usermanager.Check(username, password)
  106. if ok {
  107. ews.webserver.NewSession(user, ctx)
  108. log.Printf("user login suceeded: %v", username)
  109. return ctx.String(http.StatusOK, "hello, "+username+"\nyou are now logged in.")
  110. }
  111. log.Printf("user login failed: %v", username)
  112. return ctx.Redirect(302, "/login?failed=1")
  113. }})
  114. endpoints = append(endpoints, ws.Endpoint{"GET", "/admin", func(ctx echo.Context) error {
  115. log.Print("/admin: get")
  116. ok, user := ews.webserver.CheckSess(ctx)
  117. if !ok {
  118. log.Print("/admin: not logged in")
  119. return ctx.String(http.StatusUnauthorized, "not logged in")
  120. }
  121. log.Println("/admin:", user.Name)
  122. if user.Admin != true && user.Name != "admin" {
  123. log.Println("/admin: user is not an admin", user.Name)
  124. return ctx.String(http.StatusUnauthorized, "you are not an admin")
  125. }
  126. data := struct {
  127. Users []gamelangpb.User
  128. Sessions map[string]gamelangpb.User
  129. Worlds []gamelangpb.World
  130. }{
  131. Users: ews.usermanager.List(),
  132. Sessions: ews.webserver.ListSess(),
  133. Worlds: ews.worldmanager.List(),
  134. }
  135. err := ctx.Render(http.StatusOK, "admin", data)
  136. if err != nil {
  137. log.Println(err)
  138. }
  139. return err
  140. }})
  141. // worldbuilder
  142. // Get to /World returns register form
  143. endpoints = append(endpoints, ws.Endpoint{"GET", "/world", func(ctx echo.Context) error {
  144. ok, _ := ews.webserver.CheckSess(ctx)
  145. if !ok {
  146. log.Print("/World: not logged in")
  147. return ctx.String(http.StatusUnauthorized, "not logged in")
  148. }
  149. data := struct {
  150. Worlds []gamelangpb.World
  151. }{
  152. Worlds: ews.worldmanager.List(),
  153. }
  154. err := ctx.Render(http.StatusOK, "worldlobby", data)
  155. if err != nil {
  156. log.Print(err)
  157. }
  158. return err
  159. }})
  160. endpoints = append(endpoints, ws.Endpoint{"POST", "/world", func(ctx echo.Context) error {
  161. ok, _ := ews.webserver.CheckSess(ctx)
  162. if !ok {
  163. log.Print("/World: not logged in")
  164. return ctx.String(http.StatusUnauthorized, "not logged in")
  165. }
  166. worldname := ctx.FormValue("worldname")
  167. for _, world := range ews.worldmanager.List() {
  168. if worldname == world.Name {
  169. log.Printf("world \"%s\" already exists", worldname)
  170. return ctx.String(http.StatusAlreadyReported, "world already exists")
  171. }
  172. }
  173. log.Println("/World: creating world", worldname)
  174. _, err := ews.worldmanager.Create(rand.Uint32(), worldname)
  175. if err != nil {
  176. log.Println("error creating world", err)
  177. return ctx.String(http.StatusInternalServerError, "error creating world")
  178. }
  179. return ctx.Redirect(http.StatusFound, "/world")
  180. }})
  181. endpoints = append(endpoints, ws.Endpoint{"POST", "/world/join", func(ctx echo.Context) error {
  182. log.Print("join attemt")
  183. ok, user := ews.webserver.CheckSess(ctx)
  184. if !ok {
  185. log.Print("/World/join: not logged in")
  186. return ctx.String(http.StatusUnauthorized, "not logged in")
  187. }
  188. worldname := ctx.FormValue("worldname")
  189. log.Println("joining", user.Name, "to", worldname)
  190. err := ews.worldmanager.Join(worldname, &user)
  191. if err != nil {
  192. log.Printf("error joining %s to %s", user.Name, worldname)
  193. return ctx.String(501, "join failed")
  194. }
  195. log.Println("join of", user.Name, "to", worldname, "complete")
  196. return ctx.Redirect(302, "/world")
  197. }})
  198. return endpoints
  199. }
  200. func main() {
  201. var config ExampleConfig
  202. err := gcfg.ReadFileInto(&config, "config")
  203. if err != nil {
  204. if strings.Count(err.Error(), "no such file or directory") > 0 {
  205. config = DefaultConfig()
  206. } else {
  207. log.Fatal(err)
  208. }
  209. }
  210. log.Print("config read")
  211. log.Printf("%+v", config)
  212. // init usermanager
  213. brokers := []string{}
  214. if config.Kafka.Enabled {
  215. brokers = strings.Split(config.Kafka.UserManagerBroker, ",")
  216. }
  217. usermanager := um.NewUserManager(brokers)
  218. log.Print("usermanager initialized")
  219. brokers = []string{}
  220. if config.Kafka.Enabled {
  221. brokers = strings.Split(config.Kafka.WorldManagerBroker, ",")
  222. }
  223. worldmanager := wm.NewWorldManager(brokers)
  224. log.Print("worldmanager initialized")
  225. wsConfig := ws.Config{}
  226. listen := strings.Split(config.Http.Listen, ":")
  227. wsConfig.Http.ListenIP = listen[0]
  228. wsConfig.Http.ListenPort = listen[1]
  229. webserver := ws.NewWebserver(wsConfig)
  230. log.Print("webserver initialized")
  231. Ws := exampleWebServer{webserver: *webserver, usermanager: *usermanager, worldmanager: *worldmanager}
  232. Ws.webserver.InitEndpoints(Ws.RenderEndpoints())
  233. Ws.webserver.Run()
  234. }