Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add base working prototype #1

Merged
merged 13 commits into from
May 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .github/CONTRIBUTING.md
Empty file.
22 changes: 22 additions & 0 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Golangci-lint
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- uses: actions/setup-go@v4
with:
go-version: '1.20'

- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.57.2
30 changes: 30 additions & 0 deletions .github/workflows/push-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Push Image

on:
push:
branches:
- main

jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
file: ./build/Dockerfile
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/excaliroom:latest
22 changes: 22 additions & 0 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Unit tests
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
unit-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- uses: actions/setup-go@v4
with:
go-version: '1.20'

- name: Run tests with coverage
run: go test -v ./... -coverprofile=coverage.out -covermode=atomic

- name: Run tests -race
run: go test -v ./... -race
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@

# Go workspace file
go.work
.idea
config.yaml
110 changes: 110 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
linters:
presets:
- bugs # bugs detection
- comment # comments analysis
- complexity # code complexity analysis
- error # error handling analysis
- format # code formatting
- metalinter # linter that contains multiple rules or multiple linters
- performance # performance
- unused # Checks Go code for unused constants, variables, functions and types.

enable:
- asciicheck # Checks that all code identifiers does not have non-ASCII symbols in the name.
- containedctx # Detects too much false positives around (*http.Request).Context()
- dogsled # Checks assignments with too many blank identifiers (e.g. x, , , _, := f()).
- dupl # Detects code clone. It's recommended to use
- errname # Checks that sentinel errors are prefixed with the Err and error types are suffixed with the Error.
- forcetypeassert # Finds forced type assertions.
- gochecknoglobals # Checks that no globals in code. But we need global variables. For config or single-tone pattern realisation.
- gochecknoinits # Checks that no inits functions in app. Init functions have some side effects. But we need init function for correct app initialize.
- goconst # Finds repeated strings that could be replaced by a constant.
- godox # Detects for "TODO" or "FIXME" comments.
- gomoddirectives # Manages the use of 'replace', 'retract', and 'excludes' directives in go.mod.
- goprintffuncname # Checks that printf-like functions are named with f at the end.
- gosimple # Detects areas in Go source code that can be simplified.
- lll # Reports long lines
- makezero # Finds slice declarations with non-zero initial length.
- nakedret # Checks that functions with naked returns are not longer than a maximum size (can be zero).
- nolintlint # Requires explanation for using nolint comments.
- predeclared # Finds code that shadows one of Go's predeclared identifiers.
- promlinter # Checks Prometheus metrics naming via promlint.
- stylecheck # Stylecheck is a replacement for golint.
- tagliatelle # Requires struct fields and json description to be the same. Need to rename many of json.
- thelper # Detects golang test helpers without t.Helper()
- tparallel # Detects inappropriate usage of t.Parallel() method in your Go test codes.
- unconvert # Remove unnecessary type conversions.
- wastedassign # Finds wasted assignment statements.
- whitespace # Checks for unnecessary newlines at the start and end of functions, if, for, etc.

disable:
- contextcheck # Detects too much false positives around (*http.Request).Context()
- maligned # Deprecated: performance — superseded by govet(fieldalignment)
- scopelint # Deprecated: performance — superseded by exportloopref

linters-settings:
dogsled:
max-blank-identifiers: 3

errorlint:
errorf: true

exhaustive:
default-signifies-exhaustive: true

funlen:
lines: 100
statements: 60

gci:
sections:
- standard
- default
- prefix(github.com/Icerzack/excalidraw-ws-go)

godot:
scope: declarations
exclude:
- '^ @'

goimports:
local-prefixes: github.com/Icerzack/excalidraw-ws-go

lll:
tab-width: 4

nolintlint:
allow-leading-space: false

tagliatelle:
case:
use-field-name: true
rules:
json: snake
yaml: snake

tagalign:
sort: false # puts `example` tag before more important tag `json`

issues:
max-issues-per-linter: 0
max-same-issues: 0
exclude-rules:
- path: _test\.go
linters:
- dupl
- goerr113
- forcetypeassert
- gochecknoglobals

- path: _test\.go
text: "fieldalignment"
linters:
- govet

- source: "^//go:generate "
linters:
- lll

...
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]
Copyright 2024 Max Kuznetsov

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.PHONY: run run-background stop

run:
@echo "Running Excaliroom..."
@docker-compose up --build --wait

stop:
@echo "Stopping Excaliroom..."
@docker-compose down --remove-orphans --volumes
8 changes: 8 additions & 0 deletions build/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM golang:alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o app main.go

FROM alpine
COPY --from=builder /app/app .
CMD ["./app"]
10 changes: 10 additions & 0 deletions cmd/apps.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package cmd

const (
RestApp = "REST"
)

type App interface {
Start()
Stop()
}
75 changes: 75 additions & 0 deletions cmd/appsmanager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package cmd

import (
"os"
"os/signal"
"sync"
"syscall"

"go.uber.org/zap"
)

type AppsManager struct {
apps map[string]App
wg *sync.WaitGroup

logger *zap.Logger
}

func NewAppsManager(logger *zap.Logger) *AppsManager {
return &AppsManager{
apps: make(map[string]App),
wg: &sync.WaitGroup{},
logger: logger,
}
}

func (am *AppsManager) Register(name string, app App) {
am.apps[name] = app
}

func (am *AppsManager) Run(name string) {
app, ok := am.apps[name]
if !ok {
return
}
am.logger.Info("App started", zap.String("name", name))
app.Start()
}

func (am *AppsManager) Stop(name string) {
app, ok := am.apps[name]
if !ok {
return
}
app.Stop()
am.logger.Info("App stopped", zap.String("name", name))
}

func (am *AppsManager) RunAll() {
for name, app := range am.apps {
am.wg.Add(1)
name := name
go func(app App) {
am.logger.Info("App started", zap.String("name", name))
app.Start()
am.wg.Done()
}(app)
}
}

func (am *AppsManager) StopAll() {
for name, app := range am.apps {
am.logger.Info("App stopped", zap.String("name", name))
app.Stop()
}
}

func (am *AppsManager) WaitForShutdown() {
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
<-stop

am.StopAll()
am.wg.Wait()
}
55 changes: 55 additions & 0 deletions cmd/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package cmd

import (
"fmt"
"os"

"go.uber.org/zap"
"gopkg.in/yaml.v3"
)

type Config struct {
Apps struct {
LogLevel string `yaml:"log_level"`
Rest struct {
Port int `yaml:"port"`
Validation struct {
JWTHeaderName string `yaml:"jwt_header_name"`
JWTValidationURL string `yaml:"jwt_validation_url"`
BoardValidationURL string `yaml:"board_validation_url"`
} `yaml:"validation"`
} `yaml:"rest"`
} `yaml:"apps"`
Storage struct {
Users struct {
Type string `yaml:"type"`
RedisAddress string `yaml:"redis_address"`
RedisPassword string `yaml:"redis_password"`
RedisDB int `yaml:"redis_db"`
} `yaml:"users"`
Rooms struct {
Type string `yaml:"type"`
RedisAddress string `yaml:"redis_address"`
RedisPassword string `yaml:"redis_password"`
RedisDB int `yaml:"redis_db"`
} `yaml:"rooms"`
} `yaml:"storage"`
}

func ParseConfig(path string, logger *zap.Logger) (*Config, error) {
file, err := os.Open(path)
if err != nil {
logger.Error("Failed to open config file", zap.Error(err))
return nil, fmt.Errorf("error opening file %w", err)
}
defer file.Close()

var config Config
err = yaml.NewDecoder(file).Decode(&config)
if err != nil {
logger.Error("Failed to decode config file", zap.Error(err))
return nil, fmt.Errorf("error decoding file %w", err)
}

return &config, nil
}
14 changes: 14 additions & 0 deletions config-example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apps:
log_level: "DEBUG"
rest:
port: 8080
validation:
jwt_header_name: "<YOUR_JWT_HEADER_NAME>"
jwt_validation_url: "<YOUR_JWT_VALIDATION_URL>"
board_validation_url: "<YOUR_BOARD_VALIDATION_URL>"

storage:
users:
type: "in-memory"
rooms:
type: "in-memory"
13 changes: 13 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: "3.8"

services:
app:
build:
context: .
dockerfile: build/Dockerfile
environment:
- CONFIG_PATH=config.yaml
ports:
- "8080:8080"
volumes:
- ./config.yaml:/config.yaml
Loading
Loading