9 Commits
github ... mux

Author SHA1 Message Date
2b66c57f4c fix more liniting errors 2025-12-23 14:33:35 +01:00
38d3d2c442 fix liniting bugs 2025-12-23 14:30:37 +01:00
b4fa28d0c5 replace fiber with http.ServeMux 2025-12-23 14:24:04 +01:00
37c7e808ed replace the fiber framework with net/http.ServeMux 2025-12-23 13:33:05 +01:00
5a705b0af0 fix links 2025-11-05 08:59:43 +01:00
7129f644d3 fix changelog link 2025-11-05 08:47:43 +01:00
9cb5a4b800 add test dependencies, separate test ci 2025-11-03 10:43:06 +01:00
53d69b5278 add dist makefile 2025-11-03 10:01:24 +01:00
T. von Dein
a16b9e796c move to codeberg (#22) 2025-11-03 09:15:27 +01:00
30 changed files with 522 additions and 405 deletions

View File

@@ -1,56 +0,0 @@
name: build-and-test
#on: [push]
on:
pull_request:
branches:
- main
push:
branches:
- main
jobs:
build:
strategy:
matrix:
version: ['1.24']
os: [ubuntu-latest, macos-latest, windows-latest]
name: Build
runs-on: ${{ matrix.os }}
steps:
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: ${{ matrix.version }}
id: go
- name: checkout
uses: actions/checkout@v5
- name: build
run: go build
- name: test
run: make test
- name: Update coverage report
uses: ncruces/go-coverage-report@main
with:
report: true
chart: true
amend: true
if: |
matrix.os == 'ubuntu-latest' &&
github.event_name == 'push'
continue-on-error: true
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v6
with:
go-version: 1.24
- uses: actions/checkout@v5
- name: golangci-lint
uses: golangci/golangci-lint-action@v8

View File

@@ -1,34 +0,0 @@
name: build-push-image
on:
push:
tags:
- 'v*'
jobs:
build-and-push-image:
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Log in to the Container registry
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef
with:
registry: https://ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
with:
push: true
tags: ghcr.io/tlinden/anydb:${{ github.ref_name}}
- name: Build and push latest Docker image
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
with:
push: true
tags: ghcr.io/tlinden/anydb:latest

View File

@@ -1,87 +0,0 @@
name: build-release
on:
push:
tags:
- "v*.*.*"
jobs:
release:
name: Build Release Assets
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Set up Go
uses: actions/setup-go@v6
with:
go-version: 1.24.1
- name: Build the executables
run: ./mkrel.sh anydb ${{ github.ref_name}}
- name: List the executables
run: ls -l ./releases
- name: Upload the binaries
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref_name }}
file: ./releases/*
file_glob: true
- name: Build Changelog
id: github_release
uses: mikepenz/release-changelog-builder-action@v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
mode: "PR"
configurationJson: |
{
"template": "#{{CHANGELOG}}\n\n**Full Changelog**: #{{RELEASE_DIFF}}",
"pr_template": "- #{{TITLE}} (##{{NUMBER}}) by #{{AUTHOR}}\n#{{BODY}}",
"empty_template": "- no changes",
"categories": [
{
"title": "## New Features",
"labels": ["add", "feature"]
},
{
"title": "## Bug Fixes",
"labels": ["fix", "bug", "revert"]
},
{
"title": "## Documentation Enhancements",
"labels": ["doc"]
},
{
"title": "## Refactoring Efforts",
"labels": ["refactor"]
},
{
"title": "## Miscellaneus Changes",
"labels": []
}
],
"ignore_labels": [
"duplicate", "good first issue", "help wanted", "invalid", "question", "wontfix"
],
"label_extractor": [
{
"pattern": "(.) (.+)",
"target": "$1"
},
{
"pattern": "(.) (.+)",
"target": "$1",
"on_property": "title"
}
]
}
- name: Create Release
uses: softprops/action-gh-release@v2
with:
body: ${{steps.github_release.outputs.changelog}}

69
.goreleaser.yaml Normal file
View File

@@ -0,0 +1,69 @@
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
version: 2
before:
hooks:
- go mod tidy
gitea_urls:
api: https://codeberg.org/api/v1
download: https://codeberg.org
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
- freebsd
archives:
- formats: [tar.gz]
# this name template makes the OS and Arch compatible with the results of `uname`.
name_template: >-
{{ .ProjectName }}_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}_{{ .Tag }}
# use zip for windows archives
format_overrides:
- goos: windows
formats: [zip]
- goos: linux
formats: [tar.gz,binary]
files:
- src: "*.md"
strip_parent: true
- src: "docs/*"
strip_parent: true
- src: Makefile.dist
dst: Makefile
wrap_in_directory: true
changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"
groups:
- title: Improved
regexp: '^.*?(feat|add|new)(\([[:word:]]+\))??!?:.+$'
order: 0
- title: Fixed
regexp: '^.*?(bug|fix)(\([[:word:]]+\))??!?:.+$'
order: 1
- title: Changed
order: 999
release:
header: "# Release Notes"
footer: >-
---
Full Changelog: [{{ .PreviousTag }}...{{ .Tag }}](https://codeberg.org/scip/anydb/compare/{{ .PreviousTag }}...{{ .Tag }})

36
.woodpecker/build.yaml Normal file
View File

@@ -0,0 +1,36 @@
matrix:
platform:
- linux/amd64
goversion:
- 1.24
labels:
platform: ${platform}
steps:
build:
when:
event: [push]
image: golang:${goversion}
commands:
- go get
- go build
linter:
when:
event: [push]
image: golang:${goversion}
commands:
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.5.0
- golangci-lint --version
- golangci-lint run ./...
depends_on: [build]
test:
when:
event: [push]
image: golang:${goversion}
commands:
- go get
- go test -v -cover
depends_on: [build,linter]

32
.woodpecker/image.yaml Normal file
View File

@@ -0,0 +1,32 @@
# https://woodpecker-ci.org/plugins/docker-buildx
# enable Package unit and go to /scip/-/packages after building to link to proj
variables:
- &repo codeberg.org/${CI_REPO_OWNER}/anydb
steps:
dryrun:
image: docker.io/woodpeckerci/plugin-docker-buildx:latest
settings:
dockerfile: Dockerfile
platforms: linux/amd64
dry_run: true
repo: *repo
tags: latest
when:
event: [pull_request]
publish:
image: docker.io/woodpeckerci/plugin-docker-buildx:latest
settings:
dockerfile: Dockerfile
platforms: linux/amd64
repo: *repo
registry: codeberg.org
tags: latest,${CI_COMMIT_SHA:0:8},${CI_COMMIT_TAG}
username: ${CI_REPO_OWNER}
password:
from_secret: REGISTRY_TOKEN
when:
event: [tag]
branch: main

15
.woodpecker/release.yaml Normal file
View File

@@ -0,0 +1,15 @@
# build release
labels:
platform: linux/amd64
steps:
goreleaser:
image: goreleaser/goreleaser
when:
event: [tag]
environment:
GITEA_TOKEN:
from_secret: DEPLOY_TOKEN
commands:
- goreleaser release --clean --verbose

View File

@@ -51,11 +51,11 @@ endif
app/dbentry.pb.go: app/dbentry.proto
protoc -I=. --go_out=app app/dbentry.proto
mv app/github.com/tlinden/anydb/app/dbentry.pb.go app/dbentry.pb.go
mv app/codeberg.org/scip/anydb/app/dbentry.pb.go app/dbentry.pb.go
rm -rf app/github.com
buildlocal:
go build -ldflags "-X 'github.com/tlinden/anydb/cfg.VERSION=$(VERSION)'"
go build -ldflags "-X 'codeberg.org/scip/anydb/cfg.VERSION=$(VERSION)'"
# binaries are being built by ci workflow on tag creation
release:
@@ -75,7 +75,7 @@ test: clean
singletest:
@echo "Call like this: ''make singletest TEST=TestPrepareColumns MOD=lib"
ANYDB_PASSWORD=test go test -run $(TEST) github.com/tlinden/anydb/$(MOD)
ANYDB_PASSWORD=test go test -run $(TEST) codeberg.org/scip/anydb/$(MOD)
cover-report:
go test ./... -cover -coverprofile=coverage.out

20
Makefile.dist Normal file
View File

@@ -0,0 +1,20 @@
# -*-make-*-
.PHONY: install all
tool = rpn
PREFIX = /usr/local
UID = root
GID = 0
all:
@echo "Type 'sudo make install' to install the tool."
@echo "To change prefix, type 'sudo make install PREFIX=/opt'"
install:
install -d -o $(UID) -g $(GID) $(PREFIX)/bin
install -d -o $(UID) -g $(GID) $(PREFIX)/man/man1
install -d -o $(UID) -g $(GID) $(PREFIX)/share/doc
install -o $(UID) -g $(GID) -m 555 $(tool) $(PREFIX)/sbin/
install -o $(UID) -g $(GID) -m 444 $(tool).1 $(PREFIX)/man/man1/
install -o $(UID) -g $(GID) -m 444 *.md $(PREFIX)/share/doc/

View File

@@ -1,11 +1,10 @@
## A personal key value store
[![Actions](https://github.com/tlinden/anydb/actions/workflows/ci.yaml/badge.svg)](https://github.com/tlinden/anydb/actions)
[![License](https://img.shields.io/badge/license-GPL-blue.svg)](https://github.com/tlinden/anydb/blob/master/LICENSE)
[![Go Coverage](https://github.com/tlinden/anydb/wiki/coverage.svg)](https://raw.githack.com/wiki/tlinden/anydb/coverage.html)
[![Go Report Card](https://goreportcard.com/badge/github.com/tlinden/anydb)](https://goreportcard.com/report/github.com/tlinden/anydb)
[![GitHub release](https://img.shields.io/github/v/release/tlinden/anydb?color=%2300a719)](https://github.com/TLINDEN/anydb/releases/latest)
[![Documentation](https://img.shields.io/badge/manpage-documentation-blue)](https://github.com/TLINDEN/anydb/blob/master/anydb.pod)
[![status-badge](https://ci.codeberg.org/api/badges/15517/status.svg)](https://ci.codeberg.org/repos/15517)
[![License](https://img.shields.io/badge/license-GPL-blue.svg)](https://codeberg.org/scip/anydb/blob/master/LICENSE)
[![Go Report Card](https://goreportcard.com/badge/codeberg.org/scip/anydb)](https://goreportcard.com/report/codeberg.org/scip/anydb)
[![GitHub release](https://img.shields.io/github/v/release/tlinden/anydb?color=%2300a719)](https://codeberg.org/scip/anydb/releases)
[![Documentation](https://img.shields.io/badge/manpage-documentation-blue)](https://codeberg.org/scip/anydb/raw/branch/main/anydb.pod)
> [!CAUTION]
> Between version 0.1.0 and version 0.2.1 deletion of keys did not work. There
@@ -14,7 +13,7 @@
> upgrade to 0.2.1 and above.
> [!CAUTION]
> Version 0.1.3 introduced a [regression](https://github.com/TLINDEN/anydb/issues/19),
> Version 0.1.3 introduced a [regression](https://codeberg.org/scip/anydb/issues/19),
> which caused the encryption feature not to work correctly anymore.
> If you are using anydb 0.1.3, you are urgently advised to
> upgrade to 0.2.0
@@ -47,17 +46,17 @@ And I wrote a very similar [tool](https://www.daemon.de/projects/dbtool/) 24 yea
**anydb** can do all the things you can do with skate:
![simple demo](https://github.com/TLINDEN/anydb/blob/main/demo/intro.gif)
![simple demo](https://codeberg.org/scip/anydb/raw/branch/main/demo/intro.gif)
However, there are more features than just that!
![advanced demo](https://github.com/TLINDEN/anydb/blob/main/demo/advanced.gif)
![advanced demo](https://codeberg.org/scip/anydb/raw/branch/main/demo/advanced.gif)
## Installation
There are multiple ways to install **anydb**:
- Go to the [latest release page](https://github.com/tlinden/anydb/releases/latest),
- Go to the [latest release page](https://codeberg.org/scip/anydb/releases),
locate the binary for your operating system and platform.
Download it and put it into some directory within your `$PATH` variable.
@@ -70,7 +69,7 @@ There are multiple ways to install **anydb**:
- You can also install from source. Issue the following commands in your shell:
```shell
git clone https://github.com/TLINDEN/anydb.git
git clone https://codeberg.org/scip/anydb.git
cd anydb
make
sudo make install
@@ -78,7 +77,7 @@ There are multiple ways to install **anydb**:
- Or, if you have the GO toolkit installed, just install it like this:
```shell
go install github.com/tlinden/anydb@latest
go install codeberg.org/scip/anydb@latest
```
If you do not find a binary release for your platform, please don't
@@ -105,14 +104,14 @@ Here, we operate in a local directory `mydb`, which we'll use as HOME
inside the docker container. anydb will store its database in
`mydb/.config/anydb/default.db`.
A list of available images is [here](https://github.com/tlinden/anydb/pkgs/container/anydb/versions?filters%5Bversion_type%5D=tagged)
A list of available images is [here](https://codeberg.org/scip/anydb/pkgs/container/anydb/versions?filters%5Bversion_type%5D=tagged)
## Documentation
The documentation is provided as a unix man-page. It will be
automatically installed if you install from source. However, you can
[read the man-page online](https://github.com/TLINDEN/anydb/blob/master/anydb.pod)
[read the man-page online](https://codeberg.org/scip/anydb/blob/master/anydb.pod)
Or if you cloned the repository you can read it this way (perl needs
to be installed though): `perldoc anydb.pod`.
@@ -129,7 +128,7 @@ best way for me to forget to do something.
In order to report a bug, unexpected behavior, feature requests or to
submit a patch, please open an issue on github:
https://github.com/TLINDEN/anydb/issues.
https://codeberg.org/scip/anydb/issues.
## Copyright and license
@@ -141,7 +140,7 @@ T.v.Dein <tom AT vondein DOT org>
## Project homepage
https://github.com/TLINDEN/anydb
https://codeberg.org/scip/anydb
## Copyright and License

View File

@@ -1,4 +1,4 @@
.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40)
.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.42)
.\"
.\" Standard preamble:
.\" ========================================================================
@@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "ANYDB 1"
.TH ANYDB 1 "2025-02-11" "1" "User Commands"
.TH ANYDB 1 "2025-11-03" "1" "User Commands"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
@@ -746,7 +746,7 @@ List all keys:
.IX Header "BUGS"
In order to report a bug, unexpected behavior, feature requests
or to submit a patch, please open an issue on github:
<https://github.com/TLINDEN/anydb/issues>.
<https://codeberg.org/scip/anydb/issues>.
.PP
Please repeat the failing command with debugging enabled \f(CW\*(C`\-d\*(C'\fR and
include the output in the issue.

View File

@@ -569,7 +569,7 @@ Some curl example calls to the API:
Post a new key:
curl -X PUT localhost:8787/anydb/v1/ \
-H 'Content-Type: application/json' \
-d '{"key":"foo","val":"bar"}'
-d '{"key":"foo","data":"bar"}'
Retrieve the value:
@@ -579,11 +579,16 @@ List all keys:
curl localhost:8787/anydb/v1/
Delete an entry:
curl -s -X DELETE http://localhost:8787/anydb/v1/foo
=head1 BUGS
In order to report a bug, unexpected behavior, feature requests
or to submit a patch, please open an issue on github:
L<https://github.com/TLINDEN/anydb/issues>.
L<https://codeberg.org/scip/anydb/issues>.
Please repeat the failing command with debugging enabled C<-d> and
include the output in the issue.

View File

@@ -1,5 +1,5 @@
/*
Copyright © 2024 Thomas von Dein
Copyright © 2024-2025 Thomas von Dein
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -28,6 +28,7 @@ type DbAttr struct {
Key string
Preview string
Val []byte
Data string // alias
Args []string
Tags []string
File string
@@ -63,6 +64,12 @@ func (attr *DbAttr) ParseKV() error {
}
}
attr.SetPreview()
return nil
}
func (attr *DbAttr) SetPreview() {
switch {
case attr.Binary:
attr.Preview = "<binary-content>"
@@ -82,8 +89,6 @@ func (attr *DbAttr) ParseKV() error {
attr.Preview = string(attr.Val)
}
}
return nil
}
func (attr *DbAttr) GetFileValue() error {

View File

@@ -28,7 +28,7 @@ import (
"strings"
"time"
common "github.com/tlinden/anydb/common"
common "codeberg.org/scip/anydb/common"
bolt "go.etcd.io/bbolt"
"google.golang.org/protobuf/proto"

View File

@@ -5,7 +5,7 @@ package app;
import "google/protobuf/timestamp.proto";
option go_package = "github.com/tlinden/anydb/app";
option go_package = "codeberg.org/scip/anydb/app";
message DbEntry {
string Id = 1;

View File

@@ -19,14 +19,18 @@ package cfg
import (
"fmt"
"io"
"log/slog"
"os"
"runtime/debug"
"codeberg.org/scip/anydb/app"
"codeberg.org/scip/anydb/common"
"github.com/lmittmann/tint"
"github.com/pelletier/go-toml"
"github.com/tlinden/anydb/app"
"github.com/tlinden/anydb/common"
"github.com/tlinden/yadu"
)
var Version string = "v0.2.6"
var Version string = "v0.3.0"
type BucketConfig struct {
Encrypt bool
@@ -58,6 +62,8 @@ func (conf *Config) GetConfig(files []string) error {
}
}
conf.SetLogger()
return nil
}
@@ -114,3 +120,36 @@ func (conf *Config) ParseConfigFile(file string) error {
return nil
}
func (conf *Config) SetLogger() {
if conf.Debug {
buildInfo, _ := debug.ReadBuildInfo()
opts := &yadu.Options{
Level: slog.LevelDebug,
AddSource: true,
}
slog.SetLogLoggerLevel(slog.LevelDebug)
handler := yadu.NewHandler(os.Stdout, opts)
debuglogger := slog.New(handler).With(
slog.Group("program_info",
slog.Int("pid", os.Getpid()),
slog.String("go_version", buildInfo.GoVersion),
),
)
slog.SetDefault(debuglogger)
slog.Debug("parsed config", "conf", conf)
} else {
opts := &tint.Options{
Level: slog.LevelInfo,
AddSource: false,
}
handler := tint.NewHandler(os.Stderr, opts)
logger := slog.New(handler)
slog.SetDefault(logger)
}
}

View File

@@ -517,7 +517,7 @@ REST API
BUGS
In order to report a bug, unexpected behavior, feature requests or to
submit a patch, please open an issue on github:
<https://github.com/TLINDEN/anydb/issues>.
<https://codeberg.org/scip/anydb/issues>.
Please repeat the failing command with debugging enabled "-d" and
include the output in the issue.

View File

@@ -1,5 +1,5 @@
/*
Copyright © 2024 Thomas von Dein
Copyright © 2024-2025 Thomas von Dein
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,10 +21,10 @@ import (
"os"
"strings"
"codeberg.org/scip/anydb/app"
"codeberg.org/scip/anydb/cfg"
"codeberg.org/scip/anydb/output"
"github.com/spf13/cobra"
"github.com/tlinden/anydb/app"
"github.com/tlinden/anydb/cfg"
"github.com/tlinden/anydb/output"
)
func Set(conf *cfg.Config) *cobra.Command {

View File

@@ -26,10 +26,10 @@ import (
"os/exec"
"github.com/spf13/cobra"
"github.com/tlinden/anydb/app"
"github.com/tlinden/anydb/cfg"
"github.com/tlinden/anydb/output"
"github.com/tlinden/anydb/rest"
"codeberg.org/scip/anydb/app"
"codeberg.org/scip/anydb/cfg"
"codeberg.org/scip/anydb/output"
"codeberg.org/scip/anydb/rest"
)
func Export(conf *cfg.Config) *cobra.Command {

View File

@@ -25,8 +25,8 @@ import (
"runtime/debug"
"github.com/spf13/cobra"
"github.com/tlinden/anydb/app"
"github.com/tlinden/anydb/cfg"
"codeberg.org/scip/anydb/app"
"codeberg.org/scip/anydb/cfg"
"github.com/tlinden/yadu"
)

View File

@@ -177,6 +177,6 @@ Enter
Sleep 3s
Enter
Type "# Try it out yourself: github.com/tlinden/anydb!"
Type "# Try it out yourself: codeberg.org/scip/anydb!"
Enter
Sleep 4s

11
go.mod
View File

@@ -1,4 +1,4 @@
module github.com/tlinden/anydb
module codeberg.org/scip/anydb
go 1.24.0
@@ -6,8 +6,8 @@ toolchain go1.24.1
require (
github.com/dustin/go-humanize v1.0.1
github.com/gofiber/fiber/v2 v2.52.9
github.com/inconshreveable/mousetrap v1.1.0
github.com/lmittmann/tint v1.1.2
github.com/olekukonko/tablewriter v1.1.0
github.com/pelletier/go-toml v1.9.5
github.com/rogpeppe/go-internal v1.14.1
@@ -20,10 +20,8 @@ require (
)
require (
github.com/andybalholm/brotli v1.1.1 // indirect
github.com/alecthomas/repr v0.5.2 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
@@ -31,9 +29,6 @@ require (
github.com/olekukonko/ll v0.0.9 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/spf13/pflag v1.0.9 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.55.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/sys v0.36.0 // indirect
golang.org/x/tools v0.26.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

20
go.sum
View File

@@ -1,5 +1,5 @@
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -7,16 +7,12 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/gofiber/fiber/v2 v2.52.9 h1:YjKl5DOiyP3j0mO61u3NTmK7or8GzzWzCFzkboyP5cw=
github.com/gofiber/fiber/v2 v2.52.9/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/lmittmann/tint v1.1.2 h1:2CQzrL6rslrsyjqLDwD11bZ5OpLBPU+g3G/r5LSfS8w=
github.com/lmittmann/tint v1.1.2/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -46,14 +42,6 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tlinden/yadu v0.1.3 h1:5cRCUmj+l5yvlM2irtpFBIJwVV2DPEgYSaWvF19FtcY=
github.com/tlinden/yadu v0.1.3/go.mod h1:l3bRmHKL9zGAR6pnBHY2HRPxBecf7L74BoBgOOpTcUA=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8=
github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=

View File

@@ -24,7 +24,7 @@ import (
"runtime"
"github.com/inconshreveable/mousetrap"
"github.com/tlinden/anydb/cmd"
"codeberg.org/scip/anydb/cmd"
)
func main() {

View File

@@ -21,8 +21,8 @@ import (
"fmt"
"os"
"github.com/tlinden/anydb/app"
"github.com/tlinden/anydb/cfg"
"codeberg.org/scip/anydb/app"
"codeberg.org/scip/anydb/cfg"
)
func WriteJSON(attr *app.DbAttr, conf *cfg.Config, entries app.DbEntries) error {

View File

@@ -30,8 +30,8 @@ import (
"github.com/olekukonko/tablewriter"
"github.com/olekukonko/tablewriter/renderer"
"github.com/olekukonko/tablewriter/tw"
"github.com/tlinden/anydb/app"
"github.com/tlinden/anydb/cfg"
"codeberg.org/scip/anydb/app"
"codeberg.org/scip/anydb/cfg"
)
func List(writer io.Writer, conf *cfg.Config, entries app.DbEntries) error {

View File

@@ -25,8 +25,8 @@ import (
"reflect"
"github.com/dustin/go-humanize"
"github.com/tlinden/anydb/app"
"github.com/tlinden/anydb/cfg"
"codeberg.org/scip/anydb/app"
"codeberg.org/scip/anydb/cfg"
"golang.org/x/term"
//"github.com/alecthomas/repr"
)

View File

@@ -1,5 +1,5 @@
/*
Copyright © 2024 Thomas von Dein
Copyright © 2024-2025 Thomas von Dein
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,9 +19,12 @@ package rest
import (
//"github.com/alecthomas/repr"
"github.com/gofiber/fiber/v2"
"github.com/tlinden/anydb/app"
"github.com/tlinden/anydb/cfg"
"encoding/json"
"log"
"net/http"
"codeberg.org/scip/anydb/app"
"codeberg.org/scip/anydb/cfg"
)
type SetContext struct {
@@ -40,101 +43,113 @@ type SingleResponse struct {
Entry *app.DbEntry
}
func RestList(c *fiber.Ctx, conf *cfg.Config) error {
func RestList(resp http.ResponseWriter, req *http.Request, conf *cfg.Config) {
attr := new(app.DbAttr)
if len(c.Body()) > 0 {
if err := c.BodyParser(attr); err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{
"errors": err.Error(),
})
err := json.NewDecoder(req.Body).Decode(&attr)
if err != nil {
if err.Error() != `EOF` {
http.Error(resp, err.Error(), http.StatusBadRequest)
return
}
}
// get list
entries, err := conf.DB.List(attr, attr.Fulltext)
if err != nil {
return JsonStatus(c, fiber.StatusForbidden,
"Unable to list keys: "+err.Error())
JsonStatus(resp, http.StatusForbidden, "Unable to list keys: "+err.Error())
return
}
return c.Status(fiber.StatusOK).JSON(
resp.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(resp).Encode(
ListResponse{
Code: http.StatusOK,
Success: true,
Code: fiber.StatusOK,
Entries: entries,
},
)
}
func RestGet(c *fiber.Ctx, conf *cfg.Config) error {
if c.Params("key") == "" {
return JsonStatus(c, fiber.StatusForbidden,
"key not provided")
}
// get list
entry, err := conf.DB.Get(&app.DbAttr{Key: c.Params("key")})
if err != nil {
return JsonStatus(c, fiber.StatusForbidden,
"Unable to get key: "+err.Error())
}
if entry.Key == "" {
return JsonStatus(c, fiber.StatusForbidden,
"Key does not exist")
}
return c.Status(fiber.StatusOK).JSON(
SingleResponse{
Success: true,
Code: fiber.StatusOK,
Entry: entry,
},
)
}
func RestDelete(c *fiber.Ctx, conf *cfg.Config) error {
if c.Params("key") == "" {
return JsonStatus(c, fiber.StatusForbidden,
"key not provided")
}
// get list
err := conf.DB.Del(&app.DbAttr{Key: c.Params("key")})
if err != nil {
return JsonStatus(c, fiber.StatusForbidden,
"Unable to delete key: "+err.Error())
}
return c.Status(fiber.StatusOK).JSON(
Result{
Success: true,
Code: fiber.StatusOK,
Message: "key deleted",
},
)
}
func RestSet(c *fiber.Ctx, conf *cfg.Config) error {
attr := new(app.DbAttr)
if err := c.BodyParser(attr); err != nil {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{
"errors": err.Error(),
})
}
err := conf.DB.Set(attr)
if err != nil {
return JsonStatus(c, fiber.StatusForbidden,
"Unable to set key: "+err.Error())
log.Fatal(err)
}
}
func RestGet(resp http.ResponseWriter, req *http.Request, key string, conf *cfg.Config) {
if key == "" {
JsonStatus(resp, http.StatusForbidden, "key not provided")
return
}
return c.Status(fiber.StatusOK).JSON(
Result{
// get list
entry, err := conf.DB.Get(&app.DbAttr{Key: key})
if err != nil {
JsonStatus(resp, http.StatusForbidden, "Unable to get key: "+err.Error())
return
}
if entry.Key == "" {
JsonStatus(resp, http.StatusForbidden, "Key does not exist")
return
}
resp.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(resp).Encode(
SingleResponse{
Code: http.StatusOK,
Success: true,
Code: fiber.StatusOK,
},
)
Entry: entry,
})
if err != nil {
log.Fatal(err)
}
}
func RestDelete(resp http.ResponseWriter, req *http.Request, key string, conf *cfg.Config) {
if key == "" {
JsonStatus(resp, http.StatusForbidden, "key not provided")
return
}
// get list
err := conf.DB.Del(&app.DbAttr{Key: key})
if err != nil {
JsonStatus(resp, http.StatusForbidden, "Unable to delete key: "+err.Error())
return
}
JsonStatus(resp, http.StatusOK, "key deleted")
}
func RestSet(resp http.ResponseWriter, req *http.Request, conf *cfg.Config) {
attr := new(app.DbAttr)
err := json.NewDecoder(req.Body).Decode(&attr)
if err != nil {
http.Error(resp, err.Error(), http.StatusBadRequest)
return
}
// attr.Data is a string, thus the decoder doesn't expect it to be
// base64 encoded. However, internally we need []byte, therefore
// we copy a cast to .Val. We also need to setup the .Preview
// value here.
attr.Val = []byte(attr.Data)
attr.SetPreview()
err = conf.DB.Set(attr)
if err != nil {
JsonStatus(resp, http.StatusForbidden, "Unable to set key: "+err.Error())
return
}
JsonStatus(resp, http.StatusOK, "key added/updated")
}
func Home(resp http.ResponseWriter) {
_, err := resp.Write([]byte("Use the REST API on " + apiprefix + "\r\n"))
if err != nil {
log.Fatal(err)
}
}

98
rest/log.go Normal file
View File

@@ -0,0 +1,98 @@
/*
This logging middleware is based on
https://github.com/elithrar/admission-control/blob/v0.6.3/request_logger.go
by Matt Silverlock licensed under the Apache-2.0 license.
I am using slog and added a couple of small modifications.
*/
package rest
import (
"log/slog"
"net/http"
"runtime/debug"
"time"
)
// responseWriter is a minimal wrapper for http.ResponseWriter that allows the
// written HTTP status code to be captured for logging.
type responseWriter struct {
http.ResponseWriter
status int
size int
wroteHeader bool
}
func wrapResponseWriter(w http.ResponseWriter) *responseWriter {
return &responseWriter{ResponseWriter: w}
}
func (rw *responseWriter) Status() int {
return rw.status
}
func (rw *responseWriter) Size() int {
return rw.size
}
func (rw *responseWriter) WriteHeader(code int) {
if rw.wroteHeader {
return
}
rw.status = code
rw.ResponseWriter.WriteHeader(code)
rw.wroteHeader = true
}
func (rw *responseWriter) Write(data []byte) (int, error) {
written, err := rw.ResponseWriter.Write(data)
rw.size += written
return written, err
}
// LoggingMiddleware logs the incoming HTTP request & its duration.
func LogHandler() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
fn := func(resp http.ResponseWriter, req *http.Request) {
defer func() {
if err := recover(); err != nil {
resp.WriteHeader(http.StatusInternalServerError)
slog.Info(
"internal server error",
"err", err,
"trace", string(debug.Stack()),
)
}
}()
start := time.Now()
wrapped := wrapResponseWriter(resp)
next.ServeHTTP(wrapped, req)
header := wrapped.Header()["Content-Type"]
contenttype := ""
if header == nil {
contenttype = "text/plain"
} else {
contenttype = header[0]
}
slog.Info("request",
"ip", req.RemoteAddr,
"status", wrapped.status,
"method", req.Method,
"path", req.URL.EscapedPath(),
"size", wrapped.Size(),
"content-type", contenttype,
"duration", time.Since(start),
)
}
return http.HandlerFunc(fn)
}
}

View File

@@ -1,5 +1,5 @@
/*
Copyright © 2024 Thomas von Dein
Copyright © 2024-2025 Thomas von Dein
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,11 +17,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package rest
import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/compress"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/tlinden/anydb/cfg"
"encoding/json"
"log"
"net/http"
"codeberg.org/scip/anydb/cfg"
)
// used to return to the api client
@@ -31,84 +31,62 @@ type Result struct {
Code int `json:"code"`
}
const apiprefix = `/anydb/v1/`
func Runserver(conf *cfg.Config, args []string) error {
// setup api server
router := SetupServer(conf)
mux := http.NewServeMux()
// public rest api routes
api := router.Group("/anydb/v1")
{
api.Get("/", func(c *fiber.Ctx) error {
return RestList(c, conf)
})
api.Post("/", func(c *fiber.Ctx) error {
// same thing as above but allows to supply parameters, see app.Dbattr{}
return RestList(c, conf)
})
api.Get("/:key", func(c *fiber.Ctx) error {
return RestGet(c, conf)
})
api.Delete("/:key", func(c *fiber.Ctx) error {
return RestDelete(c, conf)
})
api.Put("/", func(c *fiber.Ctx) error {
return RestSet(c, conf)
})
}
// public routes
{
router.Get("/", func(c *fiber.Ctx) error {
return c.Send([]byte("Use the REST API"))
})
}
return router.Listen(conf.Listen)
}
func SetupServer(conf *cfg.Config) *fiber.App {
// disable colors
fiber.DefaultColors = fiber.Colors{}
router := fiber.New(fiber.Config{
CaseSensitive: true,
StrictRouting: true,
Immutable: true,
ServerHeader: "anydb serve",
AppName: "anydb",
// just in case someone tries to access the non-api url
mux.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {
Home(w)
})
router.Use(logger.New(logger.Config{
Format: "${pid} ${ip}:${port} ${status} - ${method} ${path}\n",
DisableColors: true,
}))
mux.HandleFunc("GET "+apiprefix+"{$}", func(w http.ResponseWriter, r *http.Request) {
RestList(w, r, conf)
})
router.Use(cors.New(cors.Config{
AllowMethods: "GET,PUT,POST,DELETE",
ExposeHeaders: "Content-Type,Accept",
}))
mux.HandleFunc("POST "+apiprefix+"{$}", func(w http.ResponseWriter, r *http.Request) {
RestList(w, r, conf)
})
router.Use(compress.New(compress.Config{
Level: compress.LevelBestSpeed,
}))
mux.HandleFunc("GET "+apiprefix+"{key}", func(w http.ResponseWriter, r *http.Request) {
key := r.PathValue("key")
RestGet(w, r, key, conf)
})
return router
mux.HandleFunc("DELETE "+apiprefix+"{key}", func(w http.ResponseWriter, r *http.Request) {
key := r.PathValue("key")
RestDelete(w, r, key, conf)
})
mux.HandleFunc("PUT "+apiprefix, func(w http.ResponseWriter, r *http.Request) {
RestSet(w, r, conf)
})
logger := LogHandler()
return http.ListenAndServe(conf.Listen, logger(mux))
}
/*
Wrapper to respond with proper json status, message and code,
shall be prepared and called by the handlers directly.
*/
func JsonStatus(c *fiber.Ctx, code int, msg string) error {
success := code == fiber.StatusOK
func JsonStatus(resp http.ResponseWriter, code int, msg string) {
success := code == http.StatusOK
return c.Status(code).JSON(Result{
Code: code,
Message: msg,
Success: success,
})
resp.Header().Set("Content-Type", "application/json")
resp.WriteHeader(code)
err := json.NewEncoder(resp).Encode(
Result{
Code: code,
Message: msg,
Success: success,
})
if err != nil {
log.Fatal(err)
}
}