tons of backend changes
This commit is contained in:
parent
996bfea07c
commit
fd536075c5
|
|
@ -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
|
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
func run(args []string) error {
|
|
||||||
|
|
||||||
flgs, err := newFlags(args)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
log.Fatalf("error in unmarshalling json. err: %s", err.Error())
|
||||||
}
|
}
|
||||||
// setup logger with defaults
|
_, err = w.Write(jsonResp)
|
||||||
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 {
|
if err != nil {
|
||||||
lgr.Errorf("err: %s", err)
|
return
|
||||||
lgr.Fatal("error in server.NewServer")
|
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
})
|
||||||
|
hub := ws.NewHub()
|
||||||
|
go hub.Run()
|
||||||
|
|
||||||
s.Addr = fmt.Sprintf(":%d", flgs.port)
|
r.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ws.ServeWs(hub, w, r)
|
||||||
|
})
|
||||||
|
|
||||||
return s.ListenAndServe()
|
err := http.ListenAndServe(":8080", r)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("%s", err.Error())
|
||||||
|
log.Fatalf("unable to serve on port 8080")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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=
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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) {
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package ws
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
Admin bool `json:"admin"`
|
||||||
|
}
|
||||||
|
|
@ -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}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
enum MessageTypes {
|
||||||
|
Ping,
|
||||||
|
Pong,
|
||||||
|
Identify,
|
||||||
|
Position,
|
||||||
|
SetPosition,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IMessage {
|
||||||
|
Type: MessageTypes;
|
||||||
|
Data?: Map<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IMessage;
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
interface IUser {
|
||||||
|
name: string;
|
||||||
|
userID: string;
|
||||||
|
admin: boolean;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
interface IdentityData {
|
||||||
|
clientID: string;
|
||||||
|
user: IUser;
|
||||||
|
}
|
||||||
|
|
@ -19,7 +19,6 @@ const AdminPage: NextPage<AdminPageProps> = ({
|
||||||
isAdmin,
|
isAdmin,
|
||||||
session,
|
session,
|
||||||
}) => {
|
}) => {
|
||||||
console.log(session);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Container height="100vh">
|
<Container height="100vh">
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
Loading…
Reference in New Issue