Skip to content

Commit

Permalink
feat(server): create a minimal server
Browse files Browse the repository at this point in the history
Signed-off-by: Tristan Partin <tristan@partin.io>
  • Loading branch information
tristan957 committed Nov 29, 2024
1 parent 2e5204d commit 72e1e4e
Show file tree
Hide file tree
Showing 20 changed files with 684 additions and 6 deletions.
41 changes: 41 additions & 0 deletions .github/workflows/build-server.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# SPDX-FileCopyrightText: 2024 Tristan Partin <tristan@partin.io>

name: Build Server

on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**.go"

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref }}
cancel-in-progress: true

jobs:
build-server:
runs-on: ubuntu-latest

steps:
- name: Checkout gosplitsies
uses: actions/checkout@v4

- name: Setup Go
uses: actions/setup-go@v5
with:
check-latest: true
go-version: stable

- name: Install Just
run: |
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh |
bash -s -- --to /usr/local/bin
- name: Build the Server
run: |
just debug
32 changes: 32 additions & 0 deletions .github/workflows/golangci-lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# SPDX-FileCopyrightText: 2024 Tristan Partin <tristan@partin.io>

name: golangci-lint

on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**.go"

permissions:
contents: read

jobs:
golangci-lint:
runs-on: ubuntu-latest

steps:
- name: Checkout gosplitsies
uses: actions/checkout@v4

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: stable

- name: Lint
uses: golangci/golangci-lint-action@v6
with:
version: latest
2 changes: 1 addition & 1 deletion .github/workflows/reuse.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- name: Checkout splitsies
- name: Checkout gosplitsies
uses: actions/checkout@v4

- name: Lint
Expand Down
62 changes: 62 additions & 0 deletions .github/workflows/vacuum.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# SPDX-FileCopyrightText: 2024 Tristan Partin <tristan@partin.io>

name: vacuum

on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- "openapi.yaml"
- "vacuum.conf.yaml"

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref }}
cancel-in-progress: true

jobs:
vacuum:
runs-on: ubuntu-latest
env:
VACUUM_VERSION: "v0.14.3"

steps:
- name: Checkout gosplitsies
uses: actions/checkout@v4

- name: Get the GOCACHE Environment Variable
id: gocache
run: |
echo "GOCACHE=$(go env GOCACHE)" >> "$GITHUB_OUTPUT"
- name: Get the GOMODCACHE Environment Variable
id: gomodcache
run: |
echo "GOMODCACHE=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT"
- name: Cache Go Modules
uses: actions/cache@v4
with:
path: |
${{ steps.gocache.outputs.GOCACHE }}
${{ needs.gomodcache.outputs.GOMODCACHE }}
key: ${{ env.VACUUM_VERSION }}

- name: Setup Go
uses: actions/setup-go@v5
with:
cache: false
check-latest: true
go-version: stable

- name: Install vacuum
run: |
go install "github.com/daveshanley/vacuum@$VACUUM_VERSION"
- name: Lint the OpenAPI Description
run: |
vacuum lint --no-style openapi.yaml
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@ go.work.sum
.env

!.vscode/

# Go ignores
gsplit
gsplit.debug
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ SPDX-FileCopyrightText: 2024 Tristan Partin <tristan@partin.io>

# gosplitsies

## server

### Building

```shell
# Release
just build
# Debug
just debug
```

## ui

### Setup
Expand Down
16 changes: 11 additions & 5 deletions REUSE.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# SPDX-FileCopyrightText: 2024 Tristan Partin <tristan@partin.io>

version = 1
SPDX-HomePage = "https://github.com/return0software/gosplitsies"
SPDX-PackageName = "gosplitsies"

[[annotations]]
path = [
".vscode/copyright.code-snippets",
"ui/package.json",
"ui/package-lock.json",
]
precedence = "override"
SPDX-FileCopyrightText = "2024 Joseph Martinsen <joseph@martinsen.com>"
SPDX-License-Identifier = "AGPL-3.0-or-later"

[[annotations]]
path = [
".vscode/copyright.code-snippets",
"go.mod",
"go.sum",
"VERSION",
]
precedence = "override"
SPDX-FileCopyrightText = "2024 Tristan Partin <tristan@partin.io>"
SPDX-License-Identifier = "AGPL-3.0-or-later"
1 change: 1 addition & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.0.0
118 changes: 118 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/* SPDX-License-Identifier: AGPL-3.0-or-later
*
* SPDX-FileCopyrightText: 2024 Tristan Partin <tristan@partin.io>
*/

package cmd

import (
"fmt"
"os"
"strings"

"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)

var debug string
var configFile string
var zapConfig zap.Config

var rootCmd = &cobra.Command{
Use: "gsplit",
Short: "GoSplitsies is a pay splitting application",
}

func init() {
cobra.OnInitialize(initConfig)

rootCmd.AddCommand(versionCmd)
rootCmd.AddCommand(serverCmd)

rootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "", "Path to a config file")
rootCmd.PersistentFlags().StringP("log-filepath", "l", "", "Path to log to if log-location is file")
rootCmd.PersistentFlags().String("log-location", "stderr", "Location to send logs to")

serverCmd.Flags().Uint16P("port", "p", 5431, "Port to start the server on")

flags := map[string]*pflag.Flag{
"log.filepath": rootCmd.PersistentFlags().Lookup("log-filepath"),
"log.location": rootCmd.PersistentFlags().Lookup("log-location"),

"server.port": serverCmd.Flags().Lookup("port"),
}
for key, flag := range flags {
if err := viper.BindPFlag(key, flag); err != nil {
fmt.Fprintf(os.Stderr, "failed to bind flags for configuration purposes: %s\n", err)
os.Exit(1)
}
}
}

func initConfig() {
if configFile != "" {
viper.SetConfigFile(configFile)
} else {
viper.SetConfigName("gosplitsies")
viper.SetConfigType("yaml")

// TODO: Windows and macOS?
viper.AddConfigPath("/etc")
}

viper.SetEnvPrefix("gsplit")
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_", ".", "_"))
viper.AutomaticEnv()

if err := viper.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); !ok && configFile != "" {
fmt.Fprintf(os.Stderr, "failed to read in config: %s\n", err)
os.Exit(1)
}
}

if debug == "true" {
zapConfig = zap.NewDevelopmentConfig()
zapConfig.Level.SetLevel(zapcore.DebugLevel)
} else {
zapConfig = zap.NewProductionConfig()
zapConfig.Level.SetLevel(zapcore.InfoLevel)
}

logLocation := viper.GetString("log.location")
if logLocation == "file" {
logFilepath := viper.GetString("log.filepath")
if logFilepath == "" {
fmt.Fprintln(os.Stderr, "no log filepath provided")
os.Exit(1)
}

zapConfig.OutputPaths = []string{logFilepath}
} else if logLocation == "stdout" {
zapConfig.OutputPaths = []string{"stdout"}
} else if logLocation == "stderr" {
// Nothing to do since this is the default
} else if logLocation == "syslog" { //nolint:staticcheck
// TODO: Fail this if macOS or Windows
// TODO: Also, actually implement this
}

logger, err := zapConfig.Build()
if err != nil {
fmt.Fprintln(os.Stderr, "failed to initialize logger")
}
//nolint:errcheck
defer logger.Sync()

zap.ReplaceGlobals(logger)
}

func Execute() {
if err := rootCmd.Execute(); err != nil {
zap.S().Error("%s", err)
os.Exit(1)
}
}
46 changes: 46 additions & 0 deletions cmd/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* SPDX-License-Identifier: AGPL-3.0-or-later
*
* SPDX-FileCopyrightText: 2024 Tristan Partin <tristan@partin.io>
*/

package cmd

import (
"fmt"
"net"
"net/http"
"os"

"github.com/Return0Software/gosplitsies/middleware"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tristan957/go-sd-notify"
"go.uber.org/zap"
)

var serverCmd = &cobra.Command{
Use: "server",
Short: "Start the server",
Run: func(cmd *cobra.Command, args []string) {
mux := http.NewServeMux()

mux.HandleFunc("/logs/level", zapConfig.Level.ServeHTTP)

port := viper.GetUint16("server.port")
zap.S().Infof("Starting server on port %d", port)

listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil {
zap.S().Fatalf("failed to begin listening on port %d: %s", port, err)
os.Exit(1)
}

_ = notify.Ready()

if err := http.Serve(listener, middleware.NewLogger(mux)); err != nil {
zap.S().Fatalf("failed to start the server: %s", err)
_ = notify.Stopping()
os.Exit(1)
}
},
}
26 changes: 26 additions & 0 deletions cmd/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* SPDX-License-Identifier: AGPL-3.0-or-later
*
* SPDX-FileCopyrightText: 2024 Tristan Partin <tristan@partin.io>
*/

package cmd

import (
"fmt"

"github.com/spf13/cobra"
)

var version string

var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version",
Run: func(cmd *cobra.Command, args []string) {
if debug == "true" {
fmt.Println(version)
} else {
fmt.Printf("%s debug\n", version)
}
},
}
Loading

0 comments on commit 72e1e4e

Please sign in to comment.