tons of backend changes

This commit is contained in:
vel 2022-01-22 22:57:25 -08:00
parent 996bfea07c
commit fd536075c5
Signed by: velvox
GPG Key ID: 1C8200C1D689CEF5
24 changed files with 497 additions and 396 deletions

View File

@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordProjectSettings">
<option name="show" value="PROJECT_FILES" />
<option name="description" value="" />
</component>
</project>

109
backend/.idea/workspace.xml Normal file
View File

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="ALL" />
</component>
<component name="ChangeListManager">
<list default="true" id="8a64704d-5500-41a6-aa4c-e275933fc58c" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/internal/ws/client.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/internal/ws/handlers.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/internal/ws/hub.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/internal/ws/message.go" afterDir="false" />
<change afterPath="$PROJECT_DIR$/internal/ws/structs.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.gitignore" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/Dockerfile" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/cmd/watchtogether/main.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/watchtogether/main.go" afterDir="false" />
<change beforePath="$PROJECT_DIR$/docker-compose.yml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/go.mod" beforeDir="false" afterPath="$PROJECT_DIR$/go.mod" afterDir="false" />
<change beforePath="$PROJECT_DIR$/go.sum" beforeDir="false" afterPath="$PROJECT_DIR$/go.sum" afterDir="false" />
<change beforePath="$PROJECT_DIR$/internal/driver/driver.go" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/internal/logger/logger.go" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/internal/server/middleware.go" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/internal/server/routes.go" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/internal/server/server.go" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/services/logger.go" beforeDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Go File" />
</list>
</option>
</component>
<component name="GOROOT" url="file:///usr/lib/go" />
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
</component>
<component name="GitSEFilterConfiguration">
<file-type-list>
<filtered-out-file-type name="LOCAL_BRANCH" />
<filtered-out-file-type name="REMOTE_BRANCH" />
<filtered-out-file-type name="TAG" />
<filtered-out-file-type name="COMMIT_BY_MESSAGE" />
</file-type-list>
</component>
<component name="GoLibraries">
<option name="indexEntireGoPath" value="false" />
</component>
<component name="MarkdownSettingsMigration">
<option name="stateVersion" value="1" />
</component>
<component name="ProjectId" id="2456l5ltkI1NptLGqpacBxKAWdj" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="DefaultGoTemplateProperty" value="Go File" />
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="go.format.on.save.advertiser.fired" value="true" />
<property name="go.formatter.settings.were.checked" value="true" />
<property name="go.import.settings.migrated" value="true" />
<property name="go.modules.go.list.on.any.changes.was.set" value="true" />
<property name="go.sdk.automatically.set" value="true" />
<property name="go.watchers.conflict.with.on.save.actions.check.performed" value="true" />
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
</component>
<component name="RunManager">
<configuration name="go build github.com/qpixel/watchtogether/cmd/watchtogether" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true" nameIsGenerated="true">
<module name="backend" />
<working_directory value="$PROJECT_DIR$" />
<kind value="PACKAGE" />
<package value="github.com/qpixel/watchtogether/cmd/watchtogether" />
<directory value="$PROJECT_DIR$" />
<filePath value="$PROJECT_DIR$/cmd/watchtogether/main.go" />
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="Go Build.go build github.com/qpixel/watchtogether/cmd/watchtogether" />
</list>
</recent_temporary>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="Vcs.Log.Tabs.Properties">
<option name="TAB_STATES">
<map>
<entry key="MAIN">
<value>
<State />
</value>
</entry>
</map>
</option>
</component>
<component name="VgoProject">
<integration-enabled>true</integration-enabled>
</component>
</project>

View File

View File

@ -1,72 +1,41 @@
package main package main
import ( import (
"flag" "encoding/json"
"fmt" "github.com/gorilla/mux"
"github.com/peterbourgon/ff/v3" "github.com/qpixel/watchtogether/internal/ws"
"github.com/qpixel/watchtogether/internal/logger" tlog "github.com/ubergeek77/tinylog"
"github.com/qpixel/watchtogether/internal/server" "net/http"
"github.com/ubergeek77/tinylog"
"os"
"runtime"
) )
type flags struct { var log = tlog.NewTaggedLogger("Logger", tlog.NewColor("38;5;111"))
loglvl int
port int
}
func newFlags(args []string) (flgs flags, err error) {
fs := flag.NewFlagSet(args[0], flag.ContinueOnError)
var (
loglvl = fs.Int("loglvl", tinylog.TraceLevel, "sets the log level (also via LOG_LEVEL)")
port = fs.Int("port", 4000, "sets the port to use (also via PORT)")
)
// Parse the command line flags from above
err = ff.Parse(fs, args[1:], ff.WithEnvVarNoPrefix())
if err != nil {
return flgs, err
}
return flags{
loglvl: *loglvl,
port: *port,
}, nil
}
func main() { func main() {
if err := run(os.Args); err != nil { r := mux.NewRouter()
tinylog.DefaultLogger().Errorf("error from main.run(): %s\n", err) r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
os.Exit(1) w.Header().Set("Content-Type", "application/json")
} resp := make(map[string]string)
resp["status"] = "ok"
jsonResp, err := json.Marshal(resp)
if err != nil {
log.Fatalf("error in unmarshalling json. err: %s", err.Error())
}
_, err = w.Write(jsonResp)
if err != nil {
return
}
return
})
hub := ws.NewHub()
go hub.Run()
} r.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
ws.ServeWs(hub, w, r)
})
func run(args []string) error { err := http.ListenAndServe(":8080", r)
flgs, err := newFlags(args)
if err != nil { if err != nil {
return err log.Errorf("%s", err.Error())
log.Fatalf("unable to serve on port 8080")
} }
// setup logger with defaults
lgr := logger.NewLogger(flgs.loglvl, "WatchTogether")
lgr.Infof("go runtime ver: %s", runtime.Version())
lgr.Infof("Logging level has been set to %d", lgr.LogLevel)
mr := server.NewMuxRouter()
serverDriver := server.NewDriver()
params := server.NewServerParams(lgr, serverDriver)
s, err := server.NewServer(mr, params)
if err != nil {
lgr.Errorf("err: %s", err)
lgr.Fatal("error in server.NewServer")
}
s.Addr = fmt.Sprintf(":%d", flgs.port)
return s.ListenAndServe()
} }

View File

@ -2,16 +2,8 @@ module github.com/qpixel/watchtogether
go 1.17 go 1.17
replace (
github.com/qpixel/tloghttp => ../../tloghttp
github.com/qpixel/tlogbuilder => ../../tlogbuilder
)
require ( require (
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0 // indirect
github.com/justinas/alice v1.2.0 github.com/gorilla/websocket v1.4.2 // indirect
github.com/peterbourgon/ff/v3 v3.1.2 github.com/ubergeek77/tinylog v1.0.0 // indirect
github.com/qpixel/tloghttp v0.0.0-20211222065322-cd8d1a945a36
github.com/qpixel/tlogbuilder v0.0.0
github.com/ubergeek77/tinylog v1.0.0
) )

View File

@ -1,13 +1,6 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
github.com/peterbourgon/ff/v3 v3.1.2 h1:0GNhbRhO9yHA4CC27ymskOsuRpmX0YQxwxM9UPiP6JM=
github.com/peterbourgon/ff/v3 v3.1.2/go.mod h1:XNJLY8EIl6MjMVjBS4F0+G0LYoAqs0DTa4rmHHukKDE=
github.com/ubergeek77/tinylog v1.0.0 h1:gsq98mbig3LDWhsizOe2tid12wHUz/mrkDlmgJ0MZG4= github.com/ubergeek77/tinylog v1.0.0 h1:gsq98mbig3LDWhsizOe2tid12wHUz/mrkDlmgJ0MZG4=
github.com/ubergeek77/tinylog v1.0.0/go.mod h1:NzUi4PkRG2hACL4cGgmW7db6EaKjAeqrqlVQnJdw78Q= github.com/ubergeek77/tinylog v1.0.0/go.mod h1:NzUi4PkRG2hACL4cGgmW7db6EaKjAeqrqlVQnJdw78Q=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -1,45 +0,0 @@
// Copyright 2018 The Go Cloud Development Kit Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// @gilcrest - removed TLSServer interface
// Package driver defines an interface for custom HTTP listeners.
// Application code should use package server.
package driver
import (
"context"
"net/http"
)
// Server dispatches requests to an http.Handler.
type Server interface {
// ListenAndServe listens on the TCP network address addr and then
// calls Serve with handler to handle requests on incoming connections.
// The addr argument will be a non-empty string specifying "host:port".
// The http.Handler will always be non-nil.
// Drivers must block until serving is done (or
// return an error if serving can't occur for some reason), serve
// requests to the given http.Handler, and be interruptable by Shutdown.
// Drivers should use the given address if they serve using TCP directly.
ListenAndServe(addr string, h http.Handler) error
// Shutdown gracefully shuts down the server without interrupting
// any active connections. If the provided context expires before
// the shutdown is complete, Shutdown returns the context's error,
// otherwise it returns any error returned from closing the Server's
// underlying Listener(s).
Shutdown(ctx context.Context) error
}

View File

@ -1,17 +0,0 @@
package logger
import (
"github.com/ubergeek77/tinylog"
)
func NewLogger(lvl int, tag string) *tinylog.Logger {
// cfg contains our custom config for tinylog
cfg := tinylog.NewConfig()
cfg.LogLevel = lvl
cfg.LogPrefix = tinylog.GenerateTag(tag, tinylog.NewColor("38;5;133"), cfg)
//initialize the instance of tinylog
lgr := tinylog.NewLogger(cfg)
return lgr
}

View File

@ -1,59 +0,0 @@
package server
import (
"github.com/justinas/alice"
"github.com/qpixel/tlogbuilder"
"github.com/qpixel/tloghttp"
"net/http"
"time"
)
// MIT License
//
//Copyright (c) 2017 Dan Gillis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// LoggerChain returns a middleware chain (via alice.Chain)
// initialized with all the standard middleware handlers for logging. The logger
// will be added to the request context for subsequent use with pre-populated
// fields, including the request method, url, status, size, duration, remote IP,
// user agent, referer. A unique Request ID is also added to the logger, context
// and response headers.
func (s *Server) loggerChain() alice.Chain {
ac := alice.New(tloghttp.NewHandler(s.logger),
tloghttp.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) {
tlogbuilder.CreateBuilder(tloghttp.FromRequest(r)).
Info().
Str("method", r.Method).
Stringer("url", r.URL).
Int("status", status).
Int("size", size).
Dur("duration", duration).
Msg("request logged").
Build()
}),
tloghttp.RemoteAddrHandler("remote_ip"),
tloghttp.UserAgentHandler("user_agent"),
tloghttp.RefererHandler("referer"),
//tloghttp.RequestIDHandler("request_id", "Request-Id"),
)
return ac
}

View File

@ -1,14 +0,0 @@
package server
import "net/http"
const (
contentTypeHeaderKey string = "Content-Type"
appJSONContentTypeHeaderVal string = "application/json",
)
func (s *Server) routes() {
s.router.Handle("/", func(http.ResponseWriter, *http.Response) {
})
}

View File

@ -1,159 +0,0 @@
// Copyright 2018 The Go Cloud Development Kit Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// @QPixel edits - I have made a copy of the go-api-basic server code and made
// the following changes:
//
// - removed zerolog dependency
package server
import (
"context"
"errors"
"github.com/gorilla/mux"
"github.com/qpixel/watchtogether/internal/driver"
"github.com/ubergeek77/tinylog"
"io"
"net/http"
"time"
)
const pathPrefix = "/api"
// Server represents an HTTP server
type Server struct {
router *mux.Router
driver driver.Server
logger *tinylog.Logger
Addr string
// Authorization
// Services
}
//type LoggerService interface {
// Read() logger.LoggerResponse
//
//}
// SvrParams is the set of configuration parameters for a Server
type SvrParams struct {
// Logger is used for the server logging
Logger *tinylog.Logger
// Driver serves HTTP requests
Driver driver.Server
}
// NewServerParams is an initializer for ServerParams
func NewServerParams(lgr *tinylog.Logger, d driver.Server) *SvrParams {
options := &SvrParams{
Logger: lgr,
Driver: d,
}
return options
}
// NewServer initializes a new Server and registers
// routes to the router mux
// todo add error checking
func NewServer(r *mux.Router, params *SvrParams) (*Server, error) {
s := &Server{router: r}
s.logger = params.Logger
s.driver = params.Driver
return s, nil
}
func (s *Server) ListenAndServe() error {
if s.Addr == "" {
return errors.New("server Addr is empty")
}
if s.router == nil {
return errors.New("server router is nil")
}
if s.driver == nil {
return errors.New("server driver is nil")
}
s.logger.Infof("server is listening on %s", s.Addr)
return s.driver.ListenAndServe(s.Addr, s.router)
}
// Shutdown will gracefully shut down the server without interrupting any active connections
func (s *Server) Shutdown(ctx context.Context) error {
if s.driver == nil {
return nil
}
return s.driver.Shutdown(ctx)
}
// Driver implements the driver.Server interface. The zero value is a valid http.Server
type Driver struct {
Server http.Server
}
// NewDriver intializes a Driver with http.Server using default timeouts
func NewDriver() *Driver {
return &Driver{
Server: http.Server{
ReadTimeout: 30 * time.Second,
WriteTimeout: 30 * time.Second,
IdleTimeout: 120 * time.Second,
},
}
}
// ListenAndServe sets the address and handler on Driver's http.Server
func (d *Driver) ListenAndServe(addr string, h http.Handler) error {
d.Server.Addr = addr
d.Server.Handler = h
return d.Server.ListenAndServe()
}
// Shutdown gracefully shuts down the server without interrupting any active connections,
// by calling Shutdown on Driver's http.Server
func (d *Driver) Shutdown(ctx context.Context) error {
return d.Server.Shutdown(ctx)
}
// NewMuxRouter initializes a gorilla/mux router and
// adds the /api subroute to it
func NewMuxRouter() *mux.Router {
// initializer gorilla/mux router
r := mux.NewRouter()
// send Router through PathPrefix method to validate any standard
// subroutes you may want for your APIs. e.g. I always want to be
// sure that every request has "/api" as part of its path prefix
// without having to put it into every handle path in my various
// routing functions
s := r.PathPrefix(pathPrefix).Subrouter()
return s
}
func decoderErr(err error) error {
switch {
case err == io.EOF:
return errors.New("request body cannot be empty")
case err == io.ErrUnexpectedEOF:
return errors.New("malformed json")
case err != nil:
return err
}
return nil
}

View File

@ -0,0 +1,129 @@
package ws
import (
"bytes"
"github.com/gorilla/websocket"
"net/http"
"time"
)
const (
// time allowed to write a message to the peer.
writeWait = 10 * time.Second
pongWait = 60 * time.Second
pingPeriod = (pongWait * 9) / 10
maxMessageSize = 512
)
var (
newline = []byte{'\n'}
space = []byte{' '}
)
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
type Client struct {
hub *Hub
conn *websocket.Conn
send chan []byte
}
// readPump pumps messages from the websocket connection to the hub.
//
// The application runs readPump in a per-connection goroutine. The application
// ensures that there is at most one reader on a connection by executing all
// reads from this goroutine.
func (c *Client) readPump() {
defer func() {
c.hub.unregister <- c
c.conn.Close()
}()
c.conn.SetReadLimit(maxMessageSize)
c.conn.SetReadDeadline(time.Now().Add(pongWait))
c.conn.SetPongHandler(func(string) error { c.conn.SetReadDeadline(time.Now().Add(pongWait)); return nil })
for {
_, message, err := c.conn.ReadMessage()
if err != nil {
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
log.Infof("error: %v", err)
}
break
}
message = bytes.TrimSpace(bytes.Replace(message, newline, space, -1))
c.hub.broadcast <- RawMessage{
Client: c,
Data: message,
}
}
}
// writePump pumps messages from the hub to the websocket connection.
//
// A goroutine running writePump is started for each connection. The
// application ensures that there is at most one writer to a connection by
// executing all writes from this goroutine.
func (c *Client) writePump() {
ticker := time.NewTicker(pingPeriod)
defer func() {
ticker.Stop()
c.conn.Close()
}()
for {
select {
case message, ok := <-c.send:
c.conn.SetWriteDeadline(time.Now().Add(writeWait))
if !ok {
// The hub closed the channel.
c.conn.WriteMessage(websocket.CloseMessage, []byte{})
return
}
w, err := c.conn.NextWriter(websocket.TextMessage)
if err != nil {
return
}
w.Write(message)
// Add queued chat messages to the current websocket message.
n := len(c.send)
for i := 0; i < n; i++ {
w.Write(newline)
w.Write(<-c.send)
}
if err := w.Close(); err != nil {
return
}
case <-ticker.C:
c.conn.SetWriteDeadline(time.Now().Add(writeWait))
if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
return
}
}
}
}
// ServeWs handles websocket requests from the peer.
func ServeWs(hub *Hub, w http.ResponseWriter, r *http.Request) {
upgrader.CheckOrigin = func(r *http.Request) bool {
return true
}
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Error(err.Error())
return
}
client := &Client{hub: hub, conn: conn, send: make(chan []byte, 256)}
client.hub.register <- client
// Allow collection of memory referenced by the caller by doing all work in
// new goroutines.
go client.writePump()
go client.readPump()
}

View File

@ -0,0 +1,21 @@
package ws
type IdentityData struct {
ClientID string `json:"client_id"`
User User `json:"user"`
}
func handleIdentifyEvent(message *Message) {
}
func handlePingEvent(message *Message) {
m := Message{
message.Client,
MessageData{
Type: Pong,
Data: nil,
},
}
message.send <- m.SerializeMessage().Data
}

View File

@ -0,0 +1,59 @@
package ws
type Hub struct {
// Registered clients
clients map[*Client]bool
// Inbound messages from the clients
broadcast chan RawMessage
// Register requests from the clients
register chan *Client
// Unregister requests from clients
unregister chan *Client
}
func NewHub() *Hub {
return &Hub{
broadcast: make(chan RawMessage),
register: make(chan *Client),
unregister: make(chan *Client),
clients: make(map[*Client]bool),
}
}
func (h *Hub) handleMessage(rm RawMessage) {
m := rm.UnSerializeData()
switch m.Type {
case Identify:
handleIdentifyEvent(&m)
case Ping:
handlePingEvent(&m)
}
return
}
func (h *Hub) Run() {
for {
select {
case client := <-h.register:
h.clients[client] = true
case client := <-h.unregister:
if _, ok := h.clients[client]; ok {
delete(h.clients, client)
close(client.send)
}
case message := <-h.broadcast:
go h.handleMessage(message)
//for client := range h.clients {
// select {
// case client.send <- message:
// default:
// close(client.send)
// delete(h.clients, client)
// }
//}
}
}
}

View File

@ -0,0 +1,72 @@
package ws
import (
"encoding/json"
tlog "github.com/ubergeek77/tinylog"
"strconv"
)
var log = tlog.NewTaggedLogger("WS", tlog.NewColor("38;5;111"))
type MessageTypes float64
// todo rewrite to use an event handler system
const (
Ping MessageTypes = iota
Pong
Identify
Position
SetPosition
)
type MessageData struct {
Type MessageTypes `json:"type"`
RawData json.RawMessage `json:"data,omitempty"`
Data map[string]interface{} `json:"-"`
}
type Message struct {
*Client
MessageData
}
type RawMessage struct {
Client *Client
Data []byte
}
func (rm RawMessage) UnSerializeData() Message {
s, _ := strconv.Unquote(string(rm.Data))
var md MessageData
if err := json.Unmarshal([]byte(s), &md); err != nil {
log.Errorf("error unmarshalling message, %s", err.Error())
}
if md.RawData != nil && len(md.RawData) > 0 && md.RawData[0] == '"' {
var s string
if err := json.Unmarshal(md.RawData, &s); err != nil {
// handle error
log.Errorf("error unmarshalling message, %s", err.Error())
}
md.RawData = json.RawMessage(s)
if err := json.Unmarshal(md.RawData, &md.Data); err != nil {
// handle error
log.Errorf("error unmarshalling message, %s", err.Error())
}
}
m := Message{
Client: rm.Client,
MessageData: md,
}
return m
}
func (m Message) SerializeMessage() RawMessage {
data, err := json.Marshal(m)
if err != nil {
log.Errorf("unable to marshal message, %s", err.Error())
}
return RawMessage{
Data: data,
}
}

View File

@ -0,0 +1,7 @@
package ws
type User struct {
Name string `json:"name"`
UserID string `json:"user_id"`
Admin bool `json:"admin"`
}

View File

@ -1,13 +0,0 @@
package services
import "github.com/ubergeek77/tinylog"
// LoggerService reads and updates the logger state
type LoggerService struct {
Logger tinylog.Logger
}
// NewLoggerService creates a new instance of the logging service
func NewLoggerService(logger tinylog.Logger) *LoggerService {
return &LoggerService{Logger: logger}
}

View File

@ -0,0 +1,14 @@
enum MessageTypes {
Ping,
Pong,
Identify,
Position,
SetPosition,
}
interface IMessage {
Type: MessageTypes;
Data?: Map<string, unknown>;
}
export default IMessage;

View File

@ -0,0 +1,5 @@
interface IUser {
name: string;
userID: string;
admin: boolean;
}

View File

@ -0,0 +1,4 @@
interface IdentityData {
clientID: string;
user: IUser;
}

View File

@ -19,7 +19,6 @@ const AdminPage: NextPage<AdminPageProps> = ({
isAdmin, isAdmin,
session, session,
}) => { }) => {
console.log(session);
return ( return (
<> <>
<Container height="100vh"> <Container height="100vh">

36
yarn-error.log Normal file
View File

@ -0,0 +1,36 @@
Arguments:
/home/pixel/.volta/tools/image/node/16.13.2/bin/node /home/pixel/.volta/tools/image/yarn/1.22.17/bin/yarn.js add -D @types/zib
PATH:
/home/pixel/.volta/tools/image/yarn/1.22.17/bin:/home/pixel/.volta/tools/image/node/16.13.2/bin:/home/pixel/.volta/bin:/home/pixel/.volta/bin:/home/pixel/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl
Yarn version:
1.22.17
Node version:
16.13.2
Platform:
linux x64
Trace:
Error: https://registry.yarnpkg.com/@types%2fzib: Not found
at Request.params.callback [as _callback] (/home/pixel/.volta/tools/image/yarn/1.22.17/lib/cli.js:67029:18)
at Request.self.callback (/home/pixel/.volta/tools/image/yarn/1.22.17/lib/cli.js:140883:22)
at Request.emit (node:events:390:28)
at Request.<anonymous> (/home/pixel/.volta/tools/image/yarn/1.22.17/lib/cli.js:141855:10)
at Request.emit (node:events:390:28)
at IncomingMessage.<anonymous> (/home/pixel/.volta/tools/image/yarn/1.22.17/lib/cli.js:141777:12)
at Object.onceWrapper (node:events:509:28)
at IncomingMessage.emit (node:events:402:35)
at endReadableNT (node:internal/streams/readable:1343:12)
at processTicksAndRejections (node:internal/process/task_queues:83:21)
npm manifest:
No manifest
yarn manifest:
No manifest
Lockfile:
No lockfile