main.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. package main
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "html/template"
  7. "io"
  8. "log"
  9. "math/rand"
  10. "net/http"
  11. "strings"
  12. glws "git.alfi.li/gamelang/frontend/webserver"
  13. glwss "git.alfi.li/gamelang/frontend/wsserver"
  14. bingoman "git.alfi.li/gamelang/games/bingo/bingoManager"
  15. gamelangpb "git.alfi.li/gamelang/protobuf/gamelang"
  16. glbingopb "git.alfi.li/gamelang/protobuf/gamelang-bingo"
  17. userman "git.alfi.li/gamelang/systems/usermanager"
  18. worldman "git.alfi.li/gamelang/systems/worldmanager"
  19. "github.com/labstack/echo/v4"
  20. "gopkg.in/gcfg.v1"
  21. )
  22. // Template wraps go's html template
  23. type Template struct {
  24. templates *template.Template
  25. }
  26. // Render renders a Template
  27. func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
  28. return t.templates.ExecuteTemplate(w, name, data)
  29. }
  30. func initTemplates(e *echo.Echo) {
  31. t := &Template{
  32. templates: template.Must(template.ParseGlob("public/*.html")),
  33. }
  34. e.Renderer = t
  35. }
  36. type BingoConfig struct {
  37. Http struct {
  38. ListenIP string
  39. ListenPort string
  40. }
  41. WS struct {
  42. ListenIP string
  43. ListenPort string
  44. }
  45. Manager struct {
  46. UserManager string
  47. WorldManager string
  48. BingoManager string
  49. }
  50. }
  51. func getDefaultConfig() BingoConfig {
  52. bc := BingoConfig{}
  53. bc.Http.ListenIP = "127.0.0.1"
  54. bc.Http.ListenPort = "8080"
  55. bc.WS.ListenIP = "127.0.0.1"
  56. bc.WS.ListenPort = "8081"
  57. bc.Manager.UserManager = "localhost:9090"
  58. bc.Manager.WorldManager = "localhost:9091"
  59. bc.Manager.BingoManager = "localhost:9092"
  60. return bc
  61. }
  62. type BingoGame struct {
  63. um *userman.UserManager //gamelangpb.UserServiceClient
  64. wm *worldman.WorldManager //gamelangpb.WorldServiceClient
  65. bingomanager *bingoman.BingoManager
  66. webserver *glws.Webserver
  67. wssserver *glwss.WSServer
  68. notichan chan glbingopb.Event
  69. config BingoConfig
  70. }
  71. func (bg *BingoGame) Init(config BingoConfig) {
  72. //init userclient
  73. //userconn, err := grpc.Dial(config.Manager.UserManager, grpc.WithInsecure())
  74. //if err != nil {
  75. // panic(err.Error())
  76. //}
  77. //defer userconn.Close()
  78. bg.um = userman.NewUserManager([]string{}) //gamelangpb.NewUserServiceClient(userconn)
  79. //init wm
  80. //worldconn, err := grpc.Dial(config.Manager.WorldManager, grpc.WithInsecure())
  81. //if err != nil {
  82. // panic(err.Error())
  83. //}
  84. //defer worldconn.Close()
  85. bg.wm = worldman.NewWorldManager([]string{}) //gamelangpb.NewWorldServiceClient(worldconn)
  86. bg.notichan = make(chan glbingopb.Event)
  87. bg.bingomanager = bingoman.NewBingoManager([]string{}, bg.notichan)
  88. go bg.workNotifications()
  89. //init webserver
  90. wsConfig := glws.Config{}
  91. wsConfig.Http.ListenIP = config.Http.ListenIP
  92. wsConfig.Http.ListenPort = config.Http.ListenPort
  93. bg.webserver = glws.NewWebserver(wsConfig)
  94. }
  95. func (bg *BingoGame) workNotifications() {
  96. for {
  97. log.Print("waiting for notification")
  98. event := <-bg.notichan
  99. log.Println("new notification", event)
  100. eventJson, err := json.Marshal(event)
  101. if err != nil {
  102. log.Printf("workNotifications - err marshalling event \"%s\"\n%s", event, err.Error())
  103. }
  104. notify := glwss.WSMsg{Mtype: "game:event", Payload: string(eventJson)}
  105. worldgamename := strings.Split(event.Gamename, "\uffff")
  106. worldname := worldgamename[0]
  107. gamename := worldgamename[1]
  108. // if the game is a common game or its a win event all players have to be notified
  109. if gamename == "common" || event.Type == "Win" {
  110. world := gamelangpb.World{}
  111. worlds := bg.wm.List()
  112. for _, world := range worlds {
  113. if world.GetName() == worldname {
  114. log.Println("sending world\n", world)
  115. break
  116. }
  117. }
  118. //world, err := bg.wm.GetWorld(context.Background(), &gamelangpb.World{Name: worldname})
  119. if err != nil {
  120. log.Printf("workNotifications - err getting world msg \"%s\"\n%s", worldname, err.Error())
  121. return
  122. }
  123. for _, user := range world.Users {
  124. go bg.wssserver.Write(user.Name, notify)
  125. }
  126. } else {
  127. bg.wssserver.Write(event.Username, notify)
  128. }
  129. }
  130. }
  131. // RenderEndpoints returns the endpoints that are served by the webserver
  132. func (bg *BingoGame) RenderEndpoints() []glws.Endpoint {
  133. endpoints := []glws.Endpoint{}
  134. endpoints = append(endpoints, glws.Endpoint{"GET", "/",
  135. func(ctx echo.Context) error {
  136. log.Print("/: get")
  137. ok, user := bg.webserver.CheckSess(ctx)
  138. if !ok {
  139. log.Print("/: not found")
  140. return ctx.Redirect(301, "/login")
  141. }
  142. data := struct {
  143. Username string
  144. Worlds []gamelangpb.World
  145. Items []string
  146. }{
  147. Username: user.Name,
  148. Worlds: func() []gamelangpb.World {
  149. worlds := bg.wm.List()
  150. return worlds
  151. }(),
  152. Items: []string{
  153. "user",
  154. "world",
  155. },
  156. }
  157. log.Printf("/: user \"%v\" found", user.Name)
  158. return ctx.Render(http.StatusOK, "index", data)
  159. }})
  160. endpoints = append(endpoints, glws.Endpoint{"GET", "/user", func(ctx echo.Context) error {
  161. log.Print("/user: get")
  162. log.Print("/user: sending register form")
  163. return ctx.Render(http.StatusOK, "registerform", "")
  164. }})
  165. // POST to /user creates a user
  166. endpoints = append(endpoints, glws.Endpoint{"POST", "/user", func(ctx echo.Context) error {
  167. username := ctx.FormValue("username")
  168. password := ctx.FormValue("password")
  169. log.Printf("new user request: %v", username)
  170. newUser := gamelangpb.User{Name: username, Password: []byte(password)}
  171. id := rand.Uint32()
  172. name := newUser.GetName()
  173. _, err := bg.um.Create(id, name, password)
  174. //user, err := bg.userclient.CreateUser(context.Background(), &newUser)
  175. if err != nil {
  176. return ctx.String(501, "user creation failed")
  177. }
  178. bg.webserver.NewSession(newUser, ctx)
  179. log.Printf("new user created: %v", username)
  180. return ctx.Redirect(302, "/")
  181. }})
  182. endpoints = append(endpoints, glws.Endpoint{"GET", "/login", func(ctx echo.Context) error {
  183. log.Print("/login: get")
  184. // check if the login page was called with failed parameter (set by /login POST)
  185. failedBefore := false
  186. if value := ctx.FormValue("failed"); value == "1" {
  187. failedBefore = true
  188. }
  189. ok, user := bg.webserver.CheckSess(ctx)
  190. if ok {
  191. // logged in
  192. log.Printf("/login: user %v logged in", user.Name)
  193. return ctx.String(http.StatusOK, "hello, "+user.Name+"\nyou are logged in.")
  194. }
  195. // not logged in
  196. log.Print("/login: not logged in")
  197. return ctx.Render(http.StatusOK, "loginform", failedBefore)
  198. }})
  199. endpoints = append(endpoints, glws.Endpoint{"POST", "/login", func(ctx echo.Context) error {
  200. log.Print("/login: post")
  201. username := ctx.FormValue("username")
  202. password := ctx.FormValue("password")
  203. // if the session is already set, the user is already logged in
  204. ok, _ := bg.webserver.CheckSess(ctx)
  205. if ok {
  206. return ctx.String(http.StatusOK, "you are already logged in.")
  207. }
  208. log.Printf("user login attempt: %v", username)
  209. //checkuser := gamelangpb.User{Name: username, Password: []byte(password)}
  210. user, ok := bg.um.Check(username, password) //bg.userclient.CheckUser(context.Background(), &checkuser)
  211. if ok { //err == nil {
  212. bg.webserver.NewSession(user, ctx)
  213. log.Printf("user login suceeded: %v", username)
  214. return ctx.String(http.StatusOK, "hello, "+username+"\nyou are now logged in.")
  215. }
  216. log.Printf("user login failed: %v\n%s", username)
  217. return ctx.Redirect(302, "/login?failed=1")
  218. }})
  219. endpoints = append(endpoints, glws.Endpoint{"GET", "/admin", func(ctx echo.Context) error {
  220. log.Print("/admin: get")
  221. ok, user := bg.webserver.CheckSess(ctx)
  222. if !ok {
  223. log.Print("/admin: not logged in")
  224. return ctx.String(http.StatusUnauthorized, "not logged in")
  225. }
  226. log.Println("/admin:", user.Name)
  227. if user.Admin != true && user.Name != "admin" {
  228. log.Println("/admin: user is not an admin", user.Name)
  229. return ctx.String(http.StatusUnauthorized, "you are not an admin")
  230. }
  231. data := struct {
  232. Users []gamelangpb.User
  233. Sessions map[string]gamelangpb.User
  234. Worlds []gamelangpb.World
  235. }{
  236. Users: func() []gamelangpb.User {
  237. users := bg.um.List()
  238. return users
  239. }(),
  240. Sessions: bg.webserver.ListSess(),
  241. Worlds: func() []gamelangpb.World {
  242. worlds := bg.wm.List()
  243. return worlds
  244. }(),
  245. }
  246. err := ctx.Render(http.StatusOK, "admin", data)
  247. if err != nil {
  248. log.Println(err)
  249. }
  250. return err
  251. }})
  252. // worldbuilder
  253. // Get to /World returns register form
  254. endpoints = append(endpoints, glws.Endpoint{"GET", "/world", func(ctx echo.Context) error {
  255. ok, _ := bg.webserver.CheckSess(ctx)
  256. if !ok {
  257. log.Print("/World: not logged in")
  258. return ctx.String(http.StatusUnauthorized, "not logged in")
  259. }
  260. data := struct {
  261. Worlds []gamelangpb.World
  262. }{
  263. Worlds: func() []gamelangpb.World {
  264. worlds := bg.wm.List()
  265. return worlds
  266. }(),
  267. }
  268. err := ctx.Render(http.StatusOK, "worldlobby", data)
  269. if err != nil {
  270. log.Print(err)
  271. }
  272. return err
  273. }})
  274. endpoints = append(endpoints, glws.Endpoint{"POST", "/world", func(ctx echo.Context) error {
  275. ok, _ := bg.webserver.CheckSess(ctx)
  276. if !ok {
  277. log.Print("/World: not logged in")
  278. return ctx.String(http.StatusUnauthorized, "not logged in")
  279. }
  280. worldname := ctx.FormValue("worldname")
  281. world := &gamelangpb.World{Name: worldname}
  282. lobbygame := CraftLobbygame(fmt.Sprintf("%s\uffff%s", world.GetName(), "lobby"))
  283. world.Games = []string{lobbygame.Name}
  284. log.Println("/World: creating world_\n", world)
  285. id := rand.Uint32()
  286. world.Id = id
  287. _, err := bg.wm.Create(*world)
  288. if err != nil {
  289. log.Println("error creating world", err)
  290. return ctx.String(http.StatusInternalServerError, "error creating world")
  291. }
  292. err = bg.bingomanager.Create(lobbygame)
  293. if err != nil {
  294. log.Println("error creating world", err)
  295. return ctx.String(http.StatusInternalServerError, "error creating world")
  296. }
  297. return ctx.Redirect(http.StatusFound, "/world")
  298. }})
  299. endpoints = append(endpoints, glws.Endpoint{"POST", "/world/join", func(ctx echo.Context) error {
  300. log.Print("join attemt")
  301. ok, user := bg.webserver.CheckSess(ctx)
  302. if !ok {
  303. log.Print("/World/join: not logged in")
  304. return ctx.String(http.StatusUnauthorized, "not logged in")
  305. }
  306. worldname := ctx.FormValue("worldname")
  307. log.Println("joining", user.Name, "to", worldname)
  308. joinworld := gamelangpb.World{Name: worldname, Users: []*gamelangpb.User{}}
  309. joinworld.Users = append(joinworld.Users, &user)
  310. err := bg.wm.Join(worldname, &user)
  311. if err != nil {
  312. log.Printf("error joining %s to %s\n%s", user.Name, worldname, err.Error())
  313. return ctx.String(501, "join failed")
  314. }
  315. log.Println("join of", user.Name, "to", worldname, "complete")
  316. return ctx.Redirect(302, "/world")
  317. }})
  318. return endpoints
  319. }
  320. //RenderHandler renders the endpoints that will be served via websocket
  321. func (bg *BingoGame) RenderHandler() []glwss.Handler {
  322. handler := []glwss.Handler{}
  323. handler = append(handler, glwss.Handler{MType: "echo", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  324. log.Printf("echo from \"%v\" with \"%s\"", user, msg.Payload)
  325. remsg := glwss.WSMsg{Mtype: "echo", Payload: msg.Payload}
  326. return remsg, nil
  327. }})
  328. handler = append(handler, glwss.Handler{MType: "world:create", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  329. createWorld := gamelangpb.World{Name: msg.Payload}
  330. lobbygame := CraftLobbygame(fmt.Sprintf("%s\uffff%s", createWorld.GetName(), "lobby"))
  331. createWorld.Games = []string{lobbygame.Name}
  332. id := rand.Uint32()
  333. createWorld.Id = id
  334. _, err := bg.wm.Create(*&createWorld)
  335. if err != nil {
  336. remsg := glwss.WSMsg{Mtype: "world:create", Payload: "failed"}
  337. return remsg, err
  338. }
  339. err = bg.bingomanager.Create(lobbygame)
  340. if err != nil {
  341. remsg := glwss.WSMsg{Mtype: "world:create", Payload: "failed"}
  342. return remsg, err
  343. }
  344. log.Println("world:create created Lobbygame:\n", lobbygame)
  345. createworldJSON, _ := json.Marshal(createWorld)
  346. remsg := glwss.WSMsg{Mtype: "world:create", Payload: string(createworldJSON)}
  347. return remsg, nil
  348. }})
  349. handler = append(handler, glwss.Handler{MType: "world:remove", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  350. err := bg.wm.Remove(msg.Payload)
  351. if err != nil {
  352. remsg := glwss.WSMsg{Mtype: "world:remove", Payload: "failed"}
  353. return remsg, err
  354. }
  355. remsg := glwss.WSMsg{Mtype: "world:remove", Payload: "success"}
  356. return remsg, nil
  357. }})
  358. handler = append(handler, glwss.Handler{MType: "world:join", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  359. worldname := msg.Payload
  360. err := bg.wm.Join(worldname, &user)
  361. if err != nil {
  362. remsg := glwss.WSMsg{Mtype: "world:join", Payload: "failed"}
  363. return remsg, err
  364. }
  365. remsg := glwss.WSMsg{Mtype: "world:join", Payload: "success"}
  366. return remsg, nil
  367. }})
  368. handler = append(handler, glwss.Handler{MType: "world:list", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  369. log.Print("world:list")
  370. worldlist := bg.wm.List()
  371. worldlistJSON, err := json.Marshal(worldlist)
  372. if err != nil {
  373. log.Print(err.Error())
  374. msg := glwss.WSMsg{Mtype: "world:list", Payload: "failed"}
  375. return msg, err
  376. }
  377. log.Print("world:list", "sending list")
  378. remsg := glwss.WSMsg{Mtype: "world:list", Payload: string(worldlistJSON)}
  379. return remsg, nil
  380. }})
  381. handler = append(handler, glwss.Handler{MType: "game:get", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  382. log.Println("game:get new get request:\n\"", msg.Payload, "\"")
  383. var world gamelangpb.World
  384. worldname := msg.Payload
  385. worlds := bg.wm.List()
  386. for _, world = range worlds {
  387. if world.GetName() == worldname {
  388. log.Println("sending world\n", world)
  389. break
  390. }
  391. }
  392. log.Println("game:get got world:\n\"", world, "\"")
  393. lobbygame := glbingopb.Bingo{}
  394. commongame := glbingopb.Bingo{}
  395. usergame := glbingopb.Bingo{}
  396. for _, game := range world.GetGames() {
  397. log.Println("searching games", game)
  398. if game == fmt.Sprintf("%s\uffff%s", world.GetName(), "lobby") {
  399. log.Println("found lobbygame", game)
  400. searchGame := glbingopb.Bingo{Name: game}
  401. lobbygame = bg.bingomanager.Get(searchGame)
  402. }
  403. if game == fmt.Sprintf("%s\uffff%s", world.GetName(), "common") {
  404. log.Println("found commongame", game)
  405. searchGame := glbingopb.Bingo{Name: game}
  406. commongame = bg.bingomanager.Get(searchGame)
  407. }
  408. if user.Name == strings.Split(game, "\uffff")[1] {
  409. log.Println("found usergame", game)
  410. searchGame := glbingopb.Bingo{Name: game}
  411. usergame = bg.bingomanager.Get(searchGame)
  412. break
  413. }
  414. }
  415. returngame := glbingopb.Bingo{}
  416. if usergame.Name == fmt.Sprintf("%s\uffff%s", world.GetName(), user.Name) {
  417. log.Println("sending usergame", usergame.Name)
  418. returngame = usergame
  419. } else if commongame.Name == fmt.Sprintf("%s\uffff%s", world.GetName(), "common") {
  420. log.Println("sending commongame", commongame.Name)
  421. returngame = commongame
  422. } else if lobbygame.Name == fmt.Sprintf("%s\uffff%s", world.GetName(), "lobby") {
  423. log.Println("sending lobbygame", lobbygame.Name)
  424. returngame = lobbygame
  425. } else {
  426. // if get returned empty game
  427. returngame = CraftLobbygame(fmt.Sprintf("%s\uffff%s", world.GetName(), "lobby"))
  428. bg.bingomanager.Create(returngame)
  429. log.Print("could not find lobbygame, so created one")
  430. }
  431. gameJSON, err := json.Marshal(returngame)
  432. if err != nil {
  433. remsg := glwss.WSMsg{Mtype: "game:get", Payload: "failed"}
  434. return remsg, err
  435. }
  436. log.Println("game:get sending game:\n", string(gameJSON))
  437. remsg := glwss.WSMsg{Mtype: "game:get", Payload: string(gameJSON)}
  438. return remsg, nil
  439. }})
  440. handler = append(handler, glwss.Handler{MType: "game:start", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  441. log.Println("game:start new start request:\n", msg.Payload)
  442. startgame := glbingopb.Bingo{}
  443. err := json.Unmarshal([]byte(msg.Payload), &startgame)
  444. if err != nil {
  445. log.Printf("game:start - err unmarshalling startgame \"%s\"\n%s", msg, err.Error())
  446. remsg := glwss.WSMsg{Mtype: "game:start", Payload: "failed"}
  447. return remsg, err
  448. }
  449. searchworld := gamelangpb.World{Name: strings.Split(startgame.Name, "\uffff")[0]}
  450. startworld, err := bg.wm.GetWorld(context.Background(), &searchworld)
  451. if err != nil {
  452. log.Printf("game:start - err unmarshalling startworld \"%s\"\n%s", msg, err.Error())
  453. remsg := glwss.WSMsg{Mtype: "game:start", Payload: "failed"}
  454. return remsg, err
  455. }
  456. // start game
  457. for _, option := range startgame.Options {
  458. if option.Key == "common game" && option.Bool {
  459. newGame := bg.bingomanager.CraftGame(rand.Uint32(), fmt.Sprintf("%s\uffffcommon", startworld.Name), startgame.Textlist, startgame.Numrows, startgame.Numcols, startgame.Options...)
  460. bg.bingomanager.Create(newGame)
  461. addworld := gamelangpb.World{Name: startworld.Name, Games: []string{newGame.Name}}
  462. bg.wm.AddGameWorld(context.Background(), &addworld)
  463. jsonGame, err := json.Marshal(newGame)
  464. if err != nil {
  465. log.Printf("write: err marshalling game \"%s\"\n%s", msg, err.Error())
  466. }
  467. remsg := glwss.WSMsg{Mtype: "game:get", Payload: string(jsonGame)}
  468. if err != nil {
  469. log.Printf("write: err marshalling msg \"%s\"\n%s", msg, err.Error())
  470. }
  471. for _, user := range startworld.Users {
  472. go bg.wssserver.Write(user.Name, remsg)
  473. }
  474. }
  475. }
  476. remsg := glwss.WSMsg{Mtype: "game:start", Payload: "sucess"}
  477. return remsg, nil
  478. }})
  479. handler = append(handler, glwss.Handler{MType: "game:mod", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  480. modgame := &glbingopb.Bingo{}
  481. err := json.Unmarshal([]byte(msg.Payload), modgame)
  482. if err != nil {
  483. log.Printf("game:mod - err unmarshalling msg \"%s\"\n%s", msg, err.Error())
  484. remsg := glwss.WSMsg{Mtype: "game:mod", Payload: "failed"}
  485. return remsg, nil
  486. }
  487. bg.bingomanager.Modify(*modgame)
  488. searchworld := gamelangpb.World{Name: strings.Split(modgame.Name, "\uffff")[0]}
  489. world, err := bg.wm.GetWorld(context.Background(), &searchworld)
  490. if err != nil {
  491. log.Printf("game:mod - err getting world msg \"%s\"\n%s", msg, err.Error())
  492. remsg := glwss.WSMsg{Mtype: "game:mod", Payload: "failed"}
  493. return remsg, nil
  494. }
  495. notify := glwss.WSMsg{Mtype: "game:get", Payload: msg.Payload}
  496. for _, user := range world.Users {
  497. go bg.wssserver.Write(user.Name, notify)
  498. }
  499. bg.bingomanager.CheckWin()
  500. remsg := glwss.WSMsg{Mtype: "game:mod", Payload: "success"}
  501. return remsg, nil
  502. }})
  503. handler = append(handler, glwss.Handler{MType: "game:event", Callback: func(msg glwss.WSMsg, user gamelangpb.User) (glwss.WSMsg, error) {
  504. newevent := &glbingopb.Event{}
  505. err := json.Unmarshal([]byte(msg.Payload), newevent)
  506. if err != nil {
  507. log.Printf("game:event - err unmarshalling msg \"%s\"\n%s", msg, err.Error())
  508. remsg := glwss.WSMsg{Mtype: "game:event", Payload: "failed"}
  509. return remsg, nil
  510. }
  511. newevent.Username = user.Name
  512. log.Println("game:event new event", newevent)
  513. worldgamename := strings.Split(newevent.Gamename, "\uffff")
  514. worldname := worldgamename[0]
  515. gamename := worldgamename[1]
  516. // if the game is not a common game add all games from that world to neighborgames
  517. if gamename != "common" {
  518. world, err := bg.wm.GetWorld(context.Background(), &gamelangpb.World{Name: worldname})
  519. if err != nil {
  520. log.Printf("workNotifications - err getting world msg \"%s\"\n%s", worldname, err.Error())
  521. remsg := glwss.WSMsg{Mtype: "game:mod", Payload: "failed"}
  522. return remsg, nil
  523. }
  524. for _, game := range world.Games {
  525. if strings.Split(game, "\uffff")[1] != "lobby" {
  526. newevent.Neighborgames = append(newevent.Neighborgames, game)
  527. }
  528. }
  529. }
  530. err = bg.bingomanager.HandleEvent(*newevent)
  531. if err != nil {
  532. if err.Error() == "game finished" {
  533. reevent := glbingopb.Event{Type: "Win", Gamename: newevent.Gamename}
  534. eventJson, err := json.Marshal(reevent)
  535. if err != nil {
  536. log.Printf("workNotifications - err marshalling event \"%s\"\n%s", reevent, err.Error())
  537. }
  538. notify := glwss.WSMsg{Mtype: "game:event", Payload: string(eventJson)}
  539. return notify, nil
  540. }
  541. return glwss.WSMsg{Mtype: "game:event", Payload: "failed"}, err
  542. }
  543. remsg := glwss.WSMsg{Mtype: "game:event", Payload: "success"}
  544. bg.bingomanager.CheckWin()
  545. return remsg, nil
  546. }})
  547. return handler
  548. }
  549. func CraftLobbygame(name string) glbingopb.Bingo {
  550. lobbygame := glbingopb.Bingo{Name: name}
  551. lobbygame.Options = append(lobbygame.Options, &glbingopb.Option{Key: "unique fields", Bool: true, Type: 1})
  552. lobbygame.Options = append(lobbygame.Options, &glbingopb.Option{Key: "common game", Bool: true, Type: 1})
  553. lobbygame.Numcols = 5
  554. lobbygame.Numrows = 5
  555. lobbygame.Textlist = []string{"word"}
  556. return lobbygame
  557. }
  558. func main() {
  559. var config BingoConfig
  560. err := gcfg.ReadFileInto(&config, "config")
  561. if err != nil {
  562. if strings.Count(err.Error(), "no such file or directory") > 0 {
  563. config = getDefaultConfig()
  564. } else {
  565. log.Fatal(err)
  566. }
  567. }
  568. log.Print("config read")
  569. log.Printf("%+v", config)
  570. bingogame := BingoGame{}
  571. bingogame.Init(config)
  572. bingogame.webserver.InitEndpoints(bingogame.RenderEndpoints())
  573. go bingogame.webserver.Run()
  574. bingogame.wssserver = glwss.NewWSServer([]string{}, bingogame.userclient)
  575. handler := bingogame.RenderHandler()
  576. keys := ""
  577. for _, k := range handler {
  578. keys = fmt.Sprintf("%s\n%v", keys, k)
  579. }
  580. log.Println("available MTypes:\n", keys, "\n----")
  581. bingogame.wssserver.RegisterHandler(handler)
  582. http.HandleFunc("/ws", bingogame.wssserver.WebsocketHandler)
  583. log.Println("websocket listening on", fmt.Sprintf("%s:%s", config.WS.ListenIP, config.WS.ListenPort))
  584. log.Print(http.ListenAndServe(fmt.Sprintf("%s:%s", config.WS.ListenIP, config.WS.ListenPort), nil).Error())
  585. }