aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikolay Govorov <me@govorov.online>2026-04-10 20:35:44 +0100
committerNikolay Govorov <me@govorov.online>2026-04-10 20:35:44 +0100
commit939f3a9a14ef92fabe4a4554bc8b4926d376867b (patch)
treef047dd017708555bfad89ae767a1ac616ec9d636
parent448124d11ea4b0d49689a3ea408abad4dc28de03 (diff)
downloadtar
tar.gz
tar.bz2
tar.lz
tar.xz
tar.zst
zip
Update naming, separate grpc targets
Diffstat
-rw-r--r--.gitignore9+5 −4
-rw-r--r--README.md12+6 −6
-rw-r--r--REUSE.toml4+2 −2
-rw-r--r--Taskfile.yml70+37 −33
-rw-r--r--buf.lock (renamed from proto/buf.lock)0+0 −0
-rw-r--r--buf.yaml (renamed from proto/buf.yaml)3+3 −0
-rw-r--r--cmd/mirum-server/actor.go (renamed from cmd/mirumd/actor.go)52+26 −26
-rw-r--r--cmd/mirum-server/api_cli.go (renamed from cmd/mirumd/api_cli.go)38+19 −19
-rw-r--r--cmd/mirum-server/cert.go (renamed from cmd/mirumd/cert.go)0+0 −0
-rw-r--r--cmd/mirum-server/cert_test.go (renamed from cmd/mirumd/cert_test.go)0+0 −0
-rw-r--r--cmd/mirum-server/config.go (renamed from cmd/mirumd/config.go)2+1 −1
-rw-r--r--cmd/mirum-server/database.go (renamed from cmd/mirumd/database.go)32+16 −16
-rw-r--r--cmd/mirum-server/id.go (renamed from cmd/mirumd/id.go)0+0 −0
-rw-r--r--cmd/mirum-server/id_test.go (renamed from cmd/mirumd/id_test.go)0+0 −0
-rw-r--r--cmd/mirum-server/main.go (renamed from cmd/mirumd/main.go)26+13 −13
-rw-r--r--cmd/mirum-server/proto/api.proto (renamed from proto/admin.proto)6+3 −3
-rw-r--r--cmd/mirum-server/proto/buf.gen.yaml (renamed from proto/buf.gen.yaml)6+3 −3
-rw-r--r--cmd/mirum-server/server.go (renamed from cmd/mirumd/server.go)6+3 −3
-rw-r--r--cmd/mirum-server/server_admin.go (renamed from cmd/mirumd/server_admin.go)192+96 −96
-rw-r--r--cmd/mirum-server/server_grpc.go (renamed from cmd/mirumd/server_grpc.go)14+7 −7
-rw-r--r--cmd/mirum-server/server_web.go (renamed from cmd/mirumd/server_web.go)18+9 −9
-rw-r--r--cmd/mirum-server/static.go (renamed from cmd/mirumd/static.go)0+0 −0
-rw-r--r--cmd/mirum-server/static_dev.go (renamed from cmd/mirumd/static_dev.go)0+0 −0
-rw-r--r--cmd/mirum-server/static_prod.go (renamed from cmd/mirumd/static_prod.go)0+0 −0
-rw-r--r--cmd/mirum-server/web/api/client.ts (renamed from cmd/mirumd/web/api/client.ts)6+3 −3
-rw-r--r--cmd/mirum-server/web/components.json (renamed from cmd/mirumd/web/components.json)0+0 −0
-rw-r--r--cmd/mirum-server/web/components/pages/dashboard.tsx (renamed from cmd/mirumd/web/components/pages/dashboard.tsx)6+3 −3
-rw-r--r--cmd/mirum-server/web/components/pages/error.tsx (renamed from cmd/mirumd/web/components/pages/error.tsx)0+0 −0
-rw-r--r--cmd/mirum-server/web/components/pages/login.tsx (renamed from cmd/mirumd/web/components/pages/login.tsx)2+1 −1
-rw-r--r--cmd/mirum-server/web/components/ui/alert.tsx (renamed from cmd/mirumd/web/components/ui/alert.tsx)0+0 −0
-rw-r--r--cmd/mirum-server/web/components/ui/button.tsx (renamed from cmd/mirumd/web/components/ui/button.tsx)0+0 −0
-rw-r--r--cmd/mirum-server/web/components/ui/card.tsx (renamed from cmd/mirumd/web/components/ui/card.tsx)0+0 −0
-rw-r--r--cmd/mirum-server/web/components/ui/field.tsx (renamed from cmd/mirumd/web/components/ui/field.tsx)0+0 −0
-rw-r--r--cmd/mirum-server/web/components/ui/input.tsx (renamed from cmd/mirumd/web/components/ui/input.tsx)0+0 −0
-rw-r--r--cmd/mirum-server/web/components/ui/label.tsx (renamed from cmd/mirumd/web/components/ui/label.tsx)0+0 −0
-rw-r--r--cmd/mirum-server/web/components/ui/separator.tsx (renamed from cmd/mirumd/web/components/ui/separator.tsx)0+0 −0
-rw-r--r--cmd/mirum-server/web/entries/dashboard.tsx (renamed from cmd/mirumd/web/entries/dashboard.tsx)0+0 −0
-rw-r--r--cmd/mirum-server/web/entries/error.tsx (renamed from cmd/mirumd/web/entries/error.tsx)0+0 −0
-rw-r--r--cmd/mirum-server/web/entries/login.tsx (renamed from cmd/mirumd/web/entries/login.tsx)0+0 −0
-rw-r--r--cmd/mirum-server/web/index.css (renamed from cmd/mirumd/web/index.css)0+0 −0
-rw-r--r--cmd/mirum-server/web/lib/errors.ts (renamed from cmd/mirumd/web/lib/errors.ts)2+1 −1
-rw-r--r--cmd/mirum-server/web/lib/mount.tsx (renamed from cmd/mirumd/web/lib/mount.tsx)0+0 −0
-rw-r--r--cmd/mirum-server/web/lib/utils.ts (renamed from cmd/mirumd/web/lib/utils.ts)0+0 −0
-rw-r--r--cmd/mirum-server/web/package-lock.json (renamed from cmd/mirumd/web/package-lock.json)0+0 −0
-rw-r--r--cmd/mirum-server/web/package.json (renamed from cmd/mirumd/web/package.json)0+0 −0
-rw-r--r--cmd/mirum-server/web/shell.html (renamed from cmd/mirumd/web/shell.html)0+0 −0
-rw-r--r--cmd/mirum-server/web/tsconfig.json (renamed from cmd/mirumd/web/tsconfig.json)0+0 −0
-rw-r--r--cmd/mirum-server/web/vite.config.ts (renamed from cmd/mirumd/web/vite.config.ts)0+0 −0
-rw-r--r--cmd/mirum-worker/client.go (renamed from cmd/mirumw/client.go)12+6 −6
-rw-r--r--cmd/mirum-worker/config.go (renamed from cmd/mirumw/config.go)2+1 −1
-rw-r--r--cmd/mirum-worker/main.go (renamed from cmd/mirumw/main.go)0+0 −0
-rw-r--r--internal/config/config.go2+1 −1
-rw-r--r--internal/protocol/platform.go76+38 −38
-rw-r--r--internal/protocol/proto/buf.gen.yaml11+11 −0
-rw-r--r--internal/protocol/proto/wire.proto (renamed from proto/mirum.proto)6+3 −3
-rw-r--r--nfpm.yaml40+20 −20
-rw-r--r--pkg/mirum-server.service (renamed from pkg/mirumd.service)10+5 −5
-rw-r--r--pkg/mirum-worker@.service (renamed from pkg/mirumw@.service)8+4 −4
-rw-r--r--pkg/scripts/postinstall.sh6+3 −3
-rw-r--r--pkg/scripts/preinstall.sh2+1 −1
-rw-r--r--pkg/scripts/preremove.sh8+4 −4
-rw-r--r--pkg/server/config.yaml (renamed from pkg/mirumd.yaml)4+2 −2
-rw-r--r--pkg/worker/default.yaml (renamed from pkg/mirumw-default.yaml)10+5 −5
63 files changed, 361 insertions, 342 deletions
diff --git a/.gitignore b/.gitignore
index cec9f17..e9e681e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,9 +4,10 @@
/dev
/build
/.task
-cmd/mirumd/static
-cmd/mirumd/web/node_modules
+cmd/mirum-server/static
+cmd/mirum-server/web/node_modules
# grpc generated code
-/internal/protocol/pb
-/cmd/mirumd/web/gen
+/internal/protocol/wirepb
+/cmd/mirum-server/apipb
+/cmd/mirum-server/web/gen
diff --git a/README.md b/README.md
index 4e30f73..8292f0d 100644
--- a/README.md
+++ b/README.md
@@ -16,10 +16,10 @@ echo "deb [signed-by=/usr/share/keyrings/mirum.gpg] https://dl.mirum.dev/apt/ ni
sudo apt update && sudo apt install mirum
# Start the server
-sudo systemctl enable --now mirumd
+sudo systemctl enable --now mirum-server
# Start a worker (optional, can run on a different host)
-sudo systemctl enable --now mirumw@default
+sudo systemctl enable --now mirum-worker@default
```
**Fedora/RHEL:**
@@ -34,10 +34,10 @@ sudo curl -o /etc/yum.repos.d/mirum-nightly.repo https://dl.mirum.dev/rpm/nightl
sudo dnf install mirum
# Start the server
-sudo systemctl enable --now mirumd
+sudo systemctl enable --now mirum-server
# Start a worker (optional, can run on a different host)
-sudo systemctl enable --now mirumw@default
+sudo systemctl enable --now mirum-worker@default
```
**openSUSE:**
@@ -49,10 +49,10 @@ sudo zypper refresh
sudo zypper install mirum
# Start the server
-sudo systemctl enable --now mirumd
+sudo systemctl enable --now mirum-server
# Start a worker (optional, can run on a different host)
-sudo systemctl enable --now mirumw@default
+sudo systemctl enable --now mirum-worker@default
```
## Contributing
diff --git a/REUSE.toml b/REUSE.toml
index 455fc7e..2be7092 100644
--- a/REUSE.toml
+++ b/REUSE.toml
@@ -10,12 +10,12 @@ path = [
"CONCEPT.md",
"README.md",
"VERSION",
- "cmd/mirumd/web/*.json",
+ "cmd/mirum-server/web/*.json",
"go.mod",
"go.sum",
"pkg/dl/*",
"pkg/logo.svg",
- "proto/buf.*",
+ "buf.*",
]
SPDX-FileCopyrightText = "2026 Nikolay Govorov <me@govorov.online>"
SPDX-License-Identifier = "AGPL-3.0-or-later"
diff --git a/Taskfile.yml b/Taskfile.yml
index b3090e6..8178989 100644
--- a/Taskfile.yml
+++ b/Taskfile.yml
@@ -70,22 +70,26 @@ tasks:
proto:
desc: Generate ConnectRPC code from proto files
sources:
- - proto/*.proto
- - proto/buf.gen.yaml
- - proto/buf.yaml
+ - internal/protocol/proto/*.proto
+ - internal/protocol/proto/buf.gen.yaml
+ - cmd/mirum-server/proto/*.proto
+ - cmd/mirum-server/proto/buf.gen.yaml
+ - buf.yaml
generates:
- - internal/protocol/pb/**/*.go
- - cmd/mirumd/web/gen/**/*.ts
+ - internal/protocol/wirepb/**/*.go
+ - cmd/mirum-server/apipb/**/*.go
+ - cmd/mirum-server/web/gen/**/*.ts
cmds:
- - rm -rf internal/protocol/pb cmd/mirumd/web/gen
- - cd proto && buf generate
- # admin_pb.ts imports file_buf_validate_validate from buf/validate/validate_pb.js.
+ - rm -rf internal/protocol/wirepb cmd/mirum-server/apipb cmd/mirum-server/web/gen
+ - cd internal/protocol/proto && buf generate
+ - cd cmd/mirum-server/proto && buf generate
+ # api_pb.ts imports file_buf_validate_validate from buf/validate/validate_pb.js.
# buf.validate carries only server-side field annotations that the browser
# never decodes, so replace the 200+ KB generated schema with an empty
# descriptor stub that satisfies the GenFile type.
- - mkdir -p cmd/mirumd/web/gen/buf/validate
+ - mkdir -p cmd/mirum-server/web/gen/buf/validate
- |
- cat > cmd/mirumd/web/gen/buf/validate/validate_pb.ts <<'EOF'
+ cat > cmd/mirum-server/web/gen/buf/validate/validate_pb.ts <<'EOF'
// Stub: see Taskfile.yml proto task. buf.validate is server-only.
import { fileDesc, type GenFile } from "@bufbuild/protobuf/codegenv2"
export const file_buf_validate_validate: GenFile = /*@__PURE__*/ fileDesc("")
@@ -93,7 +97,7 @@ tasks:
web:install:
desc: Install frontend dependencies
- dir: cmd/mirumd/web
+ dir: cmd/mirum-server/web
sources:
- package.json
- package-lock.json
@@ -103,8 +107,8 @@ tasks:
- npm ci
web:build:
- desc: Build the frontend into cmd/mirumd/static
- dir: cmd/mirumd/web
+ desc: Build the frontend into cmd/mirum-server/static
+ dir: cmd/mirum-server/web
deps: [web:install, proto]
sources:
- api/**/*
@@ -123,7 +127,7 @@ tasks:
web:size:
desc: Check frontend bundle size budgets
- dir: cmd/mirumd/web
+ dir: cmd/mirum-server/web
deps: [web:build]
sources:
- ../static/assets/*
@@ -132,8 +136,8 @@ tasks:
- npm run size
web:dev:
- desc: Run Vite dev server (use with `go run -tags dev ./cmd/mirumd`)
- dir: cmd/mirumd/web
+ desc: Run Vite dev server (use with `go run -tags dev ./cmd/mirum-server`)
+ dir: cmd/mirum-server/web
deps: [web:install, proto]
prefix: vite
env:
@@ -154,8 +158,8 @@ tasks:
test -f dev/server.crt ||
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1
-keyout dev/server.key -out dev/server.crt
- -days 365 -nodes -subj "/CN=mirumd"
- -addext "subjectAltName=DNS:mirumd,DNS:localhost"
+ -days 365 -nodes -subj "/CN=mirum-server"
+ -addext "subjectAltName=DNS:mirum-server,DNS:localhost"
- >-
test -f dev/worker.key ||
openssl genpkey -algorithm ed25519 -out dev/worker.key
@@ -164,13 +168,13 @@ tasks:
openssl pkey -in dev/worker.key -pubout -out dev/worker.pub
devenv:config:
- desc: Write dev/mirumd.yaml if missing
+ desc: Write dev/mirum-server.yaml if missing
status:
- - test -f dev/mirumd.yaml
+ - test -f dev/mirum-server.yaml
cmds:
- mkdir -p dev
- |
- cat > dev/mirumd.yaml <<EOF
+ cat > dev/mirum-server.yaml <<EOF
web_addr: ":3000"
grpc_addr: ":2026"
admin_socket: "/tmp/mirum-admin.sock"
@@ -199,18 +203,18 @@ tasks:
deps: [devenv:keys, devenv:config, devenv:db]
dev:server:
- desc: Build mirumd with -tags dev and run it against the dev environment
+ desc: Build mirum-server with -tags dev and run it against the dev environment
deps: [proto, devenv]
- prefix: mirumd
+ prefix: mirum-server
env:
CGO_ENABLED: "0"
cmds:
- mkdir -p {{.BUILD_DIR}}
- - go build -tags dev -o {{.BUILD_DIR}}/mirumd ./cmd/mirumd
- - "{{.BUILD_DIR}}/mirumd daemon --config dev/mirumd.yaml"
+ - go build -tags dev -o {{.BUILD_DIR}}/mirum-server ./cmd/mirum-server
+ - "{{.BUILD_DIR}}/mirum-server daemon --config dev/mirum-server.yaml"
dev:
- desc: Run Vite dev server and mirumd together (HMR-enabled)
+ desc: Run Vite dev server and mirum-server together (HMR-enabled)
deps: [web:dev, dev:server]
build:
@@ -225,16 +229,16 @@ tasks:
GOARCH: "{{.GOARCH}}"
cmds:
- mkdir -p {{.BUILD_DIR}}
- - go build -o {{.BUILD_DIR}}/mirumd-{{.GOOS}}-{{.GOARCH}} ./cmd/mirumd
- - go build -o {{.BUILD_DIR}}/mirumw-{{.GOOS}}-{{.GOARCH}} ./cmd/mirumw
- - cp {{.BUILD_DIR}}/mirumd-{{.GOOS}}-{{.GOARCH}} {{.BUILD_DIR}}/mirumd
- - cp {{.BUILD_DIR}}/mirumw-{{.GOOS}}-{{.GOARCH}} {{.BUILD_DIR}}/mirumw
+ - go build -o {{.BUILD_DIR}}/mirum-server-{{.GOOS}}-{{.GOARCH}} ./cmd/mirum-server
+ - go build -o {{.BUILD_DIR}}/mirum-worker-{{.GOOS}}-{{.GOARCH}} ./cmd/mirum-worker
+ - cp {{.BUILD_DIR}}/mirum-server-{{.GOOS}}-{{.GOARCH}} {{.BUILD_DIR}}/mirum-server
+ - cp {{.BUILD_DIR}}/mirum-worker-{{.GOOS}}-{{.GOARCH}} {{.BUILD_DIR}}/mirum-worker
run:
- desc: Build and run mirumd against the dev environment
+ desc: Build and run mirum-server against the dev environment
deps: [build, devenv]
cmds:
- - "{{.BUILD_DIR}}/mirumd daemon --config dev/mirumd.yaml"
+ - "{{.BUILD_DIR}}/mirum-server daemon --config dev/mirum-server.yaml"
test:
desc: Run all tests
@@ -282,7 +286,7 @@ tasks:
task build GOOS=linux GOARCH=$arch
ARCH=$arch nfpm package --packager deb --target {{.DIST_DIR}}/
ARCH=$arch nfpm package --packager rpm --target {{.DIST_DIR}}/
- rm {{.BUILD_DIR}}/mirumd {{.BUILD_DIR}}/mirumw
+ rm {{.BUILD_DIR}}/mirum-server {{.BUILD_DIR}}/mirum-worker
done
printf 'VERSION={{.VERSION}}\nCHANNEL={{.CHANNEL}}\n' > {{.DIST_DIR}}/build.env
diff --git a/proto/buf.lock b/buf.lock
index d15a117..d15a117 100644
--- a/proto/buf.lock
+++ b/buf.lock
diff --git a/proto/buf.yaml b/buf.yaml
index 8d594f7..ddd7a3c 100644
--- a/proto/buf.yaml
+++ b/buf.yaml
@@ -2,5 +2,8 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
version: v2
+modules:
+ - path: internal/protocol/proto
+ - path: cmd/mirum-server/proto
deps:
- buf.build/bufbuild/protovalidate
diff --git a/cmd/mirumd/actor.go b/cmd/mirum-server/actor.go
index bdd49c2..03d30ba 100644
--- a/cmd/mirumd/actor.go
+++ b/cmd/mirum-server/actor.go
@@ -8,7 +8,7 @@ import (
"errors"
"slices"
- "dimidiumlabs/mirum/internal/protocol/pb"
+ "dimidiumlabs/mirum/cmd/mirum-server/apipb"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
@@ -19,40 +19,40 @@ var (
ErrUnauthenticated = errors.New("database: authentication required")
)
-var anonPermissions = []pb.Perm{
- pb.Perm_PERM_ORG_READ,
+var anonPermissions = []apipb.Perm{
+ apipb.Perm_PERM_ORG_READ,
}
-var userGlobalPermissions = []pb.Perm{
- pb.Perm_PERM_ORG_READ,
- pb.Perm_PERM_ORG_WRITE,
- pb.Perm_PERM_USER_READ,
+var userGlobalPermissions = []apipb.Perm{
+ apipb.Perm_PERM_ORG_READ,
+ apipb.Perm_PERM_ORG_WRITE,
+ apipb.Perm_PERM_USER_READ,
}
// rolePermissions is the single source of truth for role → perm bundles.
// RLS checks only tenancy (membership); action authz lives here.
-var rolePermissions = map[string][]pb.Perm{
+var rolePermissions = map[string][]apipb.Perm{
"owner": {
- pb.Perm_PERM_ORG_READ,
- pb.Perm_PERM_ORG_WRITE,
- pb.Perm_PERM_ORG_DELETE,
- pb.Perm_PERM_ORG_MEMBER_READ,
- pb.Perm_PERM_ORG_MEMBER_WRITE,
- pb.Perm_PERM_WORKER_READ,
- pb.Perm_PERM_WORKER_WRITE,
+ apipb.Perm_PERM_ORG_READ,
+ apipb.Perm_PERM_ORG_WRITE,
+ apipb.Perm_PERM_ORG_DELETE,
+ apipb.Perm_PERM_ORG_MEMBER_READ,
+ apipb.Perm_PERM_ORG_MEMBER_WRITE,
+ apipb.Perm_PERM_WORKER_READ,
+ apipb.Perm_PERM_WORKER_WRITE,
},
"admin": {
- pb.Perm_PERM_ORG_READ,
- pb.Perm_PERM_ORG_WRITE,
- pb.Perm_PERM_ORG_MEMBER_READ,
- pb.Perm_PERM_ORG_MEMBER_WRITE,
- pb.Perm_PERM_WORKER_READ,
- pb.Perm_PERM_WORKER_WRITE,
+ apipb.Perm_PERM_ORG_READ,
+ apipb.Perm_PERM_ORG_WRITE,
+ apipb.Perm_PERM_ORG_MEMBER_READ,
+ apipb.Perm_PERM_ORG_MEMBER_WRITE,
+ apipb.Perm_PERM_WORKER_READ,
+ apipb.Perm_PERM_WORKER_WRITE,
},
"member": {
- pb.Perm_PERM_ORG_READ,
- pb.Perm_PERM_ORG_MEMBER_READ,
- pb.Perm_PERM_WORKER_READ,
+ apipb.Perm_PERM_ORG_READ,
+ apipb.Perm_PERM_ORG_MEMBER_READ,
+ apipb.Perm_PERM_WORKER_READ,
},
}
@@ -176,7 +176,7 @@ func (a Actor) kindString() string {
}
// checkGlobal checks a global-scope perm (no specific org). Pure, no DB.
-func checkGlobal(actor Actor, perm pb.Perm) error {
+func checkGlobal(actor Actor, perm apipb.Perm) error {
switch actor.kind {
case actorOperator, actorSystem:
return nil
@@ -199,7 +199,7 @@ func checkGlobal(actor Actor, perm pb.Perm) error {
}
// checkPerm checks an org-scoped perm within an existing transaction.
-func checkPerm(ctx context.Context, tx pgx.Tx, actor Actor, orgID OrgID, perm pb.Perm) error {
+func checkPerm(ctx context.Context, tx pgx.Tx, actor Actor, orgID OrgID, perm apipb.Perm) error {
switch actor.kind {
case actorOperator, actorSystem:
return nil
diff --git a/cmd/mirumd/api_cli.go b/cmd/mirum-server/api_cli.go
index 6d53511..8220c65 100644
--- a/cmd/mirumd/api_cli.go
+++ b/cmd/mirum-server/api_cli.go
@@ -3,10 +3,10 @@
package main
-// Admin CLI is generated from admin.proto at startup via protoreflect.
+// Console CLI is generated from api.proto at startup via protoreflect.
// RPC name is camelCase-split into a cobra path: UserCreate -> "user create",
// OrgMemberAdd -> "org member add". Flags come from request fields, dispatch
-// goes through reflect on pbconnect.AdminClient.
+// goes through reflect on apipbconnect.ConsoleClient.
import (
"context"
@@ -26,14 +26,14 @@ import (
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/known/timestamppb"
- "dimidiumlabs/mirum/internal/protocol/pb"
- "dimidiumlabs/mirum/internal/protocol/pb/pbconnect"
+ "dimidiumlabs/mirum/cmd/mirum-server/apipb"
+ "dimidiumlabs/mirum/cmd/mirum-server/apipb/apipbconnect"
)
// mkClient is called per-invocation so persistent flags (e.g. --socket) are
// already parsed by the time it runs.
-func buildAdminCLI(root *cobra.Command, mkClient func() pbconnect.AdminClient) {
- methods := pb.File_admin_proto.Services().ByName("Admin").Methods()
+func buildConsoleCLI(root *cobra.Command, mkClient func() apipbconnect.ConsoleClient) {
+ methods := apipb.File_api_proto.Services().ByName("Console").Methods()
for i := 0; i < methods.Len(); i++ {
md := methods.Get(i)
path := splitCamel(string(md.Name()))
@@ -77,7 +77,7 @@ func ensureGroups(root *cobra.Command, path []string) *cobra.Command {
// fieldSetter writes one flag value into the request message.
type fieldSetter func(*pflag.FlagSet, protoreflect.Message) error
-func buildMethodCmd(md protoreflect.MethodDescriptor, leaf string, mkClient func() pbconnect.AdminClient) *cobra.Command {
+func buildMethodCmd(md protoreflect.MethodDescriptor, leaf string, mkClient func() apipbconnect.ConsoleClient) *cobra.Command {
reqDesc := md.Input()
rpcName := string(md.Name())
cmd := &cobra.Command{
@@ -91,7 +91,7 @@ func buildMethodCmd(md protoreflect.MethodDescriptor, leaf string, mkClient func
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
- resp, err := dispatchAdmin(mkClient(), rpcName, req)
+ resp, err := dispatchConsole(mkClient(), rpcName, req)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
@@ -187,7 +187,7 @@ func registerField(cmd *cobra.Command, fd protoreflect.FieldDescriptor) fieldSet
}
if required {
- panic(fmt.Sprintf("admincli: unhandled required field %s (kind=%s)", fd.FullName(), fd.Kind()))
+ panic(fmt.Sprintf("consolecli: unhandled required field %s (kind=%s)", fd.FullName(), fd.Kind()))
}
return nil
}
@@ -204,7 +204,7 @@ func registerMessageField(cmd *cobra.Command, fd protoreflect.FieldDescriptor, f
}
switch fd.Message().FullName() {
- case "mirum.UserRef":
+ case "mirum.api.UserRef":
flags.String(flagName, "", "user email")
markRequired()
return func(fs *pflag.FlagSet, m protoreflect.Message) error {
@@ -212,12 +212,12 @@ func registerMessageField(cmd *cobra.Command, fd protoreflect.FieldDescriptor, f
if v == "" {
return nil
}
- ref := &pb.UserRef{Ref: &pb.UserRef_Email{Email: v}}
+ ref := &apipb.UserRef{Ref: &apipb.UserRef_Email{Email: v}}
m.Set(fd, protoreflect.ValueOfMessage(ref.ProtoReflect()))
return nil
}
- case "mirum.OrgRef":
+ case "mirum.api.OrgRef":
flags.String(flagName, "", "org slug")
markRequired()
return func(fs *pflag.FlagSet, m protoreflect.Message) error {
@@ -225,22 +225,22 @@ func registerMessageField(cmd *cobra.Command, fd protoreflect.FieldDescriptor, f
if v == "" {
return nil
}
- ref := &pb.OrgRef{Ref: &pb.OrgRef_Slug{Slug: v}}
+ ref := &apipb.OrgRef{Ref: &apipb.OrgRef_Slug{Slug: v}}
m.Set(fd, protoreflect.ValueOfMessage(ref.ProtoReflect()))
return nil
}
- case "mirum.PageRequest":
+ case "mirum.api.PageRequest":
return nil
}
if required {
- panic(fmt.Sprintf("admincli: unhandled required message field %s (type=%s)", fd.FullName(), fd.Message().FullName()))
+ panic(fmt.Sprintf("consolecli: unhandled required message field %s (type=%s)", fd.FullName(), fd.Message().FullName()))
}
return nil
}
-// Admin schema uses bytes only for UUIDs (id / *_id) and ed25519 PKIX keys.
+// Console schema uses bytes only for UUIDs (id / *_id) and ed25519 PKIX keys.
func parseBytesFlag(fieldName, v string) ([]byte, error) {
switch {
case fieldName == "id" || strings.HasSuffix(fieldName, "_id"):
@@ -297,11 +297,11 @@ func buildRequest(desc protoreflect.MessageDescriptor, flags *pflag.FlagSet, set
// reflect.New on *connect.Request[T] is equivalent to connect.NewRequest(req):
// Msg is the only public field, the rest are initialised lazily at send time.
-func dispatchAdmin(client pbconnect.AdminClient, name string, req proto.Message) (proto.Message, error) {
+func dispatchConsole(client apipbconnect.ConsoleClient, name string, req proto.Message) (proto.Message, error) {
cv := reflect.ValueOf(client)
method := cv.MethodByName(name)
if !method.IsValid() {
- return nil, fmt.Errorf("unknown admin method %q", name)
+ return nil, fmt.Errorf("unknown console method %q", name)
}
// method signature:
// func(context.Context, *connect.Request[T]) (*connect.Response[U], error)
@@ -329,7 +329,7 @@ func printResponse(resp proto.Message) {
var meaningful []protoreflect.FieldDescriptor
for i := 0; i < fields.Len(); i++ {
f := fields.Get(i)
- if f.Kind() == protoreflect.MessageKind && f.Message().FullName() == "mirum.PageResponse" {
+ if f.Kind() == protoreflect.MessageKind && f.Message().FullName() == "mirum.api.PageResponse" {
continue
}
meaningful = append(meaningful, f)
diff --git a/cmd/mirumd/cert.go b/cmd/mirum-server/cert.go
index 67128d5..67128d5 100644
--- a/cmd/mirumd/cert.go
+++ b/cmd/mirum-server/cert.go
diff --git a/cmd/mirumd/cert_test.go b/cmd/mirum-server/cert_test.go
index 794b2f6..794b2f6 100644
--- a/cmd/mirumd/cert_test.go
+++ b/cmd/mirum-server/cert_test.go
diff --git a/cmd/mirumd/config.go b/cmd/mirum-server/config.go
index 854e7ec..48d6ed2 100644
--- a/cmd/mirumd/config.go
+++ b/cmd/mirum-server/config.go
@@ -35,7 +35,7 @@ func getConfig(filename string) (*appConfig, error) {
cfg := &appConfig{
GrpcAddr: ":2026",
WebAddr: ":3000",
- AdminSocket: "/run/mirumd/admin.sock",
+ AdminSocket: "/run/mirum-server/admin.sock",
}
data, err := os.ReadFile(filename)
diff --git a/cmd/mirumd/database.go b/cmd/mirum-server/database.go
index 6c03f7a..8655dbc 100644
--- a/cmd/mirumd/database.go
+++ b/cmd/mirum-server/database.go
@@ -18,8 +18,8 @@ import (
"strings"
"time"
+ "dimidiumlabs/mirum/cmd/mirum-server/apipb"
"dimidiumlabs/mirum/internal/config"
- "dimidiumlabs/mirum/internal/protocol/pb"
sb "github.com/huandu/go-sqlbuilder"
"github.com/jackc/pgerrcode"
@@ -469,7 +469,7 @@ func (db *DB) UserGet(ctx context.Context, actor Actor, ref UserRef) (*User, err
var u User
err := db.apicall(
ctx, actor,
- func(tx pgx.Tx) error { return checkGlobal(actor, pb.Perm_PERM_USER_READ) },
+ func(tx pgx.Tx) error { return checkGlobal(actor, apipb.Perm_PERM_USER_READ) },
nil,
func(tx pgx.Tx) error {
col, val := ref.where()
@@ -498,7 +498,7 @@ func (db *DB) UserList(ctx context.Context, actor Actor, cursor UserID, limit in
var users []User
var total int
err := db.apicall(ctx, actor,
- func(tx pgx.Tx) error { return checkGlobal(actor, pb.Perm_PERM_USER_READ) },
+ func(tx pgx.Tx) error { return checkGlobal(actor, apipb.Perm_PERM_USER_READ) },
func(tx pgx.Tx) error {
if filter != "" {
return ErrNotImplemented
@@ -750,7 +750,7 @@ func (db *DB) UserSessionPurgeExpired(ctx context.Context) error {
func (db *DB) OrgGet(ctx context.Context, actor Actor, ref OrgRef) (*Organization, error) {
var o Organization
err := db.apicall(ctx, actor,
- func(tx pgx.Tx) error { return checkGlobal(actor, pb.Perm_PERM_ORG_READ) },
+ func(tx pgx.Tx) error { return checkGlobal(actor, apipb.Perm_PERM_ORG_READ) },
nil,
func(tx pgx.Tx) error {
col, val := ref.where()
@@ -777,7 +777,7 @@ func (db *DB) OrgGet(ctx context.Context, actor Actor, ref OrgRef) (*Organizatio
func (db *DB) OrgCreate(ctx context.Context, actor Actor, name, slug string, public bool, owner UserRef) (OrgID, error) {
var orgID OrgID
err := db.apicall(ctx, actor,
- func(tx pgx.Tx) error { return checkGlobal(actor, pb.Perm_PERM_ORG_WRITE) },
+ func(tx pgx.Tx) error { return checkGlobal(actor, apipb.Perm_PERM_ORG_WRITE) },
nil,
func(tx pgx.Tx) error {
userID, err := resolveUser(ctx, tx, owner)
@@ -820,7 +820,7 @@ func (db *DB) OrgUpdate(ctx context.Context, actor Actor, ref OrgRef, name *stri
if err != nil {
return err
}
- return checkPerm(ctx, tx, actor, id, pb.Perm_PERM_ORG_WRITE)
+ return checkPerm(ctx, tx, actor, id, apipb.Perm_PERM_ORG_WRITE)
},
nil,
func(tx pgx.Tx) error {
@@ -864,7 +864,7 @@ func (db *DB) OrgDelete(ctx context.Context, actor Actor, ref OrgRef) error {
if err != nil {
return err
}
- return checkPerm(ctx, tx, actor, id, pb.Perm_PERM_ORG_DELETE)
+ return checkPerm(ctx, tx, actor, id, apipb.Perm_PERM_ORG_DELETE)
},
nil,
func(tx pgx.Tx) error {
@@ -890,7 +890,7 @@ func (db *DB) OrgList(ctx context.Context, actor Actor, cursor OrgID, limit int,
var orgs []Organization
var total int
err := db.apicall(ctx, actor,
- func(tx pgx.Tx) error { return checkGlobal(actor, pb.Perm_PERM_ORG_READ) },
+ func(tx pgx.Tx) error { return checkGlobal(actor, apipb.Perm_PERM_ORG_READ) },
func(tx pgx.Tx) error {
if filter != "" {
return ErrNotImplemented
@@ -946,7 +946,7 @@ func (db *DB) OrgMemberGet(ctx context.Context, actor Actor, org OrgRef, user Us
if err != nil {
return err
}
- return checkPerm(ctx, tx, actor, orgID, pb.Perm_PERM_ORG_MEMBER_READ)
+ return checkPerm(ctx, tx, actor, orgID, apipb.Perm_PERM_ORG_MEMBER_READ)
},
nil,
func(tx pgx.Tx) error {
@@ -985,7 +985,7 @@ func (db *DB) OrgMembersList(ctx context.Context, actor Actor, org OrgRef, curso
if err != nil {
return err
}
- return checkPerm(ctx, tx, actor, orgID, pb.Perm_PERM_ORG_MEMBER_READ)
+ return checkPerm(ctx, tx, actor, orgID, apipb.Perm_PERM_ORG_MEMBER_READ)
},
func(tx pgx.Tx) error {
if filter != "" {
@@ -1041,7 +1041,7 @@ func (db *DB) OrgMemberAdd(ctx context.Context, actor Actor, org OrgRef, user Us
if err != nil {
return err
}
- return checkPerm(ctx, tx, actor, orgID, pb.Perm_PERM_ORG_MEMBER_WRITE)
+ return checkPerm(ctx, tx, actor, orgID, apipb.Perm_PERM_ORG_MEMBER_WRITE)
},
nil,
func(tx pgx.Tx) error {
@@ -1075,7 +1075,7 @@ func (db *DB) OrgMemberUpdateRole(ctx context.Context, actor Actor, org OrgRef,
if err != nil {
return err
}
- return checkPerm(ctx, tx, actor, orgID, pb.Perm_PERM_ORG_MEMBER_WRITE)
+ return checkPerm(ctx, tx, actor, orgID, apipb.Perm_PERM_ORG_MEMBER_WRITE)
},
nil,
func(tx pgx.Tx) error {
@@ -1128,7 +1128,7 @@ func (db *DB) OrgMemberRemove(ctx context.Context, actor Actor, org OrgRef, user
if err != nil {
return err
}
- return checkPerm(ctx, tx, actor, orgID, pb.Perm_PERM_ORG_MEMBER_WRITE)
+ return checkPerm(ctx, tx, actor, orgID, apipb.Perm_PERM_ORG_MEMBER_WRITE)
},
nil,
func(tx pgx.Tx) error {
@@ -1185,7 +1185,7 @@ func (db *DB) WorkerGet(ctx context.Context, actor Actor, id WorkerID) (*Worker,
return err
}
if orgID != nil {
- return checkPerm(ctx, tx, actor, *orgID, pb.Perm_PERM_WORKER_READ)
+ return checkPerm(ctx, tx, actor, *orgID, apipb.Perm_PERM_WORKER_READ)
}
if !actor.IsSuperuser() {
return ErrPermissionDenied
@@ -1214,7 +1214,7 @@ func (db *DB) WorkerCreate(ctx context.Context, actor Actor, publicKey []byte, o
return err
}
orgID = &id
- return checkPerm(ctx, tx, actor, id, pb.Perm_PERM_WORKER_WRITE)
+ return checkPerm(ctx, tx, actor, id, apipb.Perm_PERM_WORKER_WRITE)
}
if !actor.IsSuperuser() {
return ErrPermissionDenied
@@ -1246,7 +1246,7 @@ func (db *DB) WorkerDelete(ctx context.Context, actor Actor, id WorkerID) error
return err
}
if orgID != nil {
- return checkPerm(ctx, tx, actor, *orgID, pb.Perm_PERM_WORKER_WRITE)
+ return checkPerm(ctx, tx, actor, *orgID, apipb.Perm_PERM_WORKER_WRITE)
}
if !actor.IsSuperuser() {
return ErrPermissionDenied
diff --git a/cmd/mirumd/id.go b/cmd/mirum-server/id.go
index 09ec141..09ec141 100644
--- a/cmd/mirumd/id.go
+++ b/cmd/mirum-server/id.go
diff --git a/cmd/mirumd/id_test.go b/cmd/mirum-server/id_test.go
index 0d06fc1..0d06fc1 100644
--- a/cmd/mirumd/id_test.go
+++ b/cmd/mirum-server/id_test.go
diff --git a/cmd/mirumd/main.go b/cmd/mirum-server/main.go
index 73aa3f9..c592f71 100644
--- a/cmd/mirumd/main.go
+++ b/cmd/mirum-server/main.go
@@ -12,10 +12,10 @@ import (
"net/http"
"os"
+ "dimidiumlabs/mirum/cmd/mirum-server/apipb/apipbconnect"
"dimidiumlabs/mirum/internal/config"
"dimidiumlabs/mirum/internal/forges"
- "dimidiumlabs/mirum/internal/protocol/pb"
- "dimidiumlabs/mirum/internal/protocol/pb/pbconnect"
+ "dimidiumlabs/mirum/internal/protocol/wirepb"
"dimidiumlabs/mirum/internal/supervisor"
"github.com/coreos/go-systemd/v22/activation"
@@ -32,8 +32,8 @@ func hardenServer(s *http.Server) *http.Server {
func main() {
var socketPath string
- root := &cobra.Command{Use: "mirumd", Short: "Mirum CI server"}
- root.PersistentFlags().StringVar(&socketPath, "socket", "", "admin socket path (default from config or /run/mirumd/admin.sock)")
+ root := &cobra.Command{Use: "mirum-server", Short: "Mirum CI server"}
+ root.PersistentFlags().StringVar(&socketPath, "socket", "", "admin socket path (default from config or /run/mirum-server/admin.sock)")
root.AddGroup(&cobra.Group{ID: "main", Title: "Commands:"})
daemonCmd := &cobra.Command{
@@ -51,8 +51,8 @@ func main() {
_ = daemonCmd.MarkFlagRequired("config")
root.AddCommand(daemonCmd)
- // Admin subcommands are generated from admin.proto via reflection.
- buildAdminCLI(root, func() pbconnect.AdminClient { return adminClient(socketPath) })
+ // Console subcommands are generated from api.proto via reflection.
+ buildConsoleCLI(root, func() apipbconnect.ConsoleClient { return consoleClient(socketPath) })
for _, c := range root.Commands() {
if c.GroupID == "" {
c.GroupID = "main"
@@ -91,7 +91,7 @@ func daemon(configFile, socketFlag string) error {
db: db,
cfg: cfg,
forge: &forges.GitHub{Secret: cfg.WebhookSecret, Token: cfg.GitHubToken},
- queue: make(chan *pb.Task, config.TaskQueueCapacity),
+ queue: make(chan *wirepb.Task, config.TaskQueueCapacity),
}
defer srv.Close()
@@ -104,13 +104,13 @@ func daemon(configFile, socketFlag string) error {
go srv.PurgeSessions(ctx)
- adminPath, adminHandler := NewAdminHandler(srv)
+ consolePath, consoleHandler := NewConsoleHandler(srv)
- webSrv := hardenServer(NewWebServer(ctx, srv, adminPath, adminHandler))
+ webSrv := hardenServer(NewWebServer(ctx, srv, consolePath, consoleHandler))
grpcSrv := hardenServer(NewGrpcServer(ctx, srv))
adminMux := http.NewServeMux()
- adminMux.Handle(adminPath, adminHandler)
+ adminMux.Handle(consolePath, consoleHandler)
adminSrv := hardenServer(&http.Server{
Handler: adminMux,
ConnContext: func(ctx context.Context, _ net.Conn) context.Context {
@@ -237,11 +237,11 @@ func listeners(cfg *appConfig) (grpcLn, webLn, adminLn net.Listener, err error)
return grpcLn, webLn, adminLn, nil
}
-func adminClient(socketPath string) pbconnect.AdminClient {
+func consoleClient(socketPath string) apipbconnect.ConsoleClient {
if socketPath == "" {
- socketPath = "/run/mirumd/admin.sock"
+ socketPath = "/run/mirum-server/admin.sock"
}
- return pbconnect.NewAdminClient(
+ return apipbconnect.NewConsoleClient(
&http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
diff --git a/proto/admin.proto b/cmd/mirum-server/proto/api.proto
index 58f4e64..16a635e 100644
--- a/proto/admin.proto
+++ b/cmd/mirum-server/proto/api.proto
@@ -3,14 +3,14 @@
syntax = "proto3";
-package mirum;
+package mirum.api;
import "buf/validate/validate.proto";
import "google/protobuf/timestamp.proto";
-option go_package = "dimidiumlabs/mirum/internal/protocol/pb";
+option go_package = "dimidiumlabs/mirum/cmd/mirum-server/apipb";
-service Admin {
+service Console {
rpc UserCreate(UserCreateRequest) returns (UserCreateResponse);
rpc UserGet(UserGetRequest) returns (UserGetResponse);
rpc UserList(UserListRequest) returns (UserListResponse);
diff --git a/proto/buf.gen.yaml b/cmd/mirum-server/proto/buf.gen.yaml
index 0f24cdc..a9a94e2 100644
--- a/proto/buf.gen.yaml
+++ b/cmd/mirum-server/proto/buf.gen.yaml
@@ -4,13 +4,13 @@
version: v2
plugins:
- local: protoc-gen-go
- out: ../internal/protocol/pb
+ out: ../apipb
opt: paths=source_relative
- local: protoc-gen-connect-go
- out: ../internal/protocol/pb
+ out: ../apipb
opt: paths=source_relative
- remote: buf.build/bufbuild/es:v2.11.0
- out: ../cmd/mirumd/web/gen
+ out: ../web/gen
opt:
- target=ts
- import_extension=js
diff --git a/cmd/mirumd/server.go b/cmd/mirum-server/server.go
index 11585d9..5b4bbf0 100644
--- a/cmd/mirumd/server.go
+++ b/cmd/mirum-server/server.go
@@ -13,7 +13,7 @@ import (
"dimidiumlabs/mirum/internal/config"
"dimidiumlabs/mirum/internal/forges"
- "dimidiumlabs/mirum/internal/protocol/pb"
+ "dimidiumlabs/mirum/internal/protocol/wirepb"
)
// server holds the shared application state.
@@ -22,7 +22,7 @@ type server struct {
db *DB
forge forges.Forge
- queue chan *pb.Task
+ queue chan *wirepb.Task
tasks sync.Map // task_id → *forges.PushEvent
taskCounter atomic.Int64
}
@@ -60,7 +60,7 @@ func (s *server) enqueue(ev *forges.PushEvent) string {
s.tasks.Store(id, ev)
_ = s.forge.SetStatus(context.Background(), ev, forges.StatusPending, "Queued")
- s.queue <- &pb.Task{
+ s.queue <- &wirepb.Task{
Id: id,
CloneUrl: s.forge.AuthURL(ev.CloneURL),
Branch: ev.Branch,
diff --git a/cmd/mirumd/server_admin.go b/cmd/mirum-server/server_admin.go
index 7e1dae1..a79c377 100644
--- a/cmd/mirumd/server_admin.go
+++ b/cmd/mirum-server/server_admin.go
@@ -13,21 +13,21 @@ import (
"connectrpc.com/validate"
"google.golang.org/protobuf/types/known/timestamppb"
- "dimidiumlabs/mirum/internal/protocol/pb"
- "dimidiumlabs/mirum/internal/protocol/pb/pbconnect"
+ "dimidiumlabs/mirum/cmd/mirum-server/apipb"
+ "dimidiumlabs/mirum/cmd/mirum-server/apipb/apipbconnect"
)
-// NewAdminHandler creates the ConnectRPC handler with validation.
+// NewConsoleHandler creates the ConnectRPC handler with validation.
// Authorization is handled inside DB methods, not by an interceptor.
-func NewAdminHandler(srv *server) (string, http.Handler) {
- as := &adminService{srv: srv}
- return pbconnect.NewAdminHandler(as,
+func NewConsoleHandler(srv *server) (string, http.Handler) {
+ as := &consoleService{srv: srv}
+ return apipbconnect.NewConsoleHandler(as,
connect.WithInterceptors(validate.NewInterceptor()),
)
}
-type adminService struct {
- pbconnect.UnimplementedAdminHandler
+type consoleService struct {
+ apipbconnect.UnimplementedConsoleHandler
srv *server
}
@@ -36,9 +36,9 @@ type adminService struct {
// newAPIError builds a ConnectError with an empty message string and attaches
// an ErrorInfo detail carrying the domain reason. Clients switch on reason to
// pick user-facing text; the wire never carries human-readable strings.
-func newAPIError(code connect.Code, reason pb.ErrorReason, metadata map[string]string) error {
+func newAPIError(code connect.Code, reason apipb.ErrorReason, metadata map[string]string) error {
e := connect.NewError(code, nil)
- if d, err := connect.NewErrorDetail(&pb.ErrorInfo{Reason: reason, Metadata: metadata}); err == nil {
+ if d, err := connect.NewErrorDetail(&apipb.ErrorInfo{Reason: reason, Metadata: metadata}); err == nil {
e.AddDetail(d)
}
return e
@@ -47,23 +47,23 @@ func newAPIError(code connect.Code, reason pb.ErrorReason, metadata map[string]s
var errSpecs = []struct {
err error
code connect.Code
- reason pb.ErrorReason
+ reason apipb.ErrorReason
}{
- {ErrUserNotFound, connect.CodeNotFound, pb.ErrorReason_ERROR_REASON_USER_NOT_FOUND},
- {ErrOrgNotFound, connect.CodeNotFound, pb.ErrorReason_ERROR_REASON_ORG_NOT_FOUND},
- {ErrWorkerNotFound, connect.CodeNotFound, pb.ErrorReason_ERROR_REASON_WORKER_NOT_FOUND},
- {ErrNotMember, connect.CodeNotFound, pb.ErrorReason_ERROR_REASON_MEMBER_NOT_FOUND},
- {ErrEmailTaken, connect.CodeAlreadyExists, pb.ErrorReason_ERROR_REASON_EMAIL_TAKEN},
- {ErrSlugTaken, connect.CodeAlreadyExists, pb.ErrorReason_ERROR_REASON_SLUG_TAKEN},
- {ErrAlreadyMember, connect.CodeAlreadyExists, pb.ErrorReason_ERROR_REASON_ALREADY_MEMBER},
- {ErrLastOwner, connect.CodeFailedPrecondition, pb.ErrorReason_ERROR_REASON_LAST_OWNER},
- {ErrSoleOwner, connect.CodeFailedPrecondition, pb.ErrorReason_ERROR_REASON_SOLE_OWNER},
- {ErrInvalidSlug, connect.CodeInvalidArgument, pb.ErrorReason_ERROR_REASON_INVALID_SLUG},
- {ErrInvalidRole, connect.CodeInvalidArgument, pb.ErrorReason_ERROR_REASON_INVALID_ROLE},
- {ErrReservedEmail, connect.CodeInvalidArgument, pb.ErrorReason_ERROR_REASON_RESERVED_EMAIL},
- {ErrPermissionDenied, connect.CodePermissionDenied, pb.ErrorReason_ERROR_REASON_PERMISSION_DENIED},
- {ErrUnauthenticated, connect.CodeUnauthenticated, pb.ErrorReason_ERROR_REASON_UNAUTHENTICATED},
- {ErrNotImplemented, connect.CodeUnimplemented, pb.ErrorReason_ERROR_REASON_UNIMPLEMENTED},
+ {ErrUserNotFound, connect.CodeNotFound, apipb.ErrorReason_ERROR_REASON_USER_NOT_FOUND},
+ {ErrOrgNotFound, connect.CodeNotFound, apipb.ErrorReason_ERROR_REASON_ORG_NOT_FOUND},
+ {ErrWorkerNotFound, connect.CodeNotFound, apipb.ErrorReason_ERROR_REASON_WORKER_NOT_FOUND},
+ {ErrNotMember, connect.CodeNotFound, apipb.ErrorReason_ERROR_REASON_MEMBER_NOT_FOUND},
+ {ErrEmailTaken, connect.CodeAlreadyExists, apipb.ErrorReason_ERROR_REASON_EMAIL_TAKEN},
+ {ErrSlugTaken, connect.CodeAlreadyExists, apipb.ErrorReason_ERROR_REASON_SLUG_TAKEN},
+ {ErrAlreadyMember, connect.CodeAlreadyExists, apipb.ErrorReason_ERROR_REASON_ALREADY_MEMBER},
+ {ErrLastOwner, connect.CodeFailedPrecondition, apipb.ErrorReason_ERROR_REASON_LAST_OWNER},
+ {ErrSoleOwner, connect.CodeFailedPrecondition, apipb.ErrorReason_ERROR_REASON_SOLE_OWNER},
+ {ErrInvalidSlug, connect.CodeInvalidArgument, apipb.ErrorReason_ERROR_REASON_INVALID_SLUG},
+ {ErrInvalidRole, connect.CodeInvalidArgument, apipb.ErrorReason_ERROR_REASON_INVALID_ROLE},
+ {ErrReservedEmail, connect.CodeInvalidArgument, apipb.ErrorReason_ERROR_REASON_RESERVED_EMAIL},
+ {ErrPermissionDenied, connect.CodePermissionDenied, apipb.ErrorReason_ERROR_REASON_PERMISSION_DENIED},
+ {ErrUnauthenticated, connect.CodeUnauthenticated, apipb.ErrorReason_ERROR_REASON_UNAUTHENTICATED},
+ {ErrNotImplemented, connect.CodeUnimplemented, apipb.ErrorReason_ERROR_REASON_UNIMPLEMENTED},
}
func mapErr(err error) error {
@@ -76,35 +76,35 @@ func mapErr(err error) error {
}
}
slog.Error("unmapped handler error", "err", err)
- return newAPIError(connect.CodeInternal, pb.ErrorReason_ERROR_REASON_INTERNAL, nil)
+ return newAPIError(connect.CodeInternal, apipb.ErrorReason_ERROR_REASON_INTERNAL, nil)
}
// --- Ref converters ---
-func userRef(r *pb.UserRef) (UserRef, error) {
+func userRef(r *apipb.UserRef) (UserRef, error) {
switch v := r.GetRef().(type) {
- case *pb.UserRef_Id:
+ case *apipb.UserRef_Id:
id, err := IDFromBytes[UserKind](v.Id)
if err != nil {
return UserRef{}, err
}
return UserByID(id), nil
- case *pb.UserRef_Email:
+ case *apipb.UserRef_Email:
return UserByEmail(v.Email), nil
default:
return UserRef{}, nil
}
}
-func orgRef(r *pb.OrgRef) (OrgRef, error) {
+func orgRef(r *apipb.OrgRef) (OrgRef, error) {
switch v := r.GetRef().(type) {
- case *pb.OrgRef_Id:
+ case *apipb.OrgRef_Id:
id, err := IDFromBytes[OrgKind](v.Id)
if err != nil {
return OrgRef{}, err
}
return OrgByID(id), nil
- case *pb.OrgRef_Slug:
+ case *apipb.OrgRef_Slug:
return OrgBySlug(v.Slug), nil
default:
return OrgRef{}, nil
@@ -113,16 +113,16 @@ func orgRef(r *pb.OrgRef) (OrgRef, error) {
// --- Role converters ---
-var roleToString = map[pb.Role]string{
- pb.Role_ROLE_OWNER: "owner",
- pb.Role_ROLE_ADMIN: "admin",
- pb.Role_ROLE_MEMBER: "member",
+var roleToString = map[apipb.Role]string{
+ apipb.Role_ROLE_OWNER: "owner",
+ apipb.Role_ROLE_ADMIN: "admin",
+ apipb.Role_ROLE_MEMBER: "member",
}
-var roleToProto = map[string]pb.Role{
- "owner": pb.Role_ROLE_OWNER,
- "admin": pb.Role_ROLE_ADMIN,
- "member": pb.Role_ROLE_MEMBER,
+var roleToProto = map[string]apipb.Role{
+ "owner": apipb.Role_ROLE_OWNER,
+ "admin": apipb.Role_ROLE_ADMIN,
+ "member": apipb.Role_ROLE_MEMBER,
}
// --- Page helpers ---
@@ -132,7 +132,7 @@ const (
maxPageSize = 200
)
-func pageParams[K IDKind](p *pb.PageRequest) (cursor ID[K], limit int, err error) {
+func pageParams[K IDKind](p *apipb.PageRequest) (cursor ID[K], limit int, err error) {
limit = defaultPageSize
if p != nil {
if p.PageSize > 0 && int(p.PageSize) < maxPageSize {
@@ -150,8 +150,8 @@ func pageParams[K IDKind](p *pb.PageRequest) (cursor ID[K], limit int, err error
return
}
-func pageResponse[K IDKind](items int, limit int, lastID ID[K], total int) *pb.PageResponse {
- resp := &pb.PageResponse{TotalCount: int32(total)}
+func pageResponse[K IDKind](items int, limit int, lastID ID[K], total int) *apipb.PageResponse {
+ resp := &apipb.PageResponse{TotalCount: int32(total)}
if items == limit {
resp.NextCursor = lastID.Bytes()
}
@@ -160,28 +160,28 @@ func pageResponse[K IDKind](items int, limit int, lastID ID[K], total int) *pb.P
// --- Proto converters ---
-func userToProto(u User) *pb.User {
- return &pb.User{
+func userToProto(u User) *apipb.User {
+ return &apipb.User{
Id: u.ID.Bytes(), Email: u.Email, CreatedAt: timestamppb.New(u.CreatedAt),
}
}
-func orgToProto(o Organization) *pb.Org {
- return &pb.Org{
+func orgToProto(o Organization) *apipb.Org {
+ return &apipb.Org{
Id: o.ID.Bytes(), Name: o.Name, Slug: o.Slug,
Public: o.Public, CreatedAt: timestamppb.New(o.CreatedAt),
}
}
-func memberToProto(m OrgMember) *pb.OrgMemberInfo {
- return &pb.OrgMemberInfo{
+func memberToProto(m OrgMember) *apipb.OrgMemberInfo {
+ return &apipb.OrgMemberInfo{
User: userToProto(m.User), Role: roleToProto[m.Role],
JoinedAt: timestamppb.New(m.JoinedAt),
}
}
-func workerToProto(w Worker) *pb.Worker {
- pw := &pb.Worker{
+func workerToProto(w Worker) *apipb.Worker {
+ pw := &apipb.Worker{
Id: w.ID.Bytes(), PublicKey: w.PublicKey, CreatedAt: timestamppb.New(w.CreatedAt),
}
if w.OrgID != nil {
@@ -192,15 +192,15 @@ func workerToProto(w Worker) *pb.Worker {
// --- User handlers ---
-func (a *adminService) UserCreate(ctx context.Context, req *connect.Request[pb.UserCreateRequest]) (*connect.Response[pb.UserCreateResponse], error) {
+func (a *consoleService) UserCreate(ctx context.Context, req *connect.Request[apipb.UserCreateRequest]) (*connect.Response[apipb.UserCreateResponse], error) {
id, err := a.srv.db.UserCreate(ctx, ActorFromContext(ctx), req.Msg.Email, req.Msg.Password, []byte(a.srv.cfg.Pepper))
if err != nil {
return nil, mapErr(err)
}
- return connect.NewResponse(&pb.UserCreateResponse{Id: id.Bytes()}), nil
+ return connect.NewResponse(&apipb.UserCreateResponse{Id: id.Bytes()}), nil
}
-func (a *adminService) UserGet(ctx context.Context, req *connect.Request[pb.UserGetRequest]) (*connect.Response[pb.UserGetResponse], error) {
+func (a *consoleService) UserGet(ctx context.Context, req *connect.Request[apipb.UserGetRequest]) (*connect.Response[apipb.UserGetResponse], error) {
ref, err := userRef(req.Msg.User)
if err != nil {
return nil, mapErr(err)
@@ -209,10 +209,10 @@ func (a *adminService) UserGet(ctx context.Context, req *connect.Request[pb.User
if err != nil {
return nil, mapErr(err)
}
- return connect.NewResponse(&pb.UserGetResponse{User: userToProto(*u)}), nil
+ return connect.NewResponse(&apipb.UserGetResponse{User: userToProto(*u)}), nil
}
-func (a *adminService) UserList(ctx context.Context, req *connect.Request[pb.UserListRequest]) (*connect.Response[pb.UserListResponse], error) {
+func (a *consoleService) UserList(ctx context.Context, req *connect.Request[apipb.UserListRequest]) (*connect.Response[apipb.UserListResponse], error) {
cursor, limit, err := pageParams[UserKind](req.Msg.Page)
if err != nil {
return nil, mapErr(err)
@@ -227,7 +227,7 @@ func (a *adminService) UserList(ctx context.Context, req *connect.Request[pb.Use
return nil, mapErr(err)
}
- out := make([]*pb.User, len(users))
+ out := make([]*apipb.User, len(users))
for i := range users {
out[i] = userToProto(users[i])
}
@@ -237,13 +237,13 @@ func (a *adminService) UserList(ctx context.Context, req *connect.Request[pb.Use
lastID = users[len(users)-1].ID
}
- return connect.NewResponse(&pb.UserListResponse{
+ return connect.NewResponse(&apipb.UserListResponse{
Page: pageResponse(len(users), limit, lastID, total),
Users: out,
}), nil
}
-func (a *adminService) UserUpdate(ctx context.Context, req *connect.Request[pb.UserUpdateRequest]) (*connect.Response[pb.UserUpdateResponse], error) {
+func (a *consoleService) UserUpdate(ctx context.Context, req *connect.Request[apipb.UserUpdateRequest]) (*connect.Response[apipb.UserUpdateResponse], error) {
ref, err := userRef(req.Msg.User)
if err != nil {
return nil, mapErr(err)
@@ -251,10 +251,10 @@ func (a *adminService) UserUpdate(ctx context.Context, req *connect.Request[pb.U
if err := a.srv.db.UserUpdate(ctx, ActorFromContext(ctx), ref, req.Msg.Email, req.Msg.Password, []byte(a.srv.cfg.Pepper)); err != nil {
return nil, mapErr(err)
}
- return connect.NewResponse(&pb.UserUpdateResponse{}), nil
+ return connect.NewResponse(&apipb.UserUpdateResponse{}), nil
}
-func (a *adminService) UserDelete(ctx context.Context, req *connect.Request[pb.UserDeleteRequest]) (*connect.Response[pb.UserDeleteResponse], error) {
+func (a *consoleService) UserDelete(ctx context.Context, req *connect.Request[apipb.UserDeleteRequest]) (*connect.Response[apipb.UserDeleteResponse], error) {
ref, err := userRef(req.Msg.User)
if err != nil {
return nil, mapErr(err)
@@ -262,12 +262,12 @@ func (a *adminService) UserDelete(ctx context.Context, req *connect.Request[pb.U
if err := a.srv.db.UserDelete(ctx, ActorFromContext(ctx), ref); err != nil {
return nil, mapErr(err)
}
- return connect.NewResponse(&pb.UserDeleteResponse{}), nil
+ return connect.NewResponse(&apipb.UserDeleteResponse{}), nil
}
// --- Org handlers ---
-func (a *adminService) OrgCreate(ctx context.Context, req *connect.Request[pb.OrgCreateRequest]) (*connect.Response[pb.OrgCreateResponse], error) {
+func (a *consoleService) OrgCreate(ctx context.Context, req *connect.Request[apipb.OrgCreateRequest]) (*connect.Response[apipb.OrgCreateResponse], error) {
slug, err := ValidateSlug(req.Msg.Slug)
if err != nil {
return nil, mapErr(err)
@@ -280,10 +280,10 @@ func (a *adminService) OrgCreate(ctx context.Context, req *connect.Request[pb.Or
if err != nil {
return nil, mapErr(err)
}
- return connect.NewResponse(&pb.OrgCreateResponse{Id: id.Bytes()}), nil
+ return connect.NewResponse(&apipb.OrgCreateResponse{Id: id.Bytes()}), nil
}
-func (a *adminService) OrgGet(ctx context.Context, req *connect.Request[pb.OrgGetRequest]) (*connect.Response[pb.OrgGetResponse], error) {
+func (a *consoleService) OrgGet(ctx context.Context, req *connect.Request[apipb.OrgGetRequest]) (*connect.Response[apipb.OrgGetResponse], error) {
ref, err := orgRef(req.Msg.Org)
if err != nil {
return nil, mapErr(err)
@@ -292,10 +292,10 @@ func (a *adminService) OrgGet(ctx context.Context, req *connect.Request[pb.OrgGe
if err != nil {
return nil, mapErr(err)
}
- return connect.NewResponse(&pb.OrgGetResponse{Org: orgToProto(*o)}), nil
+ return connect.NewResponse(&apipb.OrgGetResponse{Org: orgToProto(*o)}), nil
}
-func (a *adminService) OrgList(ctx context.Context, req *connect.Request[pb.OrgListRequest]) (*connect.Response[pb.OrgListResponse], error) {
+func (a *consoleService) OrgList(ctx context.Context, req *connect.Request[apipb.OrgListRequest]) (*connect.Response[apipb.OrgListResponse], error) {
cursor, limit, err := pageParams[OrgKind](req.Msg.Page)
if err != nil {
return nil, mapErr(err)
@@ -310,7 +310,7 @@ func (a *adminService) OrgList(ctx context.Context, req *connect.Request[pb.OrgL
return nil, mapErr(err)
}
- out := make([]*pb.Org, len(orgs))
+ out := make([]*apipb.Org, len(orgs))
for i := range orgs {
out[i] = orgToProto(orgs[i])
}
@@ -320,13 +320,13 @@ func (a *adminService) OrgList(ctx context.Context, req *connect.Request[pb.OrgL
lastID = orgs[len(orgs)-1].ID
}
- return connect.NewResponse(&pb.OrgListResponse{
+ return connect.NewResponse(&apipb.OrgListResponse{
Page: pageResponse(len(orgs), limit, lastID, total),
Organizations: out,
}), nil
}
-func (a *adminService) OrgUpdate(ctx context.Context, req *connect.Request[pb.OrgUpdateRequest]) (*connect.Response[pb.OrgUpdateResponse], error) {
+func (a *consoleService) OrgUpdate(ctx context.Context, req *connect.Request[apipb.OrgUpdateRequest]) (*connect.Response[apipb.OrgUpdateResponse], error) {
var slug *string
if req.Msg.Slug != nil {
s, err := ValidateSlug(*req.Msg.Slug)
@@ -342,10 +342,10 @@ func (a *adminService) OrgUpdate(ctx context.Context, req *connect.Request[pb.Or
if err := a.srv.db.OrgUpdate(ctx, ActorFromContext(ctx), ref, req.Msg.Name, slug, req.Msg.Public); err != nil {
return nil, mapErr(err)
}
- return connect.NewResponse(&pb.OrgUpdateResponse{}), nil
+ return connect.NewResponse(&apipb.OrgUpdateResponse{}), nil
}
-func (a *adminService) OrgDelete(ctx context.Context, req *connect.Request[pb.OrgDeleteRequest]) (*connect.Response[pb.OrgDeleteResponse], error) {
+func (a *consoleService) OrgDelete(ctx context.Context, req *connect.Request[apipb.OrgDeleteRequest]) (*connect.Response[apipb.OrgDeleteResponse], error) {
ref, err := orgRef(req.Msg.Org)
if err != nil {
return nil, mapErr(err)
@@ -353,15 +353,15 @@ func (a *adminService) OrgDelete(ctx context.Context, req *connect.Request[pb.Or
if err := a.srv.db.OrgDelete(ctx, ActorFromContext(ctx), ref); err != nil {
return nil, mapErr(err)
}
- return connect.NewResponse(&pb.OrgDeleteResponse{}), nil
+ return connect.NewResponse(&apipb.OrgDeleteResponse{}), nil
}
// --- OrgMember handlers ---
-func (a *adminService) OrgMemberAdd(ctx context.Context, req *connect.Request[pb.OrgMemberAddRequest]) (*connect.Response[pb.OrgMemberAddResponse], error) {
+func (a *consoleService) OrgMemberAdd(ctx context.Context, req *connect.Request[apipb.OrgMemberAddRequest]) (*connect.Response[apipb.OrgMemberAddResponse], error) {
role, ok := roleToString[req.Msg.Role]
if !ok {
- return nil, newAPIError(connect.CodeInvalidArgument, pb.ErrorReason_ERROR_REASON_INVALID_ROLE, nil)
+ return nil, newAPIError(connect.CodeInvalidArgument, apipb.ErrorReason_ERROR_REASON_INVALID_ROLE, nil)
}
org, err := orgRef(req.Msg.Org)
if err != nil {
@@ -374,10 +374,10 @@ func (a *adminService) OrgMemberAdd(ctx context.Context, req *connect.Request[pb
if err := a.srv.db.OrgMemberAdd(ctx, ActorFromContext(ctx), org, user, role); err != nil {
return nil, mapErr(err)
}
- return connect.NewResponse(&pb.OrgMemberAddResponse{}), nil
+ return connect.NewResponse(&apipb.OrgMemberAddResponse{}), nil
}
-func (a *adminService) OrgMemberGet(ctx context.Context, req *connect.Request[pb.OrgMemberGetRequest]) (*connect.Response[pb.OrgMemberGetResponse], error) {
+func (a *consoleService) OrgMemberGet(ctx context.Context, req *connect.Request[apipb.OrgMemberGetRequest]) (*connect.Response[apipb.OrgMemberGetResponse], error) {
org, err := orgRef(req.Msg.Org)
if err != nil {
return nil, mapErr(err)
@@ -390,10 +390,10 @@ func (a *adminService) OrgMemberGet(ctx context.Context, req *connect.Request[pb
if err != nil {
return nil, mapErr(err)
}
- return connect.NewResponse(&pb.OrgMemberGetResponse{Member: memberToProto(*m)}), nil
+ return connect.NewResponse(&apipb.OrgMemberGetResponse{Member: memberToProto(*m)}), nil
}
-func (a *adminService) OrgMemberList(ctx context.Context, req *connect.Request[pb.OrgMemberListRequest]) (*connect.Response[pb.OrgMemberListResponse], error) {
+func (a *consoleService) OrgMemberList(ctx context.Context, req *connect.Request[apipb.OrgMemberListRequest]) (*connect.Response[apipb.OrgMemberListResponse], error) {
cursor, limit, err := pageParams[UserKind](req.Msg.Page)
if err != nil {
return nil, mapErr(err)
@@ -412,7 +412,7 @@ func (a *adminService) OrgMemberList(ctx context.Context, req *connect.Request[p
return nil, mapErr(err)
}
- out := make([]*pb.OrgMemberInfo, len(members))
+ out := make([]*apipb.OrgMemberInfo, len(members))
for i := range members {
out[i] = memberToProto(members[i])
}
@@ -422,16 +422,16 @@ func (a *adminService) OrgMemberList(ctx context.Context, req *connect.Request[p
lastID = members[len(members)-1].User.ID
}
- return connect.NewResponse(&pb.OrgMemberListResponse{
+ return connect.NewResponse(&apipb.OrgMemberListResponse{
Page: pageResponse(len(members), limit, lastID, total),
Members: out,
}), nil
}
-func (a *adminService) OrgMemberUpdate(ctx context.Context, req *connect.Request[pb.OrgMemberUpdateRequest]) (*connect.Response[pb.OrgMemberUpdateResponse], error) {
+func (a *consoleService) OrgMemberUpdate(ctx context.Context, req *connect.Request[apipb.OrgMemberUpdateRequest]) (*connect.Response[apipb.OrgMemberUpdateResponse], error) {
role, ok := roleToString[req.Msg.Role]
if !ok {
- return nil, newAPIError(connect.CodeInvalidArgument, pb.ErrorReason_ERROR_REASON_INVALID_ROLE, nil)
+ return nil, newAPIError(connect.CodeInvalidArgument, apipb.ErrorReason_ERROR_REASON_INVALID_ROLE, nil)
}
org, err := orgRef(req.Msg.Org)
if err != nil {
@@ -444,10 +444,10 @@ func (a *adminService) OrgMemberUpdate(ctx context.Context, req *connect.Request
if err := a.srv.db.OrgMemberUpdateRole(ctx, ActorFromContext(ctx), org, user, role); err != nil {
return nil, mapErr(err)
}
- return connect.NewResponse(&pb.OrgMemberUpdateResponse{}), nil
+ return connect.NewResponse(&apipb.OrgMemberUpdateResponse{}), nil
}
-func (a *adminService) OrgMemberRemove(ctx context.Context, req *connect.Request[pb.OrgMemberRemoveRequest]) (*connect.Response[pb.OrgMemberRemoveResponse], error) {
+func (a *consoleService) OrgMemberRemove(ctx context.Context, req *connect.Request[apipb.OrgMemberRemoveRequest]) (*connect.Response[apipb.OrgMemberRemoveResponse], error) {
org, err := orgRef(req.Msg.Org)
if err != nil {
return nil, mapErr(err)
@@ -459,12 +459,12 @@ func (a *adminService) OrgMemberRemove(ctx context.Context, req *connect.Request
if err := a.srv.db.OrgMemberRemove(ctx, ActorFromContext(ctx), org, user); err != nil {
return nil, mapErr(err)
}
- return connect.NewResponse(&pb.OrgMemberRemoveResponse{}), nil
+ return connect.NewResponse(&apipb.OrgMemberRemoveResponse{}), nil
}
// --- Worker handlers ---
-func (a *adminService) WorkerCreate(ctx context.Context, req *connect.Request[pb.WorkerCreateRequest]) (*connect.Response[pb.WorkerCreateResponse], error) {
+func (a *consoleService) WorkerCreate(ctx context.Context, req *connect.Request[apipb.WorkerCreateRequest]) (*connect.Response[apipb.WorkerCreateResponse], error) {
var org *OrgRef
if req.Msg.Org != nil {
r, err := orgRef(req.Msg.Org)
@@ -477,10 +477,10 @@ func (a *adminService) WorkerCreate(ctx context.Context, req *connect.Request[pb
if err != nil {
return nil, mapErr(err)
}
- return connect.NewResponse(&pb.WorkerCreateResponse{Id: id.Bytes()}), nil
+ return connect.NewResponse(&apipb.WorkerCreateResponse{Id: id.Bytes()}), nil
}
-func (a *adminService) WorkerGet(ctx context.Context, req *connect.Request[pb.WorkerGetRequest]) (*connect.Response[pb.WorkerGetResponse], error) {
+func (a *consoleService) WorkerGet(ctx context.Context, req *connect.Request[apipb.WorkerGetRequest]) (*connect.Response[apipb.WorkerGetResponse], error) {
wid, err := IDFromBytes[WorkerKind](req.Msg.Id)
if err != nil {
return nil, mapErr(err)
@@ -489,10 +489,10 @@ func (a *adminService) WorkerGet(ctx context.Context, req *connect.Request[pb.Wo
if err != nil {
return nil, mapErr(err)
}
- return connect.NewResponse(&pb.WorkerGetResponse{Worker: workerToProto(*w)}), nil
+ return connect.NewResponse(&apipb.WorkerGetResponse{Worker: workerToProto(*w)}), nil
}
-func (a *adminService) WorkerList(ctx context.Context, req *connect.Request[pb.WorkerListRequest]) (*connect.Response[pb.WorkerListResponse], error) {
+func (a *consoleService) WorkerList(ctx context.Context, req *connect.Request[apipb.WorkerListRequest]) (*connect.Response[apipb.WorkerListResponse], error) {
cursor, limit, err := pageParams[WorkerKind](req.Msg.Page)
if err != nil {
return nil, mapErr(err)
@@ -507,7 +507,7 @@ func (a *adminService) WorkerList(ctx context.Context, req *connect.Request[pb.W
return nil, mapErr(err)
}
- out := make([]*pb.Worker, len(workers))
+ out := make([]*apipb.Worker, len(workers))
for i := range workers {
out[i] = workerToProto(workers[i])
}
@@ -517,13 +517,13 @@ func (a *adminService) WorkerList(ctx context.Context, req *connect.Request[pb.W
lastID = workers[len(workers)-1].ID
}
- return connect.NewResponse(&pb.WorkerListResponse{
+ return connect.NewResponse(&apipb.WorkerListResponse{
Page: pageResponse(len(workers), limit, lastID, total),
Workers: out,
}), nil
}
-func (a *adminService) WorkerDelete(ctx context.Context, req *connect.Request[pb.WorkerDeleteRequest]) (*connect.Response[pb.WorkerDeleteResponse], error) {
+func (a *consoleService) WorkerDelete(ctx context.Context, req *connect.Request[apipb.WorkerDeleteRequest]) (*connect.Response[apipb.WorkerDeleteResponse], error) {
wid, err := IDFromBytes[WorkerKind](req.Msg.Id)
if err != nil {
return nil, mapErr(err)
@@ -531,5 +531,5 @@ func (a *adminService) WorkerDelete(ctx context.Context, req *connect.Request[pb
if err := a.srv.db.WorkerDelete(ctx, ActorFromContext(ctx), wid); err != nil {
return nil, mapErr(err)
}
- return connect.NewResponse(&pb.WorkerDeleteResponse{}), nil
+ return connect.NewResponse(&apipb.WorkerDeleteResponse{}), nil
}
diff --git a/cmd/mirumd/server_grpc.go b/cmd/mirum-server/server_grpc.go
index a41604d..a2f7cf0 100644
--- a/cmd/mirumd/server_grpc.go
+++ b/cmd/mirum-server/server_grpc.go
@@ -20,14 +20,14 @@ import (
"dimidiumlabs/mirum/internal/config"
"dimidiumlabs/mirum/internal/protocol"
- "dimidiumlabs/mirum/internal/protocol/pb"
- "dimidiumlabs/mirum/internal/protocol/pb/pbconnect"
+ "dimidiumlabs/mirum/internal/protocol/wirepb"
+ "dimidiumlabs/mirum/internal/protocol/wirepb/wirepbconnect"
)
func NewGrpcServer(ctx context.Context, srv *server) *http.Server {
gsrv := &grpcService{srv: srv}
- path, handler := pbconnect.NewMirumHandler(gsrv,
+ path, handler := wirepbconnect.NewWorkerHandler(gsrv,
connect.WithInterceptors(validate.NewInterceptor()),
)
@@ -80,11 +80,11 @@ func NewGrpcServer(ctx context.Context, srv *server) *http.Server {
// grpcService is the ConnectRPC transport adapter over server.
type grpcService struct {
- pbconnect.UnimplementedMirumHandler
+ wirepbconnect.UnimplementedWorkerHandler
srv *server
}
-func (g *grpcService) Poll(ctx context.Context, req *connect.Request[pb.PollRequest]) (*connect.Response[pb.Task], error) {
+func (g *grpcService) Poll(ctx context.Context, req *connect.Request[wirepb.PollRequest]) (*connect.Response[wirepb.Task], error) {
select {
case task, ok := <-g.srv.queue:
if !ok {
@@ -97,11 +97,11 @@ func (g *grpcService) Poll(ctx context.Context, req *connect.Request[pb.PollRequ
}
}
-func (g *grpcService) Complete(ctx context.Context, req *connect.Request[pb.TaskResult]) (*connect.Response[pb.CompleteResponse], error) {
+func (g *grpcService) Complete(ctx context.Context, req *connect.Request[wirepb.TaskResult]) (*connect.Response[wirepb.CompleteResponse], error) {
if err := g.srv.complete(ctx, req.Msg.TaskId, req.Msg.Success, req.Msg.Error); err != nil {
return nil, err
}
- return connect.NewResponse(&pb.CompleteResponse{}), nil
+ return connect.NewResponse(&wirepb.CompleteResponse{}), nil
}
// workerLog logs worker metadata from the mTLS client certificate
diff --git a/cmd/mirumd/server_web.go b/cmd/mirum-server/server_web.go
index 13c5154..8e62e53 100644
--- a/cmd/mirumd/server_web.go
+++ b/cmd/mirum-server/server_web.go
@@ -21,9 +21,9 @@ import (
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/httprate"
+ "dimidiumlabs/mirum/cmd/mirum-server/apipb"
"dimidiumlabs/mirum/internal/config"
"dimidiumlabs/mirum/internal/forges"
- "dimidiumlabs/mirum/internal/protocol/pb"
)
// __Host- prefixed cookies can only be set with Secure, Path=/, and no
@@ -34,7 +34,7 @@ const (
csrfCookie = "__Host-csrf"
)
-func NewWebServer(ctx context.Context, srv *server, adminPath string, adminHandler http.Handler) *http.Server {
+func NewWebServer(ctx context.Context, srv *server, consolePath string, consoleHandler http.Handler) *http.Server {
h := &webHandler{
srv: srv,
assets: newAssetResolver(),
@@ -90,7 +90,7 @@ func NewWebServer(ctx context.Context, srv *server, adminPath string, adminHandl
})
r.With(middleware.NoCache, httprate.LimitByIP(config.APIRateLimit, config.APIRateWindow)).
- Mount("/api/v1", http.StripPrefix("/api/v1", adminHandler))
+ Mount("/api/v1", http.StripPrefix("/api/v1", consoleHandler))
r.NotFound(func(w http.ResponseWriter, r *http.Request) {
h.renderError(w, r, http.StatusNotFound)
@@ -221,15 +221,15 @@ func (h *webHandler) webhook(w http.ResponseWriter, r *http.Request) {
}
func (h *webHandler) loginPage(w http.ResponseWriter, r *http.Request) {
- h.renderLogin(w, r, http.StatusOK, pb.ErrorReason_ERROR_REASON_UNSPECIFIED)
+ h.renderLogin(w, r, http.StatusOK, apipb.ErrorReason_ERROR_REASON_UNSPECIFIED)
}
// renderLogin is the single entry point for every login-flow outcome that
// lands back on the login page. Reason == UNSPECIFIED means no error banner.
// No caller writes error text itself — the client maps reason → copy.
-func (h *webHandler) renderLogin(w http.ResponseWriter, r *http.Request, status int, reason pb.ErrorReason) {
+func (h *webHandler) renderLogin(w http.ResponseWriter, r *http.Request, status int, reason apipb.ErrorReason) {
data := map[string]any{"csrf": csrfToken(w, r)}
- if reason != pb.ErrorReason_ERROR_REASON_UNSPECIFIED {
+ if reason != apipb.ErrorReason_ERROR_REASON_UNSPECIFIED {
data["errorReason"] = int32(reason)
}
h.assets.renderPage(w, "login", status, data)
@@ -238,7 +238,7 @@ func (h *webHandler) renderLogin(w http.ResponseWriter, r *http.Request, status
func (h *webHandler) login(w http.ResponseWriter, r *http.Request) {
if !csrfOK(r) {
clearCookie(w, csrfCookie)
- h.renderLogin(w, r, http.StatusForbidden, pb.ErrorReason_ERROR_REASON_INVALID_CSRF)
+ h.renderLogin(w, r, http.StatusForbidden, apipb.ErrorReason_ERROR_REASON_INVALID_CSRF)
return
}
@@ -247,14 +247,14 @@ func (h *webHandler) login(w http.ResponseWriter, r *http.Request) {
userID, err := h.srv.db.UserVerifyPassword(r.Context(), SystemActor(), email, password, []byte(h.srv.cfg.Pepper))
if err != nil {
- h.renderLogin(w, r, http.StatusUnauthorized, pb.ErrorReason_ERROR_REASON_INVALID_CREDENTIALS)
+ h.renderLogin(w, r, http.StatusUnauthorized, apipb.ErrorReason_ERROR_REASON_INVALID_CREDENTIALS)
return
}
token, err := h.srv.db.UserSessionCreate(r.Context(), SystemActor(), userID)
if err != nil {
slog.Error("create session failed", "err", err)
- h.renderLogin(w, r, http.StatusInternalServerError, pb.ErrorReason_ERROR_REASON_INTERNAL)
+ h.renderLogin(w, r, http.StatusInternalServerError, apipb.ErrorReason_ERROR_REASON_INTERNAL)
return
}
diff --git a/cmd/mirumd/static.go b/cmd/mirum-server/static.go
index bc304ba..bc304ba 100644
--- a/cmd/mirumd/static.go
+++ b/cmd/mirum-server/static.go
diff --git a/cmd/mirumd/static_dev.go b/cmd/mirum-server/static_dev.go
index 2f6d559..2f6d559 100644
--- a/cmd/mirumd/static_dev.go
+++ b/cmd/mirum-server/static_dev.go
diff --git a/cmd/mirumd/static_prod.go b/cmd/mirum-server/static_prod.go
index 891b04e..891b04e 100644
--- a/cmd/mirumd/static_prod.go
+++ b/cmd/mirum-server/static_prod.go
diff --git a/cmd/mirumd/web/api/client.ts b/cmd/mirum-server/web/api/client.ts
index 5d0ebc3..669fd60 100644
--- a/cmd/mirumd/web/api/client.ts
+++ b/cmd/mirum-server/web/api/client.ts
@@ -3,7 +3,7 @@
import { createClient, type Interceptor } from "@connectrpc/connect"
import { createConnectTransport } from "@connectrpc/connect-web"
-import { Admin, ErrorReason } from "@/gen/admin_pb"
+import { Console, ErrorReason } from "@/gen/api_pb"
import { errorReason } from "@/lib/errors"
const csrfInterceptor = (csrfToken: string): Interceptor =>
@@ -25,10 +25,10 @@ const authInterceptor: Interceptor = (next) => async (req) => {
}
}
-export function createAdminClient(csrfToken: string) {
+export function createConsoleClient(csrfToken: string) {
const transport = createConnectTransport({
baseUrl: "/api/v1",
interceptors: [csrfInterceptor(csrfToken), authInterceptor],
})
- return createClient(Admin, transport)
+ return createClient(Console, transport)
}
diff --git a/cmd/mirumd/web/components.json b/cmd/mirum-server/web/components.json
index a2f7d0b..a2f7d0b 100644
--- a/cmd/mirumd/web/components.json
+++ b/cmd/mirum-server/web/components.json
diff --git a/cmd/mirumd/web/components/pages/dashboard.tsx b/cmd/mirum-server/web/components/pages/dashboard.tsx
index 51c2f83..dcfd8ba 100644
--- a/cmd/mirumd/web/components/pages/dashboard.tsx
+++ b/cmd/mirum-server/web/components/pages/dashboard.tsx
@@ -2,9 +2,9 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import { useEffect, useMemo, useState } from "react"
-import { createAdminClient } from "@/api/client"
+import { createConsoleClient } from "@/api/client"
import { formatError } from "@/lib/errors"
-import type { Org } from "@/gen/admin_pb"
+import type { Org } from "@/gen/api_pb"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
@@ -14,7 +14,7 @@ export type DashboardProps = {
}
export function Page({ user, csrf }: DashboardProps) {
- const client = useMemo(() => createAdminClient(csrf), [csrf])
+ const client = useMemo(() => createConsoleClient(csrf), [csrf])
const [orgs, setOrgs] = useState<Org[] | null>(null)
const [error, setError] = useState<string | null>(null)
diff --git a/cmd/mirumd/web/components/pages/error.tsx b/cmd/mirum-server/web/components/pages/error.tsx
index 9184ed2..9184ed2 100644
--- a/cmd/mirumd/web/components/pages/error.tsx
+++ b/cmd/mirum-server/web/components/pages/error.tsx
diff --git a/cmd/mirumd/web/components/pages/login.tsx b/cmd/mirum-server/web/components/pages/login.tsx
index 71d07db..4e85144 100644
--- a/cmd/mirumd/web/components/pages/login.tsx
+++ b/cmd/mirum-server/web/components/pages/login.tsx
@@ -7,7 +7,7 @@ import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Field, FieldDescription, FieldGroup, FieldLabel } from "@/components/ui/field"
-import { ErrorReason } from "@/gen/admin_pb"
+import { ErrorReason } from "@/gen/api_pb"
import { textForReason } from "@/lib/errors"
export type LoginFormProps = {
diff --git a/cmd/mirumd/web/components/ui/alert.tsx b/cmd/mirum-server/web/components/ui/alert.tsx
index 746962e..746962e 100644
--- a/cmd/mirumd/web/components/ui/alert.tsx
+++ b/cmd/mirum-server/web/components/ui/alert.tsx
diff --git a/cmd/mirumd/web/components/ui/button.tsx b/cmd/mirum-server/web/components/ui/button.tsx
index ca6d679..ca6d679 100644
--- a/cmd/mirumd/web/components/ui/button.tsx
+++ b/cmd/mirum-server/web/components/ui/button.tsx
diff --git a/cmd/mirumd/web/components/ui/card.tsx b/cmd/mirum-server/web/components/ui/card.tsx
index 9859e5f..9859e5f 100644
--- a/cmd/mirumd/web/components/ui/card.tsx
+++ b/cmd/mirum-server/web/components/ui/card.tsx
diff --git a/cmd/mirumd/web/components/ui/field.tsx b/cmd/mirum-server/web/components/ui/field.tsx
index 9517f55..9517f55 100644
--- a/cmd/mirumd/web/components/ui/field.tsx
+++ b/cmd/mirum-server/web/components/ui/field.tsx
diff --git a/cmd/mirumd/web/components/ui/input.tsx b/cmd/mirum-server/web/components/ui/input.tsx
index 2bd6cad..2bd6cad 100644
--- a/cmd/mirumd/web/components/ui/input.tsx
+++ b/cmd/mirum-server/web/components/ui/input.tsx
diff --git a/cmd/mirumd/web/components/ui/label.tsx b/cmd/mirum-server/web/components/ui/label.tsx
index 48d4304..48d4304 100644
--- a/cmd/mirumd/web/components/ui/label.tsx
+++ b/cmd/mirum-server/web/components/ui/label.tsx
diff --git a/cmd/mirumd/web/components/ui/separator.tsx b/cmd/mirum-server/web/components/ui/separator.tsx
index 3c2a347..3c2a347 100644
--- a/cmd/mirumd/web/components/ui/separator.tsx
+++ b/cmd/mirum-server/web/components/ui/separator.tsx
diff --git a/cmd/mirumd/web/entries/dashboard.tsx b/cmd/mirum-server/web/entries/dashboard.tsx
index 0921015..0921015 100644
--- a/cmd/mirumd/web/entries/dashboard.tsx
+++ b/cmd/mirum-server/web/entries/dashboard.tsx
diff --git a/cmd/mirumd/web/entries/error.tsx b/cmd/mirum-server/web/entries/error.tsx
index 10b509e..10b509e 100644
--- a/cmd/mirumd/web/entries/error.tsx
+++ b/cmd/mirum-server/web/entries/error.tsx
diff --git a/cmd/mirumd/web/entries/login.tsx b/cmd/mirum-server/web/entries/login.tsx
index 36428f9..36428f9 100644
--- a/cmd/mirumd/web/entries/login.tsx
+++ b/cmd/mirum-server/web/entries/login.tsx
diff --git a/cmd/mirumd/web/index.css b/cmd/mirum-server/web/index.css
index 1c06db4..1c06db4 100644
--- a/cmd/mirumd/web/index.css
+++ b/cmd/mirum-server/web/index.css
diff --git a/cmd/mirumd/web/lib/errors.ts b/cmd/mirum-server/web/lib/errors.ts
index cf8a20b..2244d1b 100644
--- a/cmd/mirumd/web/lib/errors.ts
+++ b/cmd/mirum-server/web/lib/errors.ts
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import { Code, ConnectError } from "@connectrpc/connect"
-import { ErrorInfoSchema, ErrorReason } from "@/gen/admin_pb"
+import { ErrorInfoSchema, ErrorReason } from "@/gen/api_pb"
// errorReason extracts the ErrorInfo.reason attached by the server.
// Returns null for transport failures or non-mirum responses.
diff --git a/cmd/mirumd/web/lib/mount.tsx b/cmd/mirum-server/web/lib/mount.tsx
index 2c026ab..2c026ab 100644
--- a/cmd/mirumd/web/lib/mount.tsx
+++ b/cmd/mirum-server/web/lib/mount.tsx
diff --git a/cmd/mirumd/web/lib/utils.ts b/cmd/mirum-server/web/lib/utils.ts
index 5d8fa3d..5d8fa3d 100644
--- a/cmd/mirumd/web/lib/utils.ts
+++ b/cmd/mirum-server/web/lib/utils.ts
diff --git a/cmd/mirumd/web/package-lock.json b/cmd/mirum-server/web/package-lock.json
index aeb900c..aeb900c 100644
--- a/cmd/mirumd/web/package-lock.json
+++ b/cmd/mirum-server/web/package-lock.json
diff --git a/cmd/mirumd/web/package.json b/cmd/mirum-server/web/package.json
index ce805ca..ce805ca 100644
--- a/cmd/mirumd/web/package.json
+++ b/cmd/mirum-server/web/package.json
diff --git a/cmd/mirumd/web/shell.html b/cmd/mirum-server/web/shell.html
index ce74041..ce74041 100644
--- a/cmd/mirumd/web/shell.html
+++ b/cmd/mirum-server/web/shell.html
diff --git a/cmd/mirumd/web/tsconfig.json b/cmd/mirum-server/web/tsconfig.json
index 90b2f46..90b2f46 100644
--- a/cmd/mirumd/web/tsconfig.json
+++ b/cmd/mirum-server/web/tsconfig.json
diff --git a/cmd/mirumd/web/vite.config.ts b/cmd/mirum-server/web/vite.config.ts
index 6de11ff..6de11ff 100644
--- a/cmd/mirumd/web/vite.config.ts
+++ b/cmd/mirum-server/web/vite.config.ts
diff --git a/cmd/mirumw/client.go b/cmd/mirum-worker/client.go
index 7f3886d..1525904 100644
--- a/cmd/mirumw/client.go
+++ b/cmd/mirum-worker/client.go
@@ -17,14 +17,14 @@ import (
"dimidiumlabs/mirum/internal/executor"
"dimidiumlabs/mirum/internal/protocol"
- "dimidiumlabs/mirum/internal/protocol/pb"
- "dimidiumlabs/mirum/internal/protocol/pb/pbconnect"
+ "dimidiumlabs/mirum/internal/protocol/wirepb"
+ "dimidiumlabs/mirum/internal/protocol/wirepb/wirepbconnect"
)
type client struct {
cfg *config
http *http.Client
- handle pbconnect.MirumClient
+ handle wirepbconnect.WorkerClient
}
func dial(ctx context.Context, cfg *config) (*client, error) {
@@ -75,7 +75,7 @@ func dial(ctx context.Context, cfg *config) (*client, error) {
Transport: &http.Transport{TLSClientConfig: tlsCfg, ForceAttemptHTTP2: true},
},
}
- c.handle = pbconnect.NewMirumClient(c.http, "https://"+cfg.Server, connect.WithGRPC())
+ c.handle = wirepbconnect.NewWorkerClient(c.http, "https://"+cfg.Server, connect.WithGRPC())
slog.Info("dialing", "server", cfg.Server)
@@ -86,7 +86,7 @@ func (c *client) close() {}
func (c *client) work(ctx context.Context) error {
for ctx.Err() == nil {
- resp, err := c.handle.Poll(ctx, connect.NewRequest(&pb.PollRequest{}))
+ resp, err := c.handle.Poll(ctx, connect.NewRequest(&wirepb.PollRequest{}))
if err != nil {
return fmt.Errorf("poll: %w", err)
}
@@ -100,7 +100,7 @@ func (c *client) work(ctx context.Context) error {
execErr := executor.Run(task.CloneUrl, task.Branch)
- result := &pb.TaskResult{TaskId: task.Id, Success: execErr == nil}
+ result := &wirepb.TaskResult{TaskId: task.Id, Success: execErr == nil}
if execErr != nil {
result.Error = execErr.Error()
slog.Error("task failed", "id", task.Id, "err", execErr)
diff --git a/cmd/mirumw/config.go b/cmd/mirum-worker/config.go
index 50e82d3..366fdf4 100644
--- a/cmd/mirumw/config.go
+++ b/cmd/mirum-worker/config.go
@@ -11,7 +11,7 @@ import (
)
// Runtime type of this worker binary. Different worker types
-// (mirumw-vm, mirumw-docker, etc.) will have different values.
+// (mirum-worker-vm, mirum-worker-docker, etc.) will have different values.
const workerRuntime = "host"
type config struct {
diff --git a/cmd/mirumw/main.go b/cmd/mirum-worker/main.go
index e2132b5..e2132b5 100644
--- a/cmd/mirumw/main.go
+++ b/cmd/mirum-worker/main.go
diff --git a/internal/config/config.go b/internal/config/config.go
index c9d0521..3d1256c 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -1,7 +1,7 @@
// Copyright (c) 2026 Nikolay Govorov
// SPDX-License-Identifier: AGPL-3.0-or-later
-// Package config holds hard-coded tunables shared across mirumd and mirumw:
+// Package config holds hard-coded tunables shared across mirum-server and mirum-worker:
// timeouts, sizes, intervals, and limits that are not (yet) exposed through
// the YAML user config. Grouping them here keeps magic numbers out of call
// sites and gives a single place to audit defaults.
diff --git a/internal/protocol/platform.go b/internal/protocol/platform.go
index 638a664..d48da44 100644
--- a/internal/protocol/platform.go
+++ b/internal/protocol/platform.go
@@ -11,7 +11,7 @@ import (
"strings"
mirum "dimidiumlabs/mirum"
- "dimidiumlabs/mirum/internal/protocol/pb"
+ "dimidiumlabs/mirum/internal/protocol/wirepb"
)
var ErrInvalidVersion = errors.New("invalid version string")
@@ -22,53 +22,53 @@ var (
Patch uint32
)
-var osMap = map[string]pb.Os{
- "linux": pb.Os_OS_LINUX,
- "darwin": pb.Os_OS_DARWIN,
- "windows": pb.Os_OS_WINDOWS,
- "freebsd": pb.Os_OS_FREEBSD,
- "openbsd": pb.Os_OS_OPENBSD,
- "netbsd": pb.Os_OS_NETBSD,
- "dragonfly": pb.Os_OS_DRAGONFLY,
- "illumos": pb.Os_OS_ILLUMOS,
- "solaris": pb.Os_OS_SOLARIS,
- "aix": pb.Os_OS_AIX,
- "plan9": pb.Os_OS_PLAN9,
- "android": pb.Os_OS_ANDROID,
- "ios": pb.Os_OS_IOS,
- "js": pb.Os_OS_JS,
- "wasip1": pb.Os_OS_WASIP1,
+var osMap = map[string]wirepb.Os{
+ "linux": wirepb.Os_OS_LINUX,
+ "darwin": wirepb.Os_OS_DARWIN,
+ "windows": wirepb.Os_OS_WINDOWS,
+ "freebsd": wirepb.Os_OS_FREEBSD,
+ "openbsd": wirepb.Os_OS_OPENBSD,
+ "netbsd": wirepb.Os_OS_NETBSD,
+ "dragonfly": wirepb.Os_OS_DRAGONFLY,
+ "illumos": wirepb.Os_OS_ILLUMOS,
+ "solaris": wirepb.Os_OS_SOLARIS,
+ "aix": wirepb.Os_OS_AIX,
+ "plan9": wirepb.Os_OS_PLAN9,
+ "android": wirepb.Os_OS_ANDROID,
+ "ios": wirepb.Os_OS_IOS,
+ "js": wirepb.Os_OS_JS,
+ "wasip1": wirepb.Os_OS_WASIP1,
}
-var archMap = map[string]pb.Arch{
- "amd64": pb.Arch_ARCH_AMD64,
- "arm64": pb.Arch_ARCH_ARM64,
- "386": pb.Arch_ARCH_386,
- "arm": pb.Arch_ARCH_ARM,
- "riscv64": pb.Arch_ARCH_RISCV64,
- "ppc64le": pb.Arch_ARCH_PPC64LE,
- "ppc64": pb.Arch_ARCH_PPC64,
- "s390x": pb.Arch_ARCH_S390X,
- "mips64le": pb.Arch_ARCH_MIPS64LE,
- "mips64": pb.Arch_ARCH_MIPS64,
- "mipsle": pb.Arch_ARCH_MIPSLE,
- "mips": pb.Arch_ARCH_MIPS,
- "loong64": pb.Arch_ARCH_LOONG64,
- "wasm": pb.Arch_ARCH_WASM,
+var archMap = map[string]wirepb.Arch{
+ "amd64": wirepb.Arch_ARCH_AMD64,
+ "arm64": wirepb.Arch_ARCH_ARM64,
+ "386": wirepb.Arch_ARCH_386,
+ "arm": wirepb.Arch_ARCH_ARM,
+ "riscv64": wirepb.Arch_ARCH_RISCV64,
+ "ppc64le": wirepb.Arch_ARCH_PPC64LE,
+ "ppc64": wirepb.Arch_ARCH_PPC64,
+ "s390x": wirepb.Arch_ARCH_S390X,
+ "mips64le": wirepb.Arch_ARCH_MIPS64LE,
+ "mips64": wirepb.Arch_ARCH_MIPS64,
+ "mipsle": wirepb.Arch_ARCH_MIPSLE,
+ "mips": wirepb.Arch_ARCH_MIPS,
+ "loong64": wirepb.Arch_ARCH_LOONG64,
+ "wasm": wirepb.Arch_ARCH_WASM,
}
-func DetectOs() pb.Os {
+func DetectOs() wirepb.Os {
if v, ok := osMap[runtime.GOOS]; ok {
return v
}
- return pb.Os_OS_UNSPECIFIED
+ return wirepb.Os_OS_UNSPECIFIED
}
-func DetectArch() pb.Arch {
+func DetectArch() wirepb.Arch {
if v, ok := archMap[runtime.GOARCH]; ok {
return v
}
- return pb.Arch_ARCH_UNSPECIFIED
+ return wirepb.Arch_ARCH_UNSPECIFIED
}
func init() {
@@ -99,6 +99,6 @@ func VersionString() string {
return fmt.Sprintf("%d.%d.%d", Major, Minor, Patch)
}
-func VersionProto() *pb.Version {
- return &pb.Version{Major: Major, Minor: Minor, Patch: Patch}
+func VersionProto() *wirepb.Version {
+ return &wirepb.Version{Major: Major, Minor: Minor, Patch: Patch}
}
diff --git a/internal/protocol/proto/buf.gen.yaml b/internal/protocol/proto/buf.gen.yaml
new file mode 100644
--- /dev/null
+++ b/internal/protocol/proto/buf.gen.yaml
@@ -0,0 +1,11 @@
+# Copyright (c) 2026 Nikolay Govorov
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+version: v2
+plugins:
+ - local: protoc-gen-go
+ out: ../wirepb
+ opt: paths=source_relative
+ - local: protoc-gen-connect-go
+ out: ../wirepb
+ opt: paths=source_relative
diff --git a/proto/mirum.proto b/internal/protocol/proto/wire.proto
index dd85e26..73668e7 100644
--- a/proto/mirum.proto
+++ b/internal/protocol/proto/wire.proto
@@ -3,9 +3,9 @@
syntax = "proto3";
-package mirum;
+package mirum.wire;
-option go_package = "dimidiumlabs/mirum/internal/protocol/pb";
+option go_package = "dimidiumlabs/mirum/internal/protocol/wirepb";
// Describes the contract between the worker and the server.
// GRPC is the only contract between them, so to implement your own worker,
@@ -17,7 +17,7 @@ option go_package = "dimidiumlabs/mirum/internal/protocol/pb";
//
// Worker metadata (name, version, os, arch) and clock skew detection
// are embedded in the certificate (URI SAN and NotBefore).
-service Mirum {
+service Worker {
// When a worker has free resources, it requests a task from the server.
// The call will block if the server currently has no tasks.
rpc Poll(PollRequest) returns (Task);
diff --git a/nfpm.yaml b/nfpm.yaml
index f19f0a3..62181e7 100644
--- a/nfpm.yaml
+++ b/nfpm.yaml
@@ -18,55 +18,55 @@ contents:
- src: ./README.md
dst: /usr/share/doc/mirum/README.md
- - src: build/mirumd
- dst: /usr/local/bin/mirumd
+ - src: build/mirum-server
+ dst: /usr/local/bin/mirum-server
file_info:
mode: 0755
- - src: build/mirumw
- dst: /usr/local/bin/mirumw
+ - src: build/mirum-worker
+ dst: /usr/local/bin/mirum-worker
file_info:
mode: 0755
- - src: pkg/mirumd.yaml
- dst: /etc/mirum/mirumd.yaml
+ - src: pkg/server/config.yaml
+ dst: /etc/mirum/server/config.yaml
type: config|noreplace
file_info:
mode: 0640
owner: root
- group: mirumd
+ group: mirum-server
- - src: pkg/mirumw-default.yaml
- dst: /etc/mirum/mirumw-default.yaml
+ - src: pkg/worker/default.yaml
+ dst: /etc/mirum/worker/default.yaml
type: config|noreplace
file_info:
mode: 0640
owner: root
- group: mirumw
+ group: mirum-worker
- - src: pkg/mirumd.service
- dst: /usr/lib/systemd/system/mirumd.service
+ - src: pkg/mirum-server.service
+ dst: /usr/lib/systemd/system/mirum-server.service
file_info:
mode: 0644
- - src: pkg/mirumw@.service
- dst: /usr/lib/systemd/system/mirumw@.service
+ - src: pkg/mirum-worker@.service
+ dst: /usr/lib/systemd/system/mirum-worker@.service
file_info:
mode: 0644
- - dst: /var/lib/mirumd
+ - dst: /var/lib/mirum-server
type: dir
file_info:
mode: 0750
- owner: mirumd
- group: mirumd
+ owner: mirum-server
+ group: mirum-server
- - dst: /var/lib/mirumw
+ - dst: /var/lib/mirum-worker
type: dir
file_info:
mode: 0750
- owner: mirumw
- group: mirumw
+ owner: mirum-worker
+ group: mirum-worker
scripts:
diff --git a/pkg/mirumd.service b/pkg/mirum-server.service
index ab46526..69e440f 100644
--- a/pkg/mirumd.service
+++ b/pkg/mirum-server.service
@@ -8,7 +8,7 @@ After=time-sync.target network-online.target remote-fs.target nss-lookup.target
Wants=time-sync.target
# Socket activation (optional):
-# Create mirumd.socket with named file descriptors "web" and "grpc":
+# Create mirum-server.socket with named file descriptors "web" and "grpc":
#
# [Socket]
# ListenStream=0.0.0.0:3000
@@ -22,14 +22,14 @@ Wants=time-sync.target
[Service]
Type=notify
-User=mirumd
-Group=mirumd
+User=mirum-server
+Group=mirum-server
Restart=always
RestartSec=30
WatchdogSec=30
NotifyAccess=main
-ExecPaths=/usr/local/bin/mirumd /usr/lib
-ExecStart=/usr/local/bin/mirumd daemon --config=/etc/mirum/mirumd.yaml
+ExecPaths=/usr/local/bin/mirum-server /usr/lib
+ExecStart=/usr/local/bin/mirum-server daemon --config=/etc/mirum/server/config.yaml
LimitCORE=infinity
LimitNOFILE=500000
AmbientCapabilities=CAP_NET_BIND_SERVICE
diff --git a/pkg/mirumw@.service b/pkg/mirum-worker@.service
index cf7ddd5..dbbc5e0 100644
--- a/pkg/mirumw@.service
+++ b/pkg/mirum-worker@.service
@@ -9,14 +9,14 @@ Wants=time-sync.target
[Service]
Type=notify
-User=mirumw
-Group=mirumw
+User=mirum-worker
+Group=mirum-worker
Restart=always
RestartSec=30
WatchdogSec=30
NotifyAccess=main
-ExecPaths=/usr/local/bin/mirumw
-ExecStart=/usr/local/bin/mirumw --config=/etc/mirum/mirumw-%i.yaml
+ExecPaths=/usr/local/bin/mirum-worker
+ExecStart=/usr/local/bin/mirum-worker --config=/etc/mirum/worker/%i.yaml
LimitCORE=infinity
LimitNOFILE=500000
AmbientCapabilities=
diff --git a/pkg/scripts/postinstall.sh b/pkg/scripts/postinstall.sh
index 2c80442..3479c75 100644
--- a/pkg/scripts/postinstall.sh
+++ b/pkg/scripts/postinstall.sh
@@ -4,10 +4,10 @@
set -e
-if [ -x "/bin/systemctl" ] && [ -d /run/systemd/system ] && [ -f /usr/lib/systemd/system/mirumd.service ]; then
+if [ -x "/bin/systemctl" ] && [ -d /run/systemd/system ] && [ -f /usr/lib/systemd/system/mirum-server.service ]; then
/bin/systemctl daemon-reload
# Don't enable by default, don't know in advance whether it's a daemon or a worker
- # /bin/systemctl enable mirumd
- # /bin/systemctl enable mirumw
+ # /bin/systemctl enable mirum-server
+ # /bin/systemctl enable mirum-worker
fi
diff --git a/pkg/scripts/preinstall.sh b/pkg/scripts/preinstall.sh
index d15fee2..15f9f40 100644
--- a/pkg/scripts/preinstall.sh
+++ b/pkg/scripts/preinstall.sh
@@ -4,7 +4,7 @@
set -e
-for svc in mirumd mirumw; do
+for svc in mirum-server mirum-worker; do
if ! getent group $svc >/dev/null; then
groupadd --system $svc
fi
diff --git a/pkg/scripts/preremove.sh b/pkg/scripts/preremove.sh
index fdb71a8..1c92a81 100644
--- a/pkg/scripts/preremove.sh
+++ b/pkg/scripts/preremove.sh
@@ -5,9 +5,9 @@
set -e
if [ -x "/bin/systemctl" ] && [ -d /run/systemd/system ]; then
- /bin/systemctl stop mirumd.service || true
- /bin/systemctl disable mirumd.service || true
+ /bin/systemctl stop mirum-server.service || true
+ /bin/systemctl disable mirum-server.service || true
- /bin/systemctl stop 'mirumw@*' || true
- /bin/systemctl disable mirumw@.service || true
+ /bin/systemctl stop 'mirum-worker@*' || true
+ /bin/systemctl disable mirum-worker@.service || true
fi
diff --git a/pkg/mirumd.yaml b/pkg/server/config.yaml
index 4828d9b..6ea9881 100644
--- a/pkg/mirumd.yaml
+++ b/pkg/server/config.yaml
@@ -2,10 +2,10 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
# Ignored when the corresponding systemd socket activation fd is present.
-# See mirumd.socket for details (FileDescriptorName=grpc / web).
+# See mirum-server.socket for details (FileDescriptorName=grpc / web).
grpc_addr: :2026
web_addr: :3000
-admin_socket: /run/mirumd/admin.sock
+admin_socket: /run/mirum-server/admin.sock
database_uri: ""
webhook_secret: ""
token: ""
diff --git a/pkg/mirumw-default.yaml b/pkg/worker/default.yaml
index 3fc2076..f982ba1 100644
--- a/pkg/mirumw-default.yaml
+++ b/pkg/worker/default.yaml
@@ -5,13 +5,13 @@ server: localhost:2026
# Ed25519 private key for worker authentication (PEM-encoded PKCS8).
# Generate with:
-# openssl genpkey -algorithm Ed25519 -out /etc/mirum/mirumw-default.key
-# chmod 600 /etc/mirum/mirumw-default.key
+# openssl genpkey -algorithm Ed25519 -out /etc/mirum/worker/default.key
+# chmod 600 /etc/mirum/worker/default.key
#
# Register the public key on the daemon:
-# PUBKEY=$(openssl pkey -in /etc/mirum/mirumw-default.key -pubout -outform der | base64 -w0)
-# mirumd --socket /run/mirumd/admin.sock worker add --pubkey "$PUBKEY"
-key_file: /etc/mirum/mirumw-default.key
+# PUBKEY=$(openssl pkey -in /etc/mirum/worker/default.key -pubout -outform der | base64 -w0)
+# mirum-server --socket /run/mirum-server/admin.sock worker create --pubkey "$PUBKEY"
+key_file: /etc/mirum/worker/default.key
# Custom CA certificate for self-signed/dev TLS.
# Leave empty to use system trust store.