Skip to content

Commit 99f2e6b

Browse files
committed
Rewrite in go
1 parent 095e2b1 commit 99f2e6b

56 files changed

Lines changed: 1271 additions & 1595 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.dockerignore

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,7 @@
1-
docker-compose-prod.yml
2-
docker-compose.yml
31
Dockerfile
42
.dockerignore
5-
63
.git
74
.github
85
.gitignore
9-
10-
public
11-
pyazo_api/.env
12-
pyazo_api/*.db
13-
__pycache__
14-
156
.vscode
167
.editorconfig

.github/workflows/dockerbuild.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,18 @@ jobs:
1616
uses: actions/checkout@v6
1717

1818
- name: Set up Docker Buildx
19-
uses: docker/setup-buildx-action@v3
19+
uses: docker/setup-buildx-action@v4
2020

2121
- name: Login to Docker Hub
22-
uses: docker/login-action@v3
22+
uses: docker/login-action@v4
2323
with:
2424
username: ${{ secrets.DOCKER_USERNAME }}
2525
password: ${{ secrets.DOCKER_PASSWORD }}
2626

2727
- name: Build and push API image
28-
uses: docker/build-push-action@v6
28+
uses: docker/build-push-action@v7
2929
with:
3030
push: true
3131
tags: pyazo/api:latest
32+
cache-from: type=gha
33+
cache-to: type=gha,mode=max

.gitignore

Lines changed: 6 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,12 @@
1-
# Byte-compiled / optimized / DLL files
2-
__pycache__/
3-
*.py[cod]
4-
*$py.class
1+
# Binary
2+
/api
53

6-
# C extensions
7-
*.so
8-
9-
# Distribution / packaging
10-
.Python
11-
build/
12-
develop-eggs/
13-
dist/
14-
downloads/
15-
eggs/
16-
.eggs/
17-
lib/
18-
lib64/
19-
parts/
20-
sdist/
21-
var/
22-
wheels/
23-
pip-wheel-metadata/
24-
share/python-wheels/
25-
*.egg-info/
26-
.installed.cfg
27-
*.egg
28-
MANIFEST
29-
30-
# PyInstaller
31-
# Usually these files are written by a python script from a template
32-
# before PyInstaller builds the exe, so as to inject date/other infos into it.
33-
*.manifest
34-
*.spec
35-
36-
# Installer logs
37-
pip-log.txt
38-
pip-delete-this-directory.txt
39-
40-
# Unit test / coverage reports
41-
htmlcov/
42-
.tox/
43-
.nox/
44-
.coverage
45-
.coverage.*
46-
.cache
47-
nosetests.xml
48-
coverage.xml
49-
*.cover
50-
*.py,cover
51-
.hypothesis/
52-
.pytest_cache/
53-
cover/
54-
55-
# Translations
56-
*.mo
57-
*.pot
58-
59-
# Sphinx documentation
60-
docs/_build/
61-
62-
# PyBuilder
63-
.pybuilder/
64-
target/
65-
66-
# IPython
67-
profile_default/
68-
ipython_config.py
69-
70-
# Celery stuff
71-
celerybeat-schedule
72-
celerybeat.pid
73-
74-
# Environments
4+
# Environment
755
.env
76-
.venv
77-
env/
78-
venv/
79-
ENV/
80-
env.bak/
81-
venv.bak/
826

83-
# pytype static type analyzer
84-
.pytype/
85-
86-
# Editor settings
7+
# Editor
878
.idea
889
.vscode/
8910

90-
# Databases
91-
*.db
92-
93-
# mypy cache
94-
.mypy_cache/
95-
96-
#images
97-
bin/
11+
# OS
12+
.DS_Store

.mypy.ini

Lines changed: 0 additions & 11 deletions
This file was deleted.

CLAUDE.md

Lines changed: 19 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4,77 +4,48 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## Project Overview
66

7-
Pyazo API is a self-hosted screenshot and image upload service backend built with FastAPI. It provides REST endpoints for user authentication and image management with support for public image storage.
7+
Pyazo API is a self-hosted screenshot and image upload service backend built with Go (gin + pgx). It provides REST endpoints for user authentication and image management.
88

99
## Development Commands
1010

1111
```bash
12-
# Install dependencies (uses uv)
13-
uv sync
12+
# Build
13+
go build -o api ./cmd/
1414

15-
# Run development server
16-
uvicorn pyazo_api.run:app --reload
15+
# Run (requires PostgreSQL)
16+
POSTGRES_PASSWORD=pyazo JWT_SECRET=secret BLOCK_REGISTER=false ./api
1717

18-
# Run tests (requires PostgreSQL - see pytest.ini for test env config)
19-
pytest
20-
21-
# Run single test
22-
pytest tests/test_images.py::test_name
23-
24-
# Seed database with test data
25-
python -m pyazo_api.seed
18+
# Run tests (requires PostgreSQL)
19+
POSTGRES_PASSWORD=pyazo go test ./...
2620

2721
# Start PostgreSQL for local development
2822
docker compose up -d db
2923
```
3024

3125
## Architecture
3226

33-
The codebase follows a layered domain-driven architecture:
27+
Flat package structure with protocol-layer separation:
3428

3529
```
36-
pyazo_api/
37-
├── application/ # FastAPI app setup and HTTP layer
38-
│ ├── __init__.py # create_app() with lifespan, CORS, router registration
39-
│ ├── db.py # Connection pool (psycopg_pool) with lifespan management
40-
│ └── routers/ # API route handlers (auth, images)
41-
├── domain/ # Business logic layer
42-
│ ├── auth/ # Authentication domain
43-
│ │ ├── actions/ # login_action.py, register_action.py
44-
│ │ ├── repository.py # UserRepository
45-
│ │ └── dto.py # User DTOs (User, UserGet, UserCredentials, etc.)
46-
│ └── images/ # Images domain
47-
│ ├── actions/ # save_image.py, get_images.py, delete_image.py
48-
│ ├── repository.py # ImageRepository
49-
│ └── dto.py # Image DTO
50-
├── config/ # Pydantic Settings configuration
51-
│ ├── __init__.py # Exports `settings` singleton
52-
│ └── settings.py # Settings class with env var loading
53-
└── util/ # Shared utilities (pagination, auth helpers, http_exceptions)
30+
auth/ # JWT and argon2id password hashing (passlib-compatible)
31+
config/ # Config struct loaded from env vars
32+
db/ # pgx queries, User/Image structs
33+
http/ # gin handlers, middleware, server setup
34+
cmd/api/ # Entrypoint, embedded migrations
35+
migrations/ # SQL migration files (golang-migrate)
5436
```
5537

56-
**Key Patterns:**
57-
58-
- **Actions**: Business logic encapsulated in action classes with FastAPI `Depends()` injection
59-
- **Repositories**: Data access layer using raw SQL with psycopg3 async connection pool
60-
- **DTOs**: Pydantic models for data transfer; `User.to_public()` converts to `UserGet`
61-
- **Database**: Async connection pool via `psycopg_pool.AsyncConnectionPool` managed by FastAPI lifespan
62-
- **Configuration**: `pydantic-settings` with automatic `.env` file loading
63-
6438
## Database
6539

66-
- PostgreSQL with psycopg3 async + connection pooling
67-
- Migrations in `migrations/` (plain SQL files)
40+
- PostgreSQL with pgx + connection pooling
41+
- Migrations embedded in binary, run on startup via golang-migrate
6842
- Two tables: `users` (id, username, hashed_password) and `images` (id, owner_id, created_at)
6943

7044
## Configuration
7145

72-
Uses `pydantic-settings` for type-safe configuration. Settings loaded from environment variables and `.env` file.
73-
74-
Key settings (see `config/settings.py`):
46+
Environment variables (see `config/config.go`):
7547

7648
- `ENV`: development/testing/production
7749
- `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB`, `POSTGRES_HOST`
78-
- `JWT_SECRET`, `JWT_ALGORITHM`
79-
- `BLOCK_REGISTER`: Boolean to disable registration
80-
- `IMAGES_PATH`: Image storage directory
50+
- `JWT_SECRET`, `BLOCK_REGISTER`, `IMAGES_PATH`
51+
- `CORS_ORIGIN`, `PORT`

Dockerfile

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,16 @@
1-
FROM ghcr.io/astral-sh/uv:python3.13-trixie-slim AS builder
1+
FROM golang:1.26-trixie AS builder
22

33
WORKDIR /app
44

5-
COPY pyproject.toml uv.lock ./
6-
RUN uv sync --frozen --no-install-project --no-dev;
5+
COPY go.mod go.sum ./
6+
RUN go mod download
77

8-
COPY pyazo_api/ ./pyazo_api/
9-
RUN uv sync --frozen --no-dev;
8+
COPY . .
9+
RUN go build -o /pyazo ./cmd/
1010

11-
FROM python:3.13-slim-trixie
11+
FROM debian:trixie-slim
1212

1313
EXPOSE 8000
14-
WORKDIR /app
15-
ENTRYPOINT ["/entrypoint.sh"]
16-
ENV PYTHONUNBUFFERED=1
17-
VOLUME /images
18-
19-
COPY --from=migrate/migrate /usr/local/bin/migrate /usr/bin/migrate
20-
21-
RUN apt update \
22-
&& apt install -y postgresql-client \
23-
&& rm -rf /var/lib/apt/lists/* \
24-
&& apt clean;
2514

26-
COPY migrations/ ./migrations/
27-
COPY entrypoint.sh /entrypoint.sh
28-
COPY --from=builder /app/ ./
15+
COPY --from=builder /pyazo /pyazo
16+
ENTRYPOINT ["/pyazo"]

Makefile

Lines changed: 0 additions & 2 deletions
This file was deleted.

README.md

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,55 +2,55 @@
22

33
Pyazo is a self-hosted screenshot and image upload utility. It allows you to take a screenshot of a part of your screen and automatically upload it to your own server. You can also directly upload an image from your computer.
44

5-
It is comprised of a cross-platform client written in Python which defers the actual taking of the screenshot to the built-in OS tools (macOS and Windows) or common utilities (Linux distributions). The server is written as a RESTful FastAPI app with support for basic user accounts and image sharing options.
5+
It is comprised of a cross-platform client written in Python which defers the actual taking of the screenshot to the built-in OS tools (macOS and Windows) or common utilities (Linux distributions). The server is a RESTful Go API with support for basic user accounts and image management.
66

7-
## Compatibility
7+
## Requirements
88

9-
### Server
9+
- Go >= 1.24
10+
- PostgreSQL
1011

11-
- Python >= 3.13 (check with `python --version`)
12+
## Configuration
1213

13-
## Installation
14+
Copy `.env-example` to `.env` and configure:
1415

15-
The only official supported way to run the server is through docker-compose. First make a copy of the `.env-example` file, name it `.env` and change the settings inside accordingly.
16+
| Key | Default | Description |
17+
| ----------------- | ----------------------- | ---------------------------------- |
18+
| ENV | production | Set to development for debug mode |
19+
| POSTGRES_USER | pyazo | PostgreSQL username |
20+
| POSTGRES_PASSWORD | | PostgreSQL password |
21+
| POSTGRES_DB | pyazo | Database name |
22+
| POSTGRES_HOST | localhost | Database host |
23+
| JWT_SECRET | | JWT signing secret |
24+
| BLOCK_REGISTER | true | Disable user registration |
25+
| IMAGES_PATH | /images | Image storage directory |
26+
| CORS_ORIGIN | https://app.pyazo.com | Allowed CORS origin |
27+
| PORT | 8000 | HTTP listen port |
1628

17-
| Key | Default | Description |
18-
| ----------------- | --------------- | ----------------------------------------------------------- |
19-
| ENV | production | FastAPI environment. Set to development to enable debugging |
20-
| POSTGRES_USER | pyazo | Username of the postgres user |
21-
| POSTGRES_PASSWORD | ' ' | Password of the postgres user |
22-
| POSTGRES_DB | pyazo | Database name |
23-
| JWT_SECRET | ' ' | JWT secret |
24-
| BLOCK_REGISTER | 'False' | Blocks registration if true |
25-
| HOST_PUBLIC_MEDIA | /srv/http/pyazo | Host public media path (Docker only) |
26-
| IMAGE_PATH | ./media/public/ | Public media storage path (non-Docker only) |
29+
## Development
2730

28-
Make a copy of the `docker-compose-prod.yaml` file, name it `docker-compose.yaml` and change the settings inside if needed.
31+
```bash
32+
# Start PostgreSQL
33+
docker compose up -d db
2934

30-
Build the container using:
35+
# Build
36+
go build -o api ./cmd/
3137

32-
```shell
33-
docker compose build
38+
# Run
39+
POSTGRES_PASSWORD=pyazo JWT_SECRET=secret BLOCK_REGISTER=false ./api
40+
41+
# Run tests
42+
POSTGRES_PASSWORD=pyazo go test ./...
3443
```
3544

36-
Then run it using:
45+
## Docker
3746

38-
```shell
47+
```bash
48+
docker compose build
3949
docker compose up -d
4050
```
4151

42-
Place a copy of the nginx.conf-example to /etc/nginx/conf.d/pyazo.conf and change the settings inside if needed.
43-
44-
Restart nginx.
45-
46-
## Documentation
47-
48-
https://pyazo.com/docs
52+
Images are stored at the `IMAGES_PATH` volume (`/images` by default) and should be served by a reverse proxy.
4953

5054
## License and Credits
5155

5256
BSD 3-Clause
53-
54-
[Python]: https://www.python.org/downloads/
55-
[Docker]: https://docs.docker.com/
56-
[Docker Compose]: https://docs.docker.com/compose/

0 commit comments

Comments
 (0)