Change logging and implement gRPC
This commit is contained in:
+2
-2
@@ -204,7 +204,7 @@ Update notification status
|
|||||||
|
|
||||||
### Hierarchy (highest to lowest priority)
|
### Hierarchy (highest to lowest priority)
|
||||||
1. Environment variables (prefixed with `NOTIFIER_`)
|
1. Environment variables (prefixed with `NOTIFIER_`)
|
||||||
2. Configuration file (notifier.config)
|
2. Configuration file (config.yaml)
|
||||||
3. Default values
|
3. Default values
|
||||||
|
|
||||||
### Example Environment Variables
|
### Example Environment Variables
|
||||||
@@ -296,7 +296,7 @@ NOTIFIER_NOTIFIERS_SLACK_WEBHOOK_URL=https://hooks.slack.com/...
|
|||||||
3. Add configuration struct to `internal/config/`
|
3. Add configuration struct to `internal/config/`
|
||||||
4. Register in factory during initialization
|
4. Register in factory during initialization
|
||||||
5. Update protobuf and REST API types
|
5. Update protobuf and REST API types
|
||||||
6. Add configuration example to `notifier.config`
|
6. Add configuration example to `config.yaml`
|
||||||
|
|
||||||
### Adding a New Queue Implementation
|
### Adding a New Queue Implementation
|
||||||
|
|
||||||
|
|||||||
+10
-3
@@ -1,6 +1,11 @@
|
|||||||
# Build stage
|
# Build stage
|
||||||
FROM golang:1.24-alpine AS builder
|
FROM golang:1.24-alpine AS builder
|
||||||
|
|
||||||
|
# Build arguments
|
||||||
|
ARG VERSION=dev
|
||||||
|
ARG GIT_COMMIT=unknown
|
||||||
|
ARG BUILD_TIME=unknown
|
||||||
|
|
||||||
# Install build dependencies
|
# Install build dependencies
|
||||||
RUN apk add --no-cache git make
|
RUN apk add --no-cache git make
|
||||||
|
|
||||||
@@ -16,8 +21,10 @@ RUN go mod download
|
|||||||
# Copy source code
|
# Copy source code
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Build binary
|
# Build binary with version information
|
||||||
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o server ./cmd/server
|
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo \
|
||||||
|
-ldflags "-X main.Version=${VERSION} -X main.GitCommit=${GIT_COMMIT} -X main.BuildTime=${BUILD_TIME}" \
|
||||||
|
-o server ./cmd/server
|
||||||
|
|
||||||
# Runtime stage
|
# Runtime stage
|
||||||
FROM alpine:latest
|
FROM alpine:latest
|
||||||
@@ -36,7 +43,7 @@ WORKDIR /app
|
|||||||
COPY --from=builder /build/server /app/
|
COPY --from=builder /build/server /app/
|
||||||
|
|
||||||
# Copy default config (can be overridden with volume mount)
|
# Copy default config (can be overridden with volume mount)
|
||||||
COPY notifier.config /app/notifier.config
|
COPY config.yaml /app/config.yaml
|
||||||
|
|
||||||
# Create directory for queue persistence
|
# Create directory for queue persistence
|
||||||
RUN mkdir -p /var/lib/notifier && \
|
RUN mkdir -p /var/lib/notifier && \
|
||||||
|
|||||||
@@ -7,12 +7,18 @@ PROTO_OUT=$(PROTO_DIR)/pb
|
|||||||
GO_MODULE=$(shell head -n 1 go.mod | awk '{print $$2}')
|
GO_MODULE=$(shell head -n 1 go.mod | awk '{print $$2}')
|
||||||
GO_FILES=$(shell find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./api/grpc/pb/*")
|
GO_FILES=$(shell find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./api/grpc/pb/*")
|
||||||
|
|
||||||
|
# Build information
|
||||||
|
VERSION ?= dev
|
||||||
|
GIT_COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
|
||||||
|
BUILD_TIME := $(shell date -u '+%Y-%m-%d_%H:%M:%S_UTC')
|
||||||
|
LDFLAGS := -X main.Version=$(VERSION) -X main.GitCommit=$(GIT_COMMIT) -X main.BuildTime=$(BUILD_TIME)
|
||||||
|
|
||||||
# Generate protobuf code
|
# Generate protobuf code
|
||||||
proto-gen:
|
proto-gen:
|
||||||
@echo "Generating protobuf code..."
|
@echo "Generating protobuf code..."
|
||||||
@mkdir -p $(PROTO_OUT)
|
@mkdir -p $(PROTO_OUT)
|
||||||
protoc --go_out=$(PROTO_OUT) --go_opt=paths=source_relative \
|
protoc -I. --go_out=. --go_opt=module=$(GO_MODULE) \
|
||||||
--go-grpc_out=$(PROTO_OUT) --go-grpc_opt=paths=source_relative \
|
--go-grpc_out=. --go-grpc_opt=module=$(GO_MODULE) \
|
||||||
$(PROTO_FILE)
|
$(PROTO_FILE)
|
||||||
@echo "Protobuf code generated successfully"
|
@echo "Protobuf code generated successfully"
|
||||||
|
|
||||||
@@ -39,8 +45,11 @@ proto-deps:
|
|||||||
# Build binary
|
# Build binary
|
||||||
build:
|
build:
|
||||||
@echo "Building binary..."
|
@echo "Building binary..."
|
||||||
|
@echo "Version: $(VERSION)"
|
||||||
|
@echo "Git Commit: $(GIT_COMMIT)"
|
||||||
|
@echo "Build Time: $(BUILD_TIME)"
|
||||||
@mkdir -p bin
|
@mkdir -p bin
|
||||||
go build -o bin/server ./cmd/server
|
go build -ldflags "$(LDFLAGS)" -o bin/server ./cmd/server
|
||||||
@echo "Binary built successfully"
|
@echo "Binary built successfully"
|
||||||
|
|
||||||
# Run server (default: both REST and gRPC)
|
# Run server (default: both REST and gRPC)
|
||||||
@@ -112,13 +121,20 @@ qa: fmt vet lint test
|
|||||||
# Build Docker image
|
# Build Docker image
|
||||||
docker-build:
|
docker-build:
|
||||||
@echo "Building Docker image..."
|
@echo "Building Docker image..."
|
||||||
docker build -t notifier:latest .
|
@echo "Version: $(VERSION)"
|
||||||
|
@echo "Git Commit: $(GIT_COMMIT)"
|
||||||
|
@echo "Build Time: $(BUILD_TIME)"
|
||||||
|
docker build \
|
||||||
|
--build-arg VERSION=$(VERSION) \
|
||||||
|
--build-arg GIT_COMMIT=$(GIT_COMMIT) \
|
||||||
|
--build-arg BUILD_TIME=$(BUILD_TIME) \
|
||||||
|
-t notifier:latest .
|
||||||
@echo "Docker image built successfully"
|
@echo "Docker image built successfully"
|
||||||
|
|
||||||
# Run Docker container
|
# Run Docker container
|
||||||
docker-run:
|
docker-run:
|
||||||
@echo "Running Docker container..."
|
@echo "Running Docker container..."
|
||||||
docker run -p 8080:8080 -p 50051:50051 -v $(PWD)/notifier.config:/app/notifier.config notifier:latest
|
docker run -p 8080:8080 -p 50051:50051 -v $(PWD)/config.yaml:/app/config.yaml notifier:latest
|
||||||
|
|
||||||
# Clean build artifacts
|
# Clean build artifacts
|
||||||
clean:
|
clean:
|
||||||
|
|||||||
+9
-9
@@ -149,7 +149,7 @@ curl http://localhost:8080/api/v1/notifications/{notification-id}
|
|||||||
## Testing with Other Notifiers
|
## Testing with Other Notifiers
|
||||||
|
|
||||||
### SMTP (Email)
|
### SMTP (Email)
|
||||||
Update `notifier.config` with named accounts:
|
Update `config.yaml` with named accounts:
|
||||||
```yaml
|
```yaml
|
||||||
notifiers:
|
notifiers:
|
||||||
smtp:
|
smtp:
|
||||||
@@ -195,7 +195,7 @@ curl -X POST http://localhost:8080/api/v1/notifications \
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Slack
|
### Slack
|
||||||
Update `notifier.config` with named workspaces:
|
Update `config.yaml` with named workspaces:
|
||||||
```yaml
|
```yaml
|
||||||
notifiers:
|
notifiers:
|
||||||
slack:
|
slack:
|
||||||
@@ -235,7 +235,7 @@ curl -X POST http://localhost:8080/api/v1/notifications \
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Ntfy
|
### Ntfy
|
||||||
Update `notifier.config` with named servers:
|
Update `config.yaml` with named servers:
|
||||||
```yaml
|
```yaml
|
||||||
notifiers:
|
notifiers:
|
||||||
ntfy:
|
ntfy:
|
||||||
@@ -287,8 +287,8 @@ export NOTIFIER_NOTIFIERS_SMTP_PASSWORD=secret
|
|||||||
./bin/restserver
|
./bin/restserver
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using notifier.config
|
### Using config.yaml
|
||||||
Create or modify `notifier.config` in the project root:
|
Create or modify `config.yaml` in the project root:
|
||||||
```yaml
|
```yaml
|
||||||
server:
|
server:
|
||||||
rest_port: 8080
|
rest_port: 8080
|
||||||
@@ -312,7 +312,7 @@ docker build -t notifier:latest .
|
|||||||
### Run with Docker
|
### Run with Docker
|
||||||
```bash
|
```bash
|
||||||
docker run -p 8080:8080 \
|
docker run -p 8080:8080 \
|
||||||
-v $(pwd)/notifier.config:/app/notifier.config \
|
-v $(pwd)/config.yaml:/app/config.yaml \
|
||||||
notifier:latest
|
notifier:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -353,18 +353,18 @@ kubectl port-forward svc/notifier-rest 8080:8080
|
|||||||
|
|
||||||
### Server won't start
|
### Server won't start
|
||||||
- Check if port 8080 is already in use: `lsof -i :8080`
|
- Check if port 8080 is already in use: `lsof -i :8080`
|
||||||
- Check notifier.config syntax
|
- Check config.yaml syntax
|
||||||
- Verify all dependencies are installed: `go mod tidy`
|
- Verify all dependencies are installed: `go mod tidy`
|
||||||
|
|
||||||
### Notifications not sending
|
### Notifications not sending
|
||||||
- Check server logs for errors
|
- Check server logs for errors
|
||||||
- Verify the notifier is enabled in notifier.config
|
- Verify the notifier is enabled in config.yaml
|
||||||
- For SMTP: Verify credentials and allow less secure apps
|
- For SMTP: Verify credentials and allow less secure apps
|
||||||
- For Slack: Verify webhook URL is correct
|
- For Slack: Verify webhook URL is correct
|
||||||
- For Ntfy: Ensure topic name is valid
|
- For Ntfy: Ensure topic name is valid
|
||||||
|
|
||||||
### Queue filling up
|
### Queue filling up
|
||||||
- Increase worker count in notifier.config
|
- Increase worker count in config.yaml
|
||||||
- Check if notifiers are failing
|
- Check if notifiers are failing
|
||||||
- Review retry configuration
|
- Review retry configuration
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ curl http://localhost:8080/api/v1/stats
|
|||||||
|
|
||||||
### Basic Setup
|
### Basic Setup
|
||||||
|
|
||||||
Create `notifier.config` in the project root:
|
Create `config.yaml` in the project root:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
server:
|
server:
|
||||||
@@ -380,7 +380,7 @@ docker run -d \
|
|||||||
--name notifier \
|
--name notifier \
|
||||||
-p 8080:8080 \
|
-p 8080:8080 \
|
||||||
-p 50051:50051 \
|
-p 50051:50051 \
|
||||||
-v $(pwd)/notifier.config:/app/notifier.config:ro \
|
-v $(pwd)/config.yaml:/app/config.yaml:ro \
|
||||||
notifier:latest
|
notifier:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -515,7 +515,7 @@ notifier/
|
|||||||
│ └── kustomization.yaml
|
│ └── kustomization.yaml
|
||||||
├── docs/
|
├── docs/
|
||||||
│ └── NTFY_GUIDE.md # Ntfy integration guide
|
│ └── NTFY_GUIDE.md # Ntfy integration guide
|
||||||
├── notifier.config # Default configuration
|
├── config.yaml # Default configuration
|
||||||
├── docker-compose.yaml
|
├── docker-compose.yaml
|
||||||
├── Dockerfile
|
├── Dockerfile
|
||||||
├── Makefile
|
├── Makefile
|
||||||
@@ -552,7 +552,7 @@ make help # Show all available targets
|
|||||||
2. Implement `domain.Notifier` interface
|
2. Implement `domain.Notifier` interface
|
||||||
3. Add config struct to `internal/config/config.go`
|
3. Add config struct to `internal/config/config.go`
|
||||||
4. Register in `cmd/server/main.go`
|
4. Register in `cmd/server/main.go`
|
||||||
5. Update `notifier.config` with example config
|
5. Update `config.yaml` with example config
|
||||||
6. Add tests
|
6. Add tests
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|||||||
@@ -0,0 +1,351 @@
|
|||||||
|
package grpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
pb "github.com/igodwin/notifier/api/grpc/pb"
|
||||||
|
"github.com/igodwin/notifier/internal/domain"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NotifierHandler implements the gRPC NotifierService
|
||||||
|
type NotifierHandler struct {
|
||||||
|
pb.UnimplementedNotifierServiceServer
|
||||||
|
service domain.NotificationService
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNotifierHandler creates a new gRPC handler
|
||||||
|
func NewNotifierHandler(svc domain.NotificationService) *NotifierHandler {
|
||||||
|
return &NotifierHandler{
|
||||||
|
service: svc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HealthCheck verifies the service is operational
|
||||||
|
func (h *NotifierHandler) HealthCheck(ctx context.Context, req *pb.HealthCheckRequest) (*pb.HealthCheckResponse, error) {
|
||||||
|
// TODO: Implement proper health check logic
|
||||||
|
return &pb.HealthCheckResponse{
|
||||||
|
Healthy: true,
|
||||||
|
Status: "ok",
|
||||||
|
Components: map[string]string{
|
||||||
|
"service": "running",
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendNotification sends a single notification
|
||||||
|
func (h *NotifierHandler) SendNotification(ctx context.Context, req *pb.SendNotificationRequest) (*pb.SendNotificationResponse, error) {
|
||||||
|
// Convert proto notification type to domain type
|
||||||
|
notifType := convertProtoTypeToDomain(req.Type)
|
||||||
|
|
||||||
|
// Build notification
|
||||||
|
notification := &domain.Notification{
|
||||||
|
Type: notifType,
|
||||||
|
Account: req.Account,
|
||||||
|
Priority: domain.Priority(req.Priority),
|
||||||
|
Subject: req.Subject,
|
||||||
|
Body: req.Body,
|
||||||
|
Recipients: req.Recipients,
|
||||||
|
Metadata: convertStringMapToInterface(req.Metadata),
|
||||||
|
MaxRetries: int(req.MaxRetries),
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.ScheduledFor != nil {
|
||||||
|
scheduledTime := req.ScheduledFor.AsTime()
|
||||||
|
notification.ScheduledFor = &scheduledTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send notification
|
||||||
|
result, err := h.service.Send(ctx, notification)
|
||||||
|
if err != nil {
|
||||||
|
return &pb.SendNotificationResponse{
|
||||||
|
Result: &pb.NotificationResult{
|
||||||
|
Success: false,
|
||||||
|
Error: err.Error(),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert result to proto
|
||||||
|
return &pb.SendNotificationResponse{
|
||||||
|
Result: &pb.NotificationResult{
|
||||||
|
NotificationId: result.NotificationID,
|
||||||
|
Success: result.Success,
|
||||||
|
Message: result.Message,
|
||||||
|
SentAt: timestamppb.New(result.SentAt),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendBatchNotifications sends multiple notifications
|
||||||
|
func (h *NotifierHandler) SendBatchNotifications(ctx context.Context, req *pb.SendBatchNotificationsRequest) (*pb.SendBatchNotificationsResponse, error) {
|
||||||
|
var results []*pb.NotificationResult
|
||||||
|
|
||||||
|
for _, notifReq := range req.Notifications {
|
||||||
|
resp, err := h.SendNotification(ctx, notifReq)
|
||||||
|
if err != nil {
|
||||||
|
results = append(results, &pb.NotificationResult{
|
||||||
|
Success: false,
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
results = append(results, resp.Result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pb.SendBatchNotificationsResponse{
|
||||||
|
Results: results,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNotification retrieves a notification by ID
|
||||||
|
func (h *NotifierHandler) GetNotification(ctx context.Context, req *pb.GetNotificationRequest) (*pb.GetNotificationResponse, error) {
|
||||||
|
notification, err := h.service.GetNotification(ctx, req.Id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pb.GetNotificationResponse{
|
||||||
|
Notification: convertDomainToProtoNotification(notification),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListNotifications retrieves notifications matching a filter
|
||||||
|
func (h *NotifierHandler) ListNotifications(ctx context.Context, req *pb.ListNotificationsRequest) (*pb.ListNotificationsResponse, error) {
|
||||||
|
// Convert proto filter to domain filter
|
||||||
|
filter := convertProtoFilterToDomain(req.Filter)
|
||||||
|
|
||||||
|
notifications, err := h.service.ListNotifications(ctx, filter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
protoNotifications := make([]*pb.Notification, len(notifications))
|
||||||
|
for i, notif := range notifications {
|
||||||
|
protoNotifications[i] = convertDomainToProtoNotification(notif)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pb.ListNotificationsResponse{
|
||||||
|
Notifications: protoNotifications,
|
||||||
|
Total: int64(len(notifications)),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelNotification cancels a pending notification
|
||||||
|
func (h *NotifierHandler) CancelNotification(ctx context.Context, req *pb.CancelNotificationRequest) (*pb.CancelNotificationResponse, error) {
|
||||||
|
err := h.service.CancelNotification(ctx, req.Id)
|
||||||
|
if err != nil {
|
||||||
|
return &pb.CancelNotificationResponse{
|
||||||
|
Success: false,
|
||||||
|
Message: err.Error(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pb.CancelNotificationResponse{
|
||||||
|
Success: true,
|
||||||
|
Message: "notification cancelled successfully",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetryNotification retries a failed notification
|
||||||
|
func (h *NotifierHandler) RetryNotification(ctx context.Context, req *pb.RetryNotificationRequest) (*pb.RetryNotificationResponse, error) {
|
||||||
|
result, err := h.service.RetryNotification(ctx, req.Id)
|
||||||
|
if err != nil {
|
||||||
|
return &pb.RetryNotificationResponse{
|
||||||
|
Result: &pb.NotificationResult{
|
||||||
|
Success: false,
|
||||||
|
Error: err.Error(),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pb.RetryNotificationResponse{
|
||||||
|
Result: &pb.NotificationResult{
|
||||||
|
NotificationId: result.NotificationID,
|
||||||
|
Success: result.Success,
|
||||||
|
Message: result.Message,
|
||||||
|
SentAt: timestamppb.New(result.SentAt),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStats returns notification statistics
|
||||||
|
func (h *NotifierHandler) GetStats(ctx context.Context, req *pb.GetStatsRequest) (*pb.GetStatsResponse, error) {
|
||||||
|
stats, err := h.service.GetStats(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &pb.GetStatsResponse{
|
||||||
|
TotalSent: stats.TotalSent,
|
||||||
|
TotalFailed: stats.TotalFailed,
|
||||||
|
TotalPending: stats.TotalPending,
|
||||||
|
TotalQueued: stats.TotalQueued,
|
||||||
|
ByType: stats.ByType,
|
||||||
|
ByStatus: stats.ByStatus,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper functions to convert between proto and domain types
|
||||||
|
|
||||||
|
// convertStringMapToInterface converts proto's map[string]string to domain's map[string]interface{}
|
||||||
|
func convertStringMapToInterface(m map[string]string) map[string]interface{} {
|
||||||
|
if m == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
result := make(map[string]interface{}, len(m))
|
||||||
|
for k, v := range m {
|
||||||
|
result[k] = v
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertInterfaceMapToString converts domain's map[string]interface{} to proto's map[string]string
|
||||||
|
func convertInterfaceMapToString(m map[string]interface{}) map[string]string {
|
||||||
|
if m == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
result := make(map[string]string, len(m))
|
||||||
|
for k, v := range m {
|
||||||
|
if v != nil {
|
||||||
|
result[k] = fmt.Sprint(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertProtoTypeToDomain(protoType pb.NotificationType) domain.NotificationType {
|
||||||
|
switch protoType {
|
||||||
|
case pb.NotificationType_NOTIFICATION_TYPE_EMAIL:
|
||||||
|
return domain.TypeEmail
|
||||||
|
case pb.NotificationType_NOTIFICATION_TYPE_SLACK:
|
||||||
|
return domain.TypeSlack
|
||||||
|
case pb.NotificationType_NOTIFICATION_TYPE_NTFY:
|
||||||
|
return domain.TypeNtfy
|
||||||
|
case pb.NotificationType_NOTIFICATION_TYPE_STDOUT:
|
||||||
|
return domain.TypeStdout
|
||||||
|
default:
|
||||||
|
return domain.TypeStdout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertDomainToProtoType(domainType domain.NotificationType) pb.NotificationType {
|
||||||
|
switch domainType {
|
||||||
|
case domain.TypeEmail:
|
||||||
|
return pb.NotificationType_NOTIFICATION_TYPE_EMAIL
|
||||||
|
case domain.TypeSlack:
|
||||||
|
return pb.NotificationType_NOTIFICATION_TYPE_SLACK
|
||||||
|
case domain.TypeNtfy:
|
||||||
|
return pb.NotificationType_NOTIFICATION_TYPE_NTFY
|
||||||
|
case domain.TypeStdout:
|
||||||
|
return pb.NotificationType_NOTIFICATION_TYPE_STDOUT
|
||||||
|
default:
|
||||||
|
return pb.NotificationType_NOTIFICATION_TYPE_UNSPECIFIED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertDomainToProtoStatus(status domain.NotificationStatus) pb.NotificationStatus {
|
||||||
|
switch status {
|
||||||
|
case domain.StatusPending:
|
||||||
|
return pb.NotificationStatus_NOTIFICATION_STATUS_PENDING
|
||||||
|
case domain.StatusQueued:
|
||||||
|
return pb.NotificationStatus_NOTIFICATION_STATUS_QUEUED
|
||||||
|
case domain.StatusProcessing:
|
||||||
|
return pb.NotificationStatus_NOTIFICATION_STATUS_PROCESSING
|
||||||
|
case domain.StatusSent:
|
||||||
|
return pb.NotificationStatus_NOTIFICATION_STATUS_SENT
|
||||||
|
case domain.StatusFailed:
|
||||||
|
return pb.NotificationStatus_NOTIFICATION_STATUS_FAILED
|
||||||
|
case domain.StatusRetrying:
|
||||||
|
return pb.NotificationStatus_NOTIFICATION_STATUS_RETRYING
|
||||||
|
default:
|
||||||
|
return pb.NotificationStatus_NOTIFICATION_STATUS_UNSPECIFIED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertDomainToProtoNotification(notif *domain.Notification) *pb.Notification {
|
||||||
|
protoNotif := &pb.Notification{
|
||||||
|
Id: notif.ID,
|
||||||
|
Type: convertDomainToProtoType(notif.Type),
|
||||||
|
Account: notif.Account,
|
||||||
|
Priority: pb.Priority(notif.Priority),
|
||||||
|
Status: convertDomainToProtoStatus(notif.Status),
|
||||||
|
Subject: notif.Subject,
|
||||||
|
Body: notif.Body,
|
||||||
|
Recipients: notif.Recipients,
|
||||||
|
Metadata: convertInterfaceMapToString(notif.Metadata),
|
||||||
|
CreatedAt: timestamppb.New(notif.CreatedAt),
|
||||||
|
RetryCount: int32(notif.RetryCount),
|
||||||
|
MaxRetries: int32(notif.MaxRetries),
|
||||||
|
LastError: notif.LastError,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle optional timestamp fields
|
||||||
|
if notif.ScheduledFor != nil {
|
||||||
|
protoNotif.ScheduledFor = timestamppb.New(*notif.ScheduledFor)
|
||||||
|
}
|
||||||
|
if notif.SentAt != nil {
|
||||||
|
protoNotif.SentAt = timestamppb.New(*notif.SentAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return protoNotif
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertProtoFilterToDomain(filter *pb.NotificationFilter) *domain.NotificationFilter {
|
||||||
|
if filter == nil {
|
||||||
|
return &domain.NotificationFilter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert proto types to domain types
|
||||||
|
var types []domain.NotificationType
|
||||||
|
for _, protoType := range filter.Types {
|
||||||
|
types = append(types, convertProtoTypeToDomain(protoType))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert proto statuses to domain statuses
|
||||||
|
var statuses []domain.NotificationStatus
|
||||||
|
for _, protoStatus := range filter.Statuses {
|
||||||
|
statuses = append(statuses, convertProtoStatusToDomain(protoStatus))
|
||||||
|
}
|
||||||
|
|
||||||
|
domainFilter := &domain.NotificationFilter{
|
||||||
|
IDs: filter.Ids,
|
||||||
|
Types: types,
|
||||||
|
Statuses: statuses,
|
||||||
|
Recipients: filter.Recipients,
|
||||||
|
Limit: int(filter.Limit),
|
||||||
|
Offset: int(filter.Offset),
|
||||||
|
}
|
||||||
|
|
||||||
|
if filter.CreatedAfter != nil {
|
||||||
|
createdAfter := filter.CreatedAfter.AsTime()
|
||||||
|
domainFilter.CreatedAfter = &createdAfter
|
||||||
|
}
|
||||||
|
|
||||||
|
if filter.CreatedBefore != nil {
|
||||||
|
createdBefore := filter.CreatedBefore.AsTime()
|
||||||
|
domainFilter.CreatedBefore = &createdBefore
|
||||||
|
}
|
||||||
|
|
||||||
|
return domainFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertProtoStatusToDomain(protoStatus pb.NotificationStatus) domain.NotificationStatus {
|
||||||
|
switch protoStatus {
|
||||||
|
case pb.NotificationStatus_NOTIFICATION_STATUS_PENDING:
|
||||||
|
return domain.StatusPending
|
||||||
|
case pb.NotificationStatus_NOTIFICATION_STATUS_QUEUED:
|
||||||
|
return domain.StatusQueued
|
||||||
|
case pb.NotificationStatus_NOTIFICATION_STATUS_PROCESSING:
|
||||||
|
return domain.StatusProcessing
|
||||||
|
case pb.NotificationStatus_NOTIFICATION_STATUS_SENT:
|
||||||
|
return domain.StatusSent
|
||||||
|
case pb.NotificationStatus_NOTIFICATION_STATUS_FAILED:
|
||||||
|
return domain.StatusFailed
|
||||||
|
case pb.NotificationStatus_NOTIFICATION_STATUS_RETRYING:
|
||||||
|
return domain.StatusRetrying
|
||||||
|
default:
|
||||||
|
return domain.StatusPending
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,407 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// - protoc-gen-go-grpc v1.5.1
|
|
||||||
// - protoc v6.33.0
|
|
||||||
// source: api/grpc/notifier.proto
|
|
||||||
|
|
||||||
package pb
|
|
||||||
|
|
||||||
import (
|
|
||||||
context "context"
|
|
||||||
grpc "google.golang.org/grpc"
|
|
||||||
codes "google.golang.org/grpc/codes"
|
|
||||||
status "google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This is a compile-time assertion to ensure that this generated file
|
|
||||||
// is compatible with the grpc package it is being compiled against.
|
|
||||||
// Requires gRPC-Go v1.64.0 or later.
|
|
||||||
const _ = grpc.SupportPackageIsVersion9
|
|
||||||
|
|
||||||
const (
|
|
||||||
NotifierService_SendNotification_FullMethodName = "/notifier.v1.NotifierService/SendNotification"
|
|
||||||
NotifierService_SendBatchNotifications_FullMethodName = "/notifier.v1.NotifierService/SendBatchNotifications"
|
|
||||||
NotifierService_GetNotification_FullMethodName = "/notifier.v1.NotifierService/GetNotification"
|
|
||||||
NotifierService_ListNotifications_FullMethodName = "/notifier.v1.NotifierService/ListNotifications"
|
|
||||||
NotifierService_CancelNotification_FullMethodName = "/notifier.v1.NotifierService/CancelNotification"
|
|
||||||
NotifierService_RetryNotification_FullMethodName = "/notifier.v1.NotifierService/RetryNotification"
|
|
||||||
NotifierService_GetStats_FullMethodName = "/notifier.v1.NotifierService/GetStats"
|
|
||||||
NotifierService_HealthCheck_FullMethodName = "/notifier.v1.NotifierService/HealthCheck"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NotifierServiceClient is the client API for NotifierService service.
|
|
||||||
//
|
|
||||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
|
||||||
//
|
|
||||||
// NotifierService handles notification operations
|
|
||||||
type NotifierServiceClient interface {
|
|
||||||
// SendNotification sends a single notification
|
|
||||||
SendNotification(ctx context.Context, in *SendNotificationRequest, opts ...grpc.CallOption) (*SendNotificationResponse, error)
|
|
||||||
// SendBatchNotifications sends multiple notifications
|
|
||||||
SendBatchNotifications(ctx context.Context, in *SendBatchNotificationsRequest, opts ...grpc.CallOption) (*SendBatchNotificationsResponse, error)
|
|
||||||
// GetNotification retrieves a notification by ID
|
|
||||||
GetNotification(ctx context.Context, in *GetNotificationRequest, opts ...grpc.CallOption) (*GetNotificationResponse, error)
|
|
||||||
// ListNotifications retrieves notifications matching a filter
|
|
||||||
ListNotifications(ctx context.Context, in *ListNotificationsRequest, opts ...grpc.CallOption) (*ListNotificationsResponse, error)
|
|
||||||
// CancelNotification cancels a pending notification
|
|
||||||
CancelNotification(ctx context.Context, in *CancelNotificationRequest, opts ...grpc.CallOption) (*CancelNotificationResponse, error)
|
|
||||||
// RetryNotification retries a failed notification
|
|
||||||
RetryNotification(ctx context.Context, in *RetryNotificationRequest, opts ...grpc.CallOption) (*RetryNotificationResponse, error)
|
|
||||||
// GetStats returns notification statistics
|
|
||||||
GetStats(ctx context.Context, in *GetStatsRequest, opts ...grpc.CallOption) (*GetStatsResponse, error)
|
|
||||||
// HealthCheck verifies the service is operational
|
|
||||||
HealthCheck(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type notifierServiceClient struct {
|
|
||||||
cc grpc.ClientConnInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewNotifierServiceClient(cc grpc.ClientConnInterface) NotifierServiceClient {
|
|
||||||
return ¬ifierServiceClient{cc}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *notifierServiceClient) SendNotification(ctx context.Context, in *SendNotificationRequest, opts ...grpc.CallOption) (*SendNotificationResponse, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(SendNotificationResponse)
|
|
||||||
err := c.cc.Invoke(ctx, NotifierService_SendNotification_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *notifierServiceClient) SendBatchNotifications(ctx context.Context, in *SendBatchNotificationsRequest, opts ...grpc.CallOption) (*SendBatchNotificationsResponse, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(SendBatchNotificationsResponse)
|
|
||||||
err := c.cc.Invoke(ctx, NotifierService_SendBatchNotifications_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *notifierServiceClient) GetNotification(ctx context.Context, in *GetNotificationRequest, opts ...grpc.CallOption) (*GetNotificationResponse, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(GetNotificationResponse)
|
|
||||||
err := c.cc.Invoke(ctx, NotifierService_GetNotification_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *notifierServiceClient) ListNotifications(ctx context.Context, in *ListNotificationsRequest, opts ...grpc.CallOption) (*ListNotificationsResponse, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(ListNotificationsResponse)
|
|
||||||
err := c.cc.Invoke(ctx, NotifierService_ListNotifications_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *notifierServiceClient) CancelNotification(ctx context.Context, in *CancelNotificationRequest, opts ...grpc.CallOption) (*CancelNotificationResponse, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(CancelNotificationResponse)
|
|
||||||
err := c.cc.Invoke(ctx, NotifierService_CancelNotification_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *notifierServiceClient) RetryNotification(ctx context.Context, in *RetryNotificationRequest, opts ...grpc.CallOption) (*RetryNotificationResponse, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(RetryNotificationResponse)
|
|
||||||
err := c.cc.Invoke(ctx, NotifierService_RetryNotification_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *notifierServiceClient) GetStats(ctx context.Context, in *GetStatsRequest, opts ...grpc.CallOption) (*GetStatsResponse, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(GetStatsResponse)
|
|
||||||
err := c.cc.Invoke(ctx, NotifierService_GetStats_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *notifierServiceClient) HealthCheck(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(HealthCheckResponse)
|
|
||||||
err := c.cc.Invoke(ctx, NotifierService_HealthCheck_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotifierServiceServer is the server API for NotifierService service.
|
|
||||||
// All implementations must embed UnimplementedNotifierServiceServer
|
|
||||||
// for forward compatibility.
|
|
||||||
//
|
|
||||||
// NotifierService handles notification operations
|
|
||||||
type NotifierServiceServer interface {
|
|
||||||
// SendNotification sends a single notification
|
|
||||||
SendNotification(context.Context, *SendNotificationRequest) (*SendNotificationResponse, error)
|
|
||||||
// SendBatchNotifications sends multiple notifications
|
|
||||||
SendBatchNotifications(context.Context, *SendBatchNotificationsRequest) (*SendBatchNotificationsResponse, error)
|
|
||||||
// GetNotification retrieves a notification by ID
|
|
||||||
GetNotification(context.Context, *GetNotificationRequest) (*GetNotificationResponse, error)
|
|
||||||
// ListNotifications retrieves notifications matching a filter
|
|
||||||
ListNotifications(context.Context, *ListNotificationsRequest) (*ListNotificationsResponse, error)
|
|
||||||
// CancelNotification cancels a pending notification
|
|
||||||
CancelNotification(context.Context, *CancelNotificationRequest) (*CancelNotificationResponse, error)
|
|
||||||
// RetryNotification retries a failed notification
|
|
||||||
RetryNotification(context.Context, *RetryNotificationRequest) (*RetryNotificationResponse, error)
|
|
||||||
// GetStats returns notification statistics
|
|
||||||
GetStats(context.Context, *GetStatsRequest) (*GetStatsResponse, error)
|
|
||||||
// HealthCheck verifies the service is operational
|
|
||||||
HealthCheck(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error)
|
|
||||||
mustEmbedUnimplementedNotifierServiceServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnimplementedNotifierServiceServer must be embedded to have
|
|
||||||
// forward compatible implementations.
|
|
||||||
//
|
|
||||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
|
||||||
// pointer dereference when methods are called.
|
|
||||||
type UnimplementedNotifierServiceServer struct{}
|
|
||||||
|
|
||||||
func (UnimplementedNotifierServiceServer) SendNotification(context.Context, *SendNotificationRequest) (*SendNotificationResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method SendNotification not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedNotifierServiceServer) SendBatchNotifications(context.Context, *SendBatchNotificationsRequest) (*SendBatchNotificationsResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method SendBatchNotifications not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedNotifierServiceServer) GetNotification(context.Context, *GetNotificationRequest) (*GetNotificationResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetNotification not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedNotifierServiceServer) ListNotifications(context.Context, *ListNotificationsRequest) (*ListNotificationsResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method ListNotifications not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedNotifierServiceServer) CancelNotification(context.Context, *CancelNotificationRequest) (*CancelNotificationResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method CancelNotification not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedNotifierServiceServer) RetryNotification(context.Context, *RetryNotificationRequest) (*RetryNotificationResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method RetryNotification not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedNotifierServiceServer) GetStats(context.Context, *GetStatsRequest) (*GetStatsResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetStats not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedNotifierServiceServer) HealthCheck(context.Context, *HealthCheckRequest) (*HealthCheckResponse, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method HealthCheck not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedNotifierServiceServer) mustEmbedUnimplementedNotifierServiceServer() {}
|
|
||||||
func (UnimplementedNotifierServiceServer) testEmbeddedByValue() {}
|
|
||||||
|
|
||||||
// UnsafeNotifierServiceServer may be embedded to opt out of forward compatibility for this service.
|
|
||||||
// Use of this interface is not recommended, as added methods to NotifierServiceServer will
|
|
||||||
// result in compilation errors.
|
|
||||||
type UnsafeNotifierServiceServer interface {
|
|
||||||
mustEmbedUnimplementedNotifierServiceServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
func RegisterNotifierServiceServer(s grpc.ServiceRegistrar, srv NotifierServiceServer) {
|
|
||||||
// If the following call pancis, it indicates UnimplementedNotifierServiceServer was
|
|
||||||
// embedded by pointer and is nil. This will cause panics if an
|
|
||||||
// unimplemented method is ever invoked, so we test this at initialization
|
|
||||||
// time to prevent it from happening at runtime later due to I/O.
|
|
||||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
|
||||||
t.testEmbeddedByValue()
|
|
||||||
}
|
|
||||||
s.RegisterService(&NotifierService_ServiceDesc, srv)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _NotifierService_SendNotification_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(SendNotificationRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(NotifierServiceServer).SendNotification(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: NotifierService_SendNotification_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(NotifierServiceServer).SendNotification(ctx, req.(*SendNotificationRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _NotifierService_SendBatchNotifications_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(SendBatchNotificationsRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(NotifierServiceServer).SendBatchNotifications(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: NotifierService_SendBatchNotifications_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(NotifierServiceServer).SendBatchNotifications(ctx, req.(*SendBatchNotificationsRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _NotifierService_GetNotification_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(GetNotificationRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(NotifierServiceServer).GetNotification(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: NotifierService_GetNotification_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(NotifierServiceServer).GetNotification(ctx, req.(*GetNotificationRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _NotifierService_ListNotifications_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(ListNotificationsRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(NotifierServiceServer).ListNotifications(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: NotifierService_ListNotifications_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(NotifierServiceServer).ListNotifications(ctx, req.(*ListNotificationsRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _NotifierService_CancelNotification_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(CancelNotificationRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(NotifierServiceServer).CancelNotification(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: NotifierService_CancelNotification_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(NotifierServiceServer).CancelNotification(ctx, req.(*CancelNotificationRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _NotifierService_RetryNotification_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(RetryNotificationRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(NotifierServiceServer).RetryNotification(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: NotifierService_RetryNotification_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(NotifierServiceServer).RetryNotification(ctx, req.(*RetryNotificationRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _NotifierService_GetStats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(GetStatsRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(NotifierServiceServer).GetStats(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: NotifierService_GetStats_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(NotifierServiceServer).GetStats(ctx, req.(*GetStatsRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _NotifierService_HealthCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(HealthCheckRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(NotifierServiceServer).HealthCheck(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: NotifierService_HealthCheck_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(NotifierServiceServer).HealthCheck(ctx, req.(*HealthCheckRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotifierService_ServiceDesc is the grpc.ServiceDesc for NotifierService service.
|
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
|
||||||
// and not to be introspected or modified (even as a copy)
|
|
||||||
var NotifierService_ServiceDesc = grpc.ServiceDesc{
|
|
||||||
ServiceName: "notifier.v1.NotifierService",
|
|
||||||
HandlerType: (*NotifierServiceServer)(nil),
|
|
||||||
Methods: []grpc.MethodDesc{
|
|
||||||
{
|
|
||||||
MethodName: "SendNotification",
|
|
||||||
Handler: _NotifierService_SendNotification_Handler,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MethodName: "SendBatchNotifications",
|
|
||||||
Handler: _NotifierService_SendBatchNotifications_Handler,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MethodName: "GetNotification",
|
|
||||||
Handler: _NotifierService_GetNotification_Handler,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MethodName: "ListNotifications",
|
|
||||||
Handler: _NotifierService_ListNotifications_Handler,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MethodName: "CancelNotification",
|
|
||||||
Handler: _NotifierService_CancelNotification_Handler,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MethodName: "RetryNotification",
|
|
||||||
Handler: _NotifierService_RetryNotification_Handler,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MethodName: "GetStats",
|
|
||||||
Handler: _NotifierService_GetStats_Handler,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MethodName: "HealthCheck",
|
|
||||||
Handler: _NotifierService_HealthCheck_Handler,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Streams: []grpc.StreamDesc{},
|
|
||||||
Metadata: "api/grpc/notifier.proto",
|
|
||||||
}
|
|
||||||
+32
-2
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -11,6 +12,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
grpcapi "github.com/igodwin/notifier/api/grpc"
|
||||||
|
pb "github.com/igodwin/notifier/api/grpc/pb"
|
||||||
"github.com/igodwin/notifier/api/rest"
|
"github.com/igodwin/notifier/api/rest"
|
||||||
"github.com/igodwin/notifier/internal/config"
|
"github.com/igodwin/notifier/internal/config"
|
||||||
"github.com/igodwin/notifier/internal/domain"
|
"github.com/igodwin/notifier/internal/domain"
|
||||||
@@ -22,7 +25,23 @@ import (
|
|||||||
"google.golang.org/grpc/reflection"
|
"google.golang.org/grpc/reflection"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Build information - set via ldflags during build
|
||||||
|
// Example: go build -ldflags "-X main.Version=1.0.0 -X main.GitCommit=$(git rev-parse HEAD)"
|
||||||
|
Version = "dev"
|
||||||
|
GitCommit = "unknown"
|
||||||
|
BuildTime = "unknown"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
// Print service identifier and build info
|
||||||
|
fmt.Printf("====================================\n")
|
||||||
|
fmt.Printf("Notifier Service\n")
|
||||||
|
fmt.Printf("Version: %s\n", Version)
|
||||||
|
fmt.Printf("Git Commit: %s\n", GitCommit)
|
||||||
|
fmt.Printf("Build Time: %s\n", BuildTime)
|
||||||
|
fmt.Printf("====================================\n")
|
||||||
|
|
||||||
// Load configuration
|
// Load configuration
|
||||||
cfg, err := config.Load("")
|
cfg, err := config.Load("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -40,6 +59,14 @@ func main() {
|
|||||||
logger.Warnf("Failed to open log file, using stdout: %v", err)
|
logger.Warnf("Failed to open log file, using stdout: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log which config file was loaded
|
||||||
|
logger.Infof("Loaded configuration from: %s", cfg.ConfigFile)
|
||||||
|
|
||||||
|
// Log sanitized config (with sensitive data redacted)
|
||||||
|
if sanitized, err := json.MarshalIndent(cfg.Sanitize(), "", " "); err == nil {
|
||||||
|
logger.Infof("Configuration:\n%s", string(sanitized))
|
||||||
|
}
|
||||||
|
|
||||||
logger.Infof("Starting Notifier Service in mode: %s", cfg.Server.Mode)
|
logger.Infof("Starting Notifier Service in mode: %s", cfg.Server.Mode)
|
||||||
|
|
||||||
// Create context
|
// Create context
|
||||||
@@ -200,12 +227,15 @@ func startGRPCServer(ctx context.Context, wg *sync.WaitGroup, cfg *config.Config
|
|||||||
|
|
||||||
grpcServer := grpc.NewServer()
|
grpcServer := grpc.NewServer()
|
||||||
|
|
||||||
// TODO: Register gRPC service implementation when protobuf is generated
|
// Create and register gRPC handler
|
||||||
// pb.RegisterNotifierServiceServer(grpcServer, grpcHandler)
|
grpcHandler := grpcapi.NewNotifierHandler(svc)
|
||||||
|
pb.RegisterNotifierServiceServer(grpcServer, grpcHandler)
|
||||||
|
|
||||||
// Enable reflection for tools like grpcurl
|
// Enable reflection for tools like grpcurl
|
||||||
reflection.Register(grpcServer)
|
reflection.Register(grpcServer)
|
||||||
|
|
||||||
|
logger.Info("Registered gRPC NotifierService")
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
logger.Infof("gRPC server listening on %s", addr)
|
logger.Infof("gRPC server listening on %s", addr)
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ services:
|
|||||||
- "9090:9090" # Metrics (future)
|
- "9090:9090" # Metrics (future)
|
||||||
- "8081:8081" # Health check (future)
|
- "8081:8081" # Health check (future)
|
||||||
volumes:
|
volumes:
|
||||||
- ./notifier.config:/app/notifier.config:ro
|
- ./config.yaml:/app/config.yaml:ro
|
||||||
- notifier-data:/var/lib/notifier
|
- notifier-data:/var/lib/notifier
|
||||||
environment:
|
environment:
|
||||||
- NOTIFIER_SERVER_MODE=both
|
- NOTIFIER_SERVER_MODE=both
|
||||||
|
|||||||
+112
-7
@@ -2,6 +2,8 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/igodwin/notifier/internal/domain"
|
"github.com/igodwin/notifier/internal/domain"
|
||||||
@@ -17,6 +19,7 @@ type Config struct {
|
|||||||
Logging LoggingConfig `mapstructure:"logging"`
|
Logging LoggingConfig `mapstructure:"logging"`
|
||||||
Metrics MetricsConfig `mapstructure:"metrics"`
|
Metrics MetricsConfig `mapstructure:"metrics"`
|
||||||
HealthCheck HealthCheckConfig `mapstructure:"health_check"`
|
HealthCheck HealthCheckConfig `mapstructure:"health_check"`
|
||||||
|
ConfigFile string `mapstructure:"-"` // Path to config file used (not from config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerConfig contains server configuration
|
// ServerConfig contains server configuration
|
||||||
@@ -59,25 +62,30 @@ type HealthCheckConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load loads configuration from file and environment variables
|
// Load loads configuration from file and environment variables
|
||||||
|
// Returns the loaded config and the path to the config file that was used
|
||||||
func Load(configPath string) (*Config, error) {
|
func Load(configPath string) (*Config, error) {
|
||||||
v := viper.New()
|
v := viper.New()
|
||||||
|
|
||||||
// Set default values
|
// Set default values
|
||||||
setDefaults(v)
|
setDefaults(v)
|
||||||
|
|
||||||
// Configure viper
|
// Configure viper to look for config.yaml
|
||||||
v.SetConfigName("notifier")
|
v.SetConfigName("config")
|
||||||
v.SetConfigType("yaml")
|
v.SetConfigType("yaml")
|
||||||
|
|
||||||
|
// Add config search paths
|
||||||
if configPath != "" {
|
if configPath != "" {
|
||||||
v.AddConfigPath(configPath)
|
v.AddConfigPath(configPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also look in common locations
|
|
||||||
v.AddConfigPath(".")
|
v.AddConfigPath(".")
|
||||||
v.AddConfigPath("./config")
|
v.AddConfigPath("./config")
|
||||||
v.AddConfigPath("/etc/notifier")
|
v.AddConfigPath("/etc/notifier")
|
||||||
v.AddConfigPath("$HOME/.notifier")
|
|
||||||
|
// Add $HOME/.notifier if HOME is set
|
||||||
|
if home := os.Getenv("HOME"); home != "" {
|
||||||
|
v.AddConfigPath(filepath.Join(home, ".notifier"))
|
||||||
|
}
|
||||||
|
|
||||||
// Environment variable support
|
// Environment variable support
|
||||||
v.SetEnvPrefix("NOTIFIER")
|
v.SetEnvPrefix("NOTIFIER")
|
||||||
@@ -85,11 +93,13 @@ func Load(configPath string) (*Config, error) {
|
|||||||
v.AutomaticEnv()
|
v.AutomaticEnv()
|
||||||
|
|
||||||
// Read config file
|
// Read config file
|
||||||
|
var configErr error
|
||||||
if err := v.ReadInConfig(); err != nil {
|
if err := v.ReadInConfig(); err != nil {
|
||||||
// Config file is optional if environment variables are set
|
// Config file is optional if environment variables are set
|
||||||
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
|
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
|
||||||
return nil, fmt.Errorf("failed to read config file: %w", err)
|
return nil, fmt.Errorf("failed to read config file: %w", err)
|
||||||
}
|
}
|
||||||
|
configErr = err
|
||||||
}
|
}
|
||||||
|
|
||||||
var config Config
|
var config Config
|
||||||
@@ -97,6 +107,16 @@ func Load(configPath string) (*Config, error) {
|
|||||||
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
|
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store which config file was used
|
||||||
|
config.ConfigFile = v.ConfigFileUsed()
|
||||||
|
if config.ConfigFile == "" {
|
||||||
|
if configErr != nil {
|
||||||
|
config.ConfigFile = "no config file found (using defaults and environment variables)"
|
||||||
|
} else {
|
||||||
|
config.ConfigFile = "using defaults and environment variables"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Validate configuration
|
// Validate configuration
|
||||||
if err := config.Validate(); err != nil {
|
if err := config.Validate(); err != nil {
|
||||||
return nil, fmt.Errorf("invalid configuration: %w", err)
|
return nil, fmt.Errorf("invalid configuration: %w", err)
|
||||||
@@ -143,9 +163,8 @@ func setDefaults(v *viper.Viper) {
|
|||||||
|
|
||||||
// Notifier defaults
|
// Notifier defaults
|
||||||
v.SetDefault("notifiers.stdout", true)
|
v.SetDefault("notifiers.stdout", true)
|
||||||
v.SetDefault("notifiers.smtp.port", 587)
|
// Note: SMTP, Slack, and Ntfy now use named instances (maps)
|
||||||
v.SetDefault("notifiers.smtp.use_tls", true)
|
// so we don't set defaults at the type level
|
||||||
v.SetDefault("notifiers.ntfy.server_url", "https://ntfy.sh")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates the configuration
|
// Validate validates the configuration
|
||||||
@@ -210,6 +229,92 @@ func (c *Config) GetEnabledNotifiers() []domain.NotificationType {
|
|||||||
return enabled
|
return enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sanitize returns a sanitized copy of the config with sensitive data redacted
|
||||||
|
func (c *Config) Sanitize() map[string]interface{} {
|
||||||
|
sanitized := map[string]interface{}{
|
||||||
|
"config_file": c.ConfigFile,
|
||||||
|
"server": map[string]interface{}{
|
||||||
|
"grpc_port": c.Server.GRPCPort,
|
||||||
|
"rest_port": c.Server.RESTPort,
|
||||||
|
"host": c.Server.Host,
|
||||||
|
"mode": c.Server.Mode,
|
||||||
|
},
|
||||||
|
"queue": map[string]interface{}{
|
||||||
|
"type": c.Queue.Type,
|
||||||
|
"worker_count": c.Queue.WorkerCount,
|
||||||
|
"retry_attempts": c.Queue.RetryAttempts,
|
||||||
|
},
|
||||||
|
"logging": map[string]interface{}{
|
||||||
|
"level": c.Logging.Level,
|
||||||
|
"format": c.Logging.Format,
|
||||||
|
},
|
||||||
|
"metrics": map[string]interface{}{
|
||||||
|
"enabled": c.Metrics.Enabled,
|
||||||
|
"port": c.Metrics.Port,
|
||||||
|
},
|
||||||
|
"health_check": map[string]interface{}{
|
||||||
|
"enabled": c.HealthCheck.Enabled,
|
||||||
|
"port": c.HealthCheck.Port,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanitize notifiers
|
||||||
|
notifiers := map[string]interface{}{
|
||||||
|
"stdout": c.Notifiers.Stdout,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanitize SMTP configs
|
||||||
|
if len(c.Notifiers.SMTP) > 0 {
|
||||||
|
smtpAccounts := make(map[string]interface{})
|
||||||
|
for name, cfg := range c.Notifiers.SMTP {
|
||||||
|
smtpAccounts[name] = map[string]interface{}{
|
||||||
|
"host": cfg.Host,
|
||||||
|
"port": cfg.Port,
|
||||||
|
"username": cfg.Username,
|
||||||
|
"password": "***REDACTED***",
|
||||||
|
"from": cfg.From,
|
||||||
|
"use_tls": cfg.UseTLS,
|
||||||
|
"default": cfg.Default,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notifiers["smtp"] = smtpAccounts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanitize Slack configs
|
||||||
|
if len(c.Notifiers.Slack) > 0 {
|
||||||
|
slackAccounts := make(map[string]interface{})
|
||||||
|
for name, cfg := range c.Notifiers.Slack {
|
||||||
|
slackAccounts[name] = map[string]interface{}{
|
||||||
|
"webhook_url": "***REDACTED***",
|
||||||
|
"token": "***REDACTED***",
|
||||||
|
"username": cfg.Username,
|
||||||
|
"icon_emoji": cfg.IconEmoji,
|
||||||
|
"default": cfg.Default,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notifiers["slack"] = slackAccounts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanitize Ntfy configs
|
||||||
|
if len(c.Notifiers.Ntfy) > 0 {
|
||||||
|
ntfyAccounts := make(map[string]interface{})
|
||||||
|
for name, cfg := range c.Notifiers.Ntfy {
|
||||||
|
ntfyAccounts[name] = map[string]interface{}{
|
||||||
|
"server_url": cfg.ServerURL,
|
||||||
|
"token": "***REDACTED***",
|
||||||
|
"username": cfg.Username,
|
||||||
|
"password": "***REDACTED***",
|
||||||
|
"default_topic": cfg.DefaultTopic,
|
||||||
|
"default": cfg.Default,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notifiers["ntfy"] = ntfyAccounts
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitized["notifiers"] = notifiers
|
||||||
|
return sanitized
|
||||||
|
}
|
||||||
|
|
||||||
// GetDefaultAccount returns the default account name for a notifier type, or the first account if no default is set
|
// GetDefaultAccount returns the default account name for a notifier type, or the first account if no default is set
|
||||||
func (c *Config) GetDefaultAccount(notifierType domain.NotificationType) string {
|
func (c *Config) GetDefaultAccount(notifierType domain.NotificationType) string {
|
||||||
switch notifierType {
|
switch notifierType {
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ metadata:
|
|||||||
labels:
|
labels:
|
||||||
app: notifier
|
app: notifier
|
||||||
data:
|
data:
|
||||||
notifier.config: |
|
config.yaml: |
|
||||||
server:
|
server:
|
||||||
grpc_port: 50051
|
grpc_port: 50051
|
||||||
rest_port: 8080
|
rest_port: 8080
|
||||||
|
|||||||
+2
-2
@@ -45,8 +45,8 @@ spec:
|
|||||||
value: "local"
|
value: "local"
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: config
|
- name: config
|
||||||
mountPath: /app/notifier.config
|
mountPath: /app/config.yaml
|
||||||
subPath: notifier.config
|
subPath: config.yaml
|
||||||
readOnly: true
|
readOnly: true
|
||||||
- name: queue-storage
|
- name: queue-storage
|
||||||
mountPath: /var/lib/notifier
|
mountPath: /var/lib/notifier
|
||||||
|
|||||||
Reference in New Issue
Block a user