Skip to content

Commit

Permalink
Initial PoC, implementing:
Browse files Browse the repository at this point in the history
- Reading configuration from pxls.conf
- Webserver: /info, /boarddata, /whoami
- Websocket: userinfo (login with IP), pixel (place and update board), pixels (update player's stack)

also:
- Added go.mod
- Added reference.conf (now reference.pxls.conf) from Pxls
- Added implementation TODO to README.md
- Fixed small indentation in pxls.js
  • Loading branch information
netux committed Aug 19, 2019
1 parent 04873f2 commit c8b7566
Show file tree
Hide file tree
Showing 14 changed files with 928 additions and 7 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# VS Code
*debug*
settings.json

# Configuration
pxls.conf
18 changes: 18 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/src/main.go",
"cwd": "${workspaceFolder}",
"env": {},
"args": []
}
]
}
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,37 @@ This started from the frustration of getting the original, Java version, to work
I'm fairly new to Rust and had learned Golang a few months ago, so prefered trying to refresh what I knew about Golang instead.

With some hope (and luck), this might eventually become the live version of the game.


## Implemented
- [x] Load pxls.conf
- [ ] Load boarddata.bin
- [ ] Webserver
- [x] Sending static content to the client
- [x] /info endpoint
- [x] /boarddata endpoint
- [x] /whoami endpoint
- [ ] other endpoints...
- [ ] Websocket
- [x] send userinfo message
- [x] IP-based
- [ ] User-based
- [x] handle pixel placing
- [x] handle pixel stacking
- [ ] other message types...
- [ ] User roles
- [ ] Database
- [ ] Console commands


## Plans
- [ ] Separate frontend-serving code from game-handling backend code

### Ambitious ideas
- [ ] Tools
- [ ] /stats in Golang
- [ ] Database overview for moderators in Golang
- [ ] boarddata.bin maker
- [ ] Frontend
- [ ] Modularize/[Webpacketize](https://github.com/go-webpack/webpack)
- [ ] Convert to [TypeScript](https://www.typescriptlang.org/)
7 changes: 7 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module pxls.space/go-rework

require (
github.com/go-akka/configuration v0.0.0-20190712021255-16baaebe39b5
github.com/gorilla/websocket v1.4.0
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
)
9 changes: 9 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
github.com/go-akka/configuration v0.0.0-20190712021255-16baaebe39b5 h1:CJkpF8xbiqhNUfHxHA7sR5fEDZmLdM9h1HeWjpsQxiM=
github.com/go-akka/configuration v0.0.0-20190712021255-16baaebe39b5/go.mod h1:19bUnum2ZAeftfwwLZ/wRe7idyfoW2MfmXO464Hrfbw=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
191 changes: 191 additions & 0 deletions reference.pxls.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
// The canvas code, especially useful for external sites to know that the canvas has rolled over
canvascode: "1"

server {
port: 4567

// The directory the server places board files and backups in
storage: .

// If you're using a reverse proxy, you need to set this up to identify the users' real IPs
// If the connecting client's IP matches "server.proxy.localhosts", it will look up each header in the "headers" field
// in sequence until it finds a non-local IP, and will use that IP throughout for rate limiting and storage
proxy {
// If you have a custom load balancer, reverse proxy, DDoS protector, etc, put its IP in here
localhosts: ["127.0.0.1", "0:0:0:0:0:0:0:1"]
headers: []
}

limits {
// time is a rate limit time frame
// count is how many times a request can be made in that time frame before 429ing
signup {
count: 4
time: 1h
}

auth {
count: 3
time: 10m
}

lookup {
count: 20
time: 2m
}

undo {
count: 3
time: 1m
}

chat {
count: 2
time: 1s
}
}
}

html {
title: Pxls
head: ""
info: "resource:/public/info.html"
}

database {
// The driver class to use, currently only org.mariadb.jdbc.Driver is supported
driver: org.mariadb.jdbc.Driver

user: ""
pass: ""

// The JDBC URI, of the format "jdbc:mariadb://<host>:<port>/<db>"
// database will add "?allowMultiQueries=true" so make sure nothing is inserted after <db>
// example: "jdbc:mariadb://localhost:3306/pxls"
url: ""
}

pixelCounts {
countTowardsAlltime: true,
countTowardsCurrent: true
}

board {
width: 1000
height: 1000
palette: [
"#FFFFFF",
"#E4E4E4",
"#888888",
"#222222",
"#FFA7D1",
"#E50000",
"#E59500",
"#A06A42",
"#E5D900",
"#94E044",
"#02BE01",
"#00D3DD",
"#0083C7",
"#0000EA",
"#CF6EE4",
"#820080"
]
defaultColor: 0
// See cooldown below
heatmapCooldown: 3h
saveInterval: 5s
backupInterval: 5m
}

// See https://github.com/typesafehub/config/blob/master/HOCON.md#duration-format
// raw numbers will be interpreted as milliseconds
cooldown: 3m
useStaticCooldown: false
undo {
window: 5s
}

// Cooldown increase based on authed user count
activityCooldown {
enabled: true
// This multiplies the final cooldown in seconds
multiplier: 1
}

selfPixelTimeIncrease: true

// Cooldown multiplier for placing on non-background pixels
backgroundPixel {
enabled: true
// This multiplies the final cooldown in seconds
multiplier: 1.6
}

// System host, used for various things, including auth. MUST be set correctly or you'll have a bad time trying to debug auth. Should be set to your domain - or IP if testing locally - without port.
host: ""

captcha {
// Captcha will show rougly 1/<threshold> times
threshold: 5
key: ""
secret: ""
maxPixels: 0
allTime: true
}

stacking {
cooldownMultiplier: 3,
maxStacked: 5
}

whoamiAllowedOrigin: "https://pxls.space"

oauth {
useIp: false
// Should be your url + /auth (for example, http://pxls.space/auth)
callbackBase: ""

enableRegistration: true

// Create at https://www.reddit.com/prefs/apps
reddit {
key: ""
secret: ""
minAge: 1d
}

// Create at https://console.developers.google.com/
google {
key: ""
secret: ""
}

// Create at https://discordapp.com/developers/applications/me
discord {
key: ""
secret: ""
minAge: 1d
}

// Create at https://vk.com/apps?act=manage
vk {
key: ""
secret: ""
}

// Create at https://www.tumblr.com/oauth/apps
tumblr {
key: ""
secret: ""
}
}

chat {
filter {
enabled: true
static: []
regex: ["n([i1]+)g+([e3a4])[2r]?[5sz]?", "f[a4]g+[sz5]?([o0][7t]+)?", "k[1i]+k[e3]+[5sz]?"] //"nigger, faggot, kike" and their short/1337/plural alternatives
}
trimInput: true
}
54 changes: 54 additions & 0 deletions src/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package main

import (
"time"

"github.com/go-akka/configuration"
)

// Palette is a list of color values that can be used in the canvas.
type Palette []int

// Canvas contains canvas information: width, height and pixel color indices.
type Canvas struct {
Width uint
Height uint
Board []byte
}

// NewCanvas creates new canvas with the width and height specified.
func NewCanvas(w, h uint, bgColorIdx byte) *Canvas {
c := &Canvas{w, h, make([]byte, w*h)}
for y := uint(0); y < h; y++ {
for x := uint(0); x < w; x++ {
c.Board[x+y*w] = bgColorIdx
}
}
return c
}

// GetPixelColorIndex returns the color index of the pixel.
func (c *Canvas) GetPixelColorIndex(x, y uint) byte {
return c.Board[x+y*c.Width]
}

// SetPixelColor sets the color index of a pixel.
func (c *Canvas) SetPixelColor(x, y uint, colorIdx byte) {
c.Board[x+y*c.Width] = colorIdx
}

// PxlsApp stores information about the game application.
type PxlsApp struct {
conf configuration.Config
canvas Canvas
palette Palette
users []User
}

// GetCooldown returns the time in between placing pixels
// players have to wait until they can place again.
func (a *PxlsApp) GetCooldown() time.Duration {
var cooldown = a.conf.GetTimeDurationInfiniteNotAllowed("cooldown")
// TODO(netux): apply math function used in Pxls' sourcecode
return cooldown
}
70 changes: 70 additions & 0 deletions src/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package main

import (
"fmt"
"strconv"

"github.com/go-akka/configuration"
)

const (
// MaxUserAmount is the maximum amount of concurrent users supported by the server
MaxUserAmount = 1024

// TODO(netux): lower these values

// MaxWebsocketReadBufferSize is the maximum size limit of a valid websocket incoming message
MaxWebsocketReadBufferSize = 1024
// MaxWebsocketSendBufferSize is the maximum size limit of a valid websocket outgoing message
MaxWebsocketSendBufferSize = 1024
)

// makeCanvasFromConf reads width and height from the config file and creates a canvas
func makeCanvasFromConf(conf *configuration.Config) (*Canvas, error) {
return NewCanvas(
uint(conf.GetInt32("board.width")),
uint(conf.GetInt32("board.height")),
byte(conf.GetInt32("board.defaultColor")),
), nil
}

// makePaletteFromConf converts the palette in the config file to a Palette
func makePaletteFromConf(conf *configuration.Config) (Palette, error) {
cPalette := conf.GetStringList("board.palette")

var palette = make(Palette, len(cPalette))
for i, v := range cPalette {
c, err := strconv.ParseInt(v[1:], 16, 32)
if err != nil {
return nil, err
}
palette[i] = int(c)
}

return palette, nil
}

// App stores globally accesible information about the game application
var App PxlsApp

func main() {
// TODO(netux): open file manually to handle file not found errors
var conf = configuration.LoadConfig("pxls.conf")

palette, err := makePaletteFromConf(conf)
if err != nil {
fmt.Printf("Palette parsing from config err: %s\n", err)
return
}
canvas, err := makeCanvasFromConf(conf)
if err != nil {
fmt.Printf("Canvas parsing from config err: %s\n", err)
return
}

var users = make([]User, 0, 1024)

App = PxlsApp{*conf, *canvas, palette, users}

StartServer()
}
Loading

0 comments on commit c8b7566

Please sign in to comment.