Initial commit

main
Sean Hickey 2022-11-09 01:06:01 -08:00
commit e02498ec0e
10 changed files with 220 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
# Emacs
*~
# Build output
*.test

24
License.md Normal file
View File

@ -0,0 +1,24 @@
# BSD 2-Clause License
Copyright (c) 2022, Sean Hickey (Wisellama)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

11
Makefile Normal file
View File

@ -0,0 +1,11 @@
all: linter test
test:
go test
lint: linter
linter:
golangci-lint run
goimports_everything:
find . -name "*.go" -exec goimports -w {} \;

13
Readme.md Normal file
View File

@ -0,0 +1,13 @@
# gopackagebase
```sh
go get git.wisellama.rocks/Wisellama/gopackagebase@v0.0.1
```
This modules contains basic setup and initialization functions that
are useful to run at the beginning of a program. This integrates with
[gosimpleconf][1] to also support parsing config files.
I wanted to create this package to centralize some of the basic setup
boilerplate I had started to collect in my Go projects. This
repository may be considered an anti-pattern, but it fits my use-case.

5
go.mod Normal file
View File

@ -0,0 +1,5 @@
module git.wisellama.rocks/gopackagebase
go 1.17
require git.wisellama.rocks/Wisellama/gosimpleconf v0.1.0

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
git.wisellama.rocks/Wisellama/gosimpleconf v0.1.0 h1:Z2FAzARct8ShV4NSueC/y+PyuSQVcyo4WnW7GoZ9L10=
git.wisellama.rocks/Wisellama/gosimpleconf v0.1.0/go.mod h1:Gg1vUTBRZD7qcXvdF8L50PsnL9coLt/XbWa5BwSDN/M=

53
gopackagebase.go Normal file
View File

@ -0,0 +1,53 @@
package gopackagebase
import (
"context"
"log"
"git.wisellama.rocks/Wisellama/gosimpleconf"
)
type BaseConfig struct {
Ctx context.Context
Cancel func()
ConfigMap gosimpleconf.ConfigMap
}
// Initialize will configure all of the base stuff that we want
// commonly set up at the beginning of a Go project.
func Initialize(configFile string, defaultConfig gosimpleconf.ConfigMap) (*BaseConfig, error) {
var err error
ctx, cancel := InitSignalHandler()
err = InitRNG()
if err != nil {
return nil, err
}
configMap, err := gosimpleconf.ConfigureWithDefaults(configFile, defaultConfig)
if err != nil {
log.Fatalf("error during configure: %v\n", err)
}
writeToFile := gosimpleconf.Bool(configMap["log.writeToFile"])
logFilename := configMap["log.file"]
logWriter, err := SetupLogging(writeToFile, logFilename)
if err != nil {
return nil, err
}
fullCancel := func() {
logWriter.Cleanup()
cancel()
}
baseConfig := BaseConfig{
Ctx: ctx,
Cancel: fullCancel,
ConfigMap: configMap,
}
return &baseConfig, nil
}

43
logging.go Normal file
View File

@ -0,0 +1,43 @@
package gopackagebase
import (
"fmt"
"log"
"os"
"time"
)
type logWriter struct {
writeToFile bool
logFile *os.File
}
func (w *logWriter) Write(bytes []byte) (int, error) {
t := time.Now().UTC().Format(time.RFC3339)
return fmt.Fprintf(w.logFile, "%v %v", t, string(bytes))
}
func (w *logWriter) Cleanup() {
defer w.logFile.Close()
}
func SetupLogging(writeToFile bool, logFilename string) (*logWriter, error) {
var err error
log.SetFlags(0)
logFile := os.Stdout
if writeToFile {
logFile, err = os.OpenFile(logFilename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return nil, err
}
}
writer := &logWriter{
writeToFile: writeToFile,
logFile: logFile,
}
log.SetOutput(writer)
return writer, nil
}

24
random.go Normal file
View File

@ -0,0 +1,24 @@
package gopackagebase
import (
crypto_rand "crypto/rand"
"encoding/binary"
"fmt"
math_rand "math/rand"
)
// InitRNG will grab some cryptographically secure bytes to use as the
// seed for the non-crypto random number generator. Suggested on
// StackOverflow to avoid time-based seeds:
// https://stackoverflow.com/a/54491783
func InitRNG() error {
var b [8]byte
_, err := crypto_rand.Read(b[:])
if err != nil {
err = fmt.Errorf("error seeding random number generator: %w", err)
return err
}
math_rand.Seed(int64(binary.LittleEndian.Uint64(b[:])))
return nil
}

40
sighandler.go Normal file
View File

@ -0,0 +1,40 @@
package gopackagebase
import (
"context"
"log"
"os"
"os/signal"
)
func InitSignalHandler() (context.Context, func()) {
// Setup some initial context for gracefully killing the program
// with system interrupt signals like ctrl+c
// https://pace.dev/blog/2020/02/17/repond-to-ctrl-c-interrupt-signals-gracefully-with-context-in-golang-by-mat-ryer.html
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt)
// Start a goroutine to listen for signal interrupts
go func() {
select {
case <-signalChan:
// Graceful exit on ctrl+c
log.Printf("Attempting to exit gracefully...\n")
cancel()
case <-ctx.Done():
}
<-signalChan // Hard exit on second ctrl+c
log.Printf("Hard kill\n")
os.Exit(2)
}()
// Return a new cancel function that also sends the stop signal.
killFunc := func() {
signal.Stop(signalChan)
cancel()
}
return ctx, killFunc
}