initial commit
This commit is contained in:
commit
10296fb4dd
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.direnv
|
||||||
|
gen
|
4
cmd/zen/main.go
Normal file
4
cmd/zen/main.go
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
// This is the main entry point for CLI interface.
|
||||||
|
func main() {}
|
26
flake.lock
Normal file
26
flake.lock
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1724177844,
|
||||||
|
"narHash": "sha256-G7Mf9uN9m8FimeP3eMHu/dOC4QS8QAzo0h4ZIlDHcCA=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "d13fa5a45a34e7c8be33474f58003914430bdc5a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
31
flake.nix
Normal file
31
flake.nix
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "nixpkgs/nixpkgs-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { nixpkgs, ... }:
|
||||||
|
let
|
||||||
|
system = "x86_64-linux";
|
||||||
|
|
||||||
|
pkgs = import nixpkgs { inherit system; };
|
||||||
|
in
|
||||||
|
{
|
||||||
|
devShell.${system} = pkgs.mkShell {
|
||||||
|
name = "zen-shell";
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
go
|
||||||
|
nodePackages_latest.nodejs
|
||||||
|
goose
|
||||||
|
air
|
||||||
|
upx
|
||||||
|
buf
|
||||||
|
buf-language-server
|
||||||
|
protoc-gen-go
|
||||||
|
protoc-gen-connect-go
|
||||||
|
protoc-gen-validate
|
||||||
|
air
|
||||||
|
gopls
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
24
schemas/proto/buf.gen.yaml
Normal file
24
schemas/proto/buf.gen.yaml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
version: v2
|
||||||
|
managed:
|
||||||
|
enabled: true
|
||||||
|
disable:
|
||||||
|
- module: buf.build/bufbuild/protovalidate
|
||||||
|
- module: buf.build/protocolbuffers/wellknowntypes
|
||||||
|
|
||||||
|
override:
|
||||||
|
- file_option: go_package_prefix
|
||||||
|
value: gitlab.bareksa.com/backend/zen/zcore/internal/gen/proto
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
- remote: buf.build/protocolbuffers/go:v1.34.2
|
||||||
|
out: ../../zcore/internal/gen/proto
|
||||||
|
opt:
|
||||||
|
- paths=source_relative
|
||||||
|
|
||||||
|
- remote: buf.build/connectrpc/go
|
||||||
|
out: ../../zcore/internal/gen/proto
|
||||||
|
opt:
|
||||||
|
- paths=source_relative
|
||||||
|
|
||||||
|
- remote: buf.build/community/pseudomuto-doc:v1.5.1
|
||||||
|
out: ../../zcore/internal/gen/proto
|
2
schemas/proto/buf.lock
Normal file
2
schemas/proto/buf.lock
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# Generated by buf. DO NOT EDIT.
|
||||||
|
version: v2
|
4
schemas/proto/buf.yaml
Normal file
4
schemas/proto/buf.yaml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
version: v2
|
||||||
|
deps:
|
||||||
|
- buf.build/bufbuild/protovalidate
|
||||||
|
- buf.build/protocolbuffers/wellknowntypes
|
19
schemas/proto/notify/v1/notify.proto
Normal file
19
schemas/proto/notify/v1/notify.proto
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package notify.v1;
|
||||||
|
|
||||||
|
import "notify/v1/send_notification.proto";
|
||||||
|
|
||||||
|
service NotifyService {
|
||||||
|
rpc SendNotification(SendNotificationRequest) returns (SendNotificationResponse);
|
||||||
|
rpc SendAttachment(stream SendAttachmentRequest) returns (SendAttachmentResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message SendAttachmentRequest {
|
||||||
|
string notification_id = 1;
|
||||||
|
string name = 2;
|
||||||
|
string content_type = 3;
|
||||||
|
bytes chunk = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SendAttachmentResponse {}
|
79
schemas/proto/notify/v1/send_notification.proto
Normal file
79
schemas/proto/notify/v1/send_notification.proto
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package notify.v1;
|
||||||
|
|
||||||
|
import "notify/v1/types.proto";
|
||||||
|
|
||||||
|
message SendNotificationRequest {
|
||||||
|
Payload payload = 1;
|
||||||
|
Service service = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendAttachmentResponse is sent when message is successful.
|
||||||
|
message SendNotificationResponse {
|
||||||
|
// notification_id is the snowflake id of the message.
|
||||||
|
//
|
||||||
|
// Guaranteed to be unique even on distributed environment.
|
||||||
|
//
|
||||||
|
// notification_id can be used in `SendAttachment` rpc to
|
||||||
|
// attach binary data to the message.
|
||||||
|
string notification_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Payload {
|
||||||
|
string message = 1;
|
||||||
|
Level level = 2;
|
||||||
|
optional int64 code = 3;
|
||||||
|
// details adds context to the message.
|
||||||
|
//
|
||||||
|
// like timestamps, invalid inputs,
|
||||||
|
// request payloads, backend response, etc.
|
||||||
|
//
|
||||||
|
// Anything that can enrich why this message
|
||||||
|
// appears will help.
|
||||||
|
//
|
||||||
|
// DO NOT INCLUDE BINARIES LIKE IMAGES, PDFS, DOCS, IN
|
||||||
|
// THIS PAYLOAD. USE `SendAttachment` rpc
|
||||||
|
// to attach binary values instead since they are designed
|
||||||
|
// for streaming. Server and Client RAM
|
||||||
|
// can be eaten alive if you failed to do so since GRPC
|
||||||
|
// handles via whole messages.
|
||||||
|
oneof details {
|
||||||
|
// Sends JSON as details.
|
||||||
|
bytes d_json = 4;
|
||||||
|
string d_text = 5;
|
||||||
|
}
|
||||||
|
oneof error {
|
||||||
|
bytes e_json = 6;
|
||||||
|
string e_text = 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message Service {
|
||||||
|
// The name of the service that is sending the notification.
|
||||||
|
//
|
||||||
|
// This is used to identify the service that is sending the notification.
|
||||||
|
//
|
||||||
|
// The value of name should be related to the product or service.
|
||||||
|
// e.g. `sbn-frontend`, `sbn-cron-job`, `payment-frontend`, `robo-frontend`.
|
||||||
|
//
|
||||||
|
// `name`, `type`, and `environment` combination are used to select which channel the
|
||||||
|
// discord notification is sent.
|
||||||
|
string name = 1;
|
||||||
|
string type = 2;
|
||||||
|
Environment environment = 3;
|
||||||
|
optional string version = 4;
|
||||||
|
// domain specifies whose message this belongs to.
|
||||||
|
//
|
||||||
|
// It's not required to be set, but setting this field
|
||||||
|
// will help zen to categorize messages when building
|
||||||
|
// reports.
|
||||||
|
ServiceDomain domain = 5;
|
||||||
|
repeated Attribute attributes = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ServiceDomain {
|
||||||
|
SERVICE_DOMAIN_UNSPECIFIED = 0;
|
||||||
|
SERVICE_DOMAIN_FRONTEND = 1;
|
||||||
|
SERVICE_DOMAIN_BACKEND = 2;
|
||||||
|
}
|
23
schemas/proto/notify/v1/types.proto
Normal file
23
schemas/proto/notify/v1/types.proto
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package notify.v1;
|
||||||
|
|
||||||
|
enum Level {
|
||||||
|
LEVEL_UNSPECIFIED = 0;
|
||||||
|
LEVEL_DEBUG = 1;
|
||||||
|
LEVEL_INFO = 2;
|
||||||
|
LEVEL_WARN = 3;
|
||||||
|
LEVEL_ERROR = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Environment {
|
||||||
|
ENVIRONMENT_UNSPECIFIED = 0;
|
||||||
|
ENVIRONMENT_DEVELOPMENT = 1;
|
||||||
|
ENVIRONMENT_STAGING = 2;
|
||||||
|
ENVIRONMENT_PRODUCTION = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Attribute {
|
||||||
|
string key = 1;
|
||||||
|
string value = 2;
|
||||||
|
}
|
1
zcore/internal/server/server.go
Normal file
1
zcore/internal/server/server.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package server
|
33
zcore/zerr/zerr.go
Normal file
33
zcore/zerr/zerr.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package zerr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gitlab.bareksa.com/backend/zen/zcore/zoptions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Error interface {
|
||||||
|
error
|
||||||
|
|
||||||
|
Code(code int) Error
|
||||||
|
GetCode() int
|
||||||
|
|
||||||
|
Message(msg string, args ...any) Error
|
||||||
|
GetMessage() string
|
||||||
|
|
||||||
|
PublicMessage(msg string, args ...any) Error
|
||||||
|
GetPublicMessage() string
|
||||||
|
|
||||||
|
Caller(pc uintptr) Error
|
||||||
|
GetCaller() uintptr
|
||||||
|
|
||||||
|
Time(t time.Time) Error
|
||||||
|
GetTime() time.Time
|
||||||
|
|
||||||
|
Key(msg string, args ...any) Error
|
||||||
|
GetKey() string
|
||||||
|
|
||||||
|
Log(ctx context.Context) Error
|
||||||
|
Notify(ctx context.Context, opts ...zoptions.NotifyOption) Error
|
||||||
|
}
|
1
zcore/zlog/zlog.go
Normal file
1
zcore/zlog/zlog.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package zlog
|
131
zcore/zoptions/notify.go
Normal file
131
zcore/zoptions/notify.go
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
package zoptions
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type NotifyParameters struct {
|
||||||
|
// AlwaysSend makes sure this message
|
||||||
|
// is always sent no matter the condition.
|
||||||
|
//
|
||||||
|
// It will cause `zen` to ignore every other
|
||||||
|
// parameters and just send the message.
|
||||||
|
AlwaysSend bool
|
||||||
|
|
||||||
|
// InitialBackoff is the starting backoff.
|
||||||
|
//
|
||||||
|
// If not specified, the default duration is time.Minute.
|
||||||
|
InitialBackoff time.Duration
|
||||||
|
// MaxBackoff is the maximum backoff. If unset, the default value
|
||||||
|
// is time.Hour * 24.
|
||||||
|
MaxBackoff time.Duration
|
||||||
|
|
||||||
|
// BackoffFormula is a string that represents the formula to calculate the backoff time
|
||||||
|
// when multiple message with the same key is fired off repeatedly.
|
||||||
|
//
|
||||||
|
// It uses CEL (Common Expression Language) syntax. See: https://github.com/google/cel-go
|
||||||
|
// for the language spec.
|
||||||
|
//
|
||||||
|
// Expression must return a duration type.
|
||||||
|
//
|
||||||
|
// If invalid cel expression, empty string, or wrong return value, default formula will be used.
|
||||||
|
//
|
||||||
|
// Available variables:
|
||||||
|
//
|
||||||
|
// - `repeat`: the number of times the notification has been sent. type: int.
|
||||||
|
// - `last`: the last time the notification was sent. type: timestamp.
|
||||||
|
// - `prev_backoff`: the backoff value from previous evaluation. 0 if first seen. Type: duration.
|
||||||
|
// - `initial_backoff`: the initial_backoff value. Type: duration
|
||||||
|
// - `max_backoff`: the maximum backoff value. Type: duration
|
||||||
|
//
|
||||||
|
// Available Non-Standard functions:
|
||||||
|
//
|
||||||
|
// // pow multiplies the base with the exponent
|
||||||
|
// pow(base: double, exp: double) -> double
|
||||||
|
//
|
||||||
|
// // mult_dur_double multiplies the duration with the double value
|
||||||
|
// mult_dur_double(dur: duration, mult: double) -> duration
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Example (and also default formula):
|
||||||
|
//
|
||||||
|
// mult_dur_double(initial_backoff, pow(1.5, double(repeat))) > max_backoff
|
||||||
|
// ? max_backoff
|
||||||
|
// : mult_dur_double(initial_backoff, pow(1.5, double(repeat)))
|
||||||
|
BackoffFormula string
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotifyOption interface {
|
||||||
|
Apply(parameters *NotifyParameters)
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotifyOptionFunc func(parameters *NotifyParameters)
|
||||||
|
|
||||||
|
func (f NotifyOptionFunc) Apply(parameters *NotifyParameters) {
|
||||||
|
f(parameters)
|
||||||
|
}
|
||||||
|
|
||||||
|
type NotifiyOptionBuilder []NotifyOption
|
||||||
|
|
||||||
|
func (no NotifiyOptionBuilder) Apply(parameters *NotifyParameters) {
|
||||||
|
for _, opt := range no {
|
||||||
|
opt.Apply(parameters)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (no NotifiyOptionBuilder) AlwaysSend(alwaysSend bool) NotifiyOptionBuilder {
|
||||||
|
return append(no, NotifyOptionFunc(func(parameters *NotifyParameters) {
|
||||||
|
parameters.AlwaysSend = alwaysSend
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (no NotifiyOptionBuilder) InitialBackoff(backoff time.Duration) NotifiyOptionBuilder {
|
||||||
|
return append(no, NotifyOptionFunc(func(parameters *NotifyParameters) {
|
||||||
|
parameters.InitialBackoff = backoff
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (no NotifiyOptionBuilder) MaxBackoff(maxBackoff time.Duration) NotifiyOptionBuilder {
|
||||||
|
return append(no, NotifyOptionFunc(func(parameters *NotifyParameters) {
|
||||||
|
parameters.MaxBackoff = maxBackoff
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BackoffFormula is a string that represents the formula to calculate the backoff time
|
||||||
|
// when multiple message with the same key is fired off repeatedly.
|
||||||
|
//
|
||||||
|
// It uses CEL (Common Expression Language) syntax. See: https://github.com/google/cel-go
|
||||||
|
// for the language spec.
|
||||||
|
//
|
||||||
|
// Expression must return a duration type.
|
||||||
|
//
|
||||||
|
// If invalid cel expression, empty string, or wrong return value, default formula will be used.
|
||||||
|
//
|
||||||
|
// Available variables:
|
||||||
|
//
|
||||||
|
// - `repeat`: the number of times the notification has been sent. type: int.
|
||||||
|
// - `last`: the last time the notification was sent. type: timestamp.
|
||||||
|
// - `prev_backoff`: the backoff value from previous evaluation. 0 if this message is first seen. Type: duration.
|
||||||
|
// - `initial_backoff`: the initial_backoff value. Type: duration
|
||||||
|
// - `max_backoff`: the maximum backoff value. Type: duration
|
||||||
|
//
|
||||||
|
// Available Non-Standard functions:
|
||||||
|
//
|
||||||
|
// // pow multiplies the base with the exponent
|
||||||
|
// pow(base: double, exp: double) -> double
|
||||||
|
//
|
||||||
|
// // mult_dur_double multiplies the duration with the double value
|
||||||
|
// mult_dur_double(dur: duration, mult: double) -> duration
|
||||||
|
//
|
||||||
|
// Example (and also default formula):
|
||||||
|
//
|
||||||
|
// mult_dur_double(initial_backoff, pow(1.5, double(repeat))) > max_backoff
|
||||||
|
// ? max_backoff
|
||||||
|
// : mult_dur_double(initial_backoff, pow(1.5, double(repeat)))
|
||||||
|
func (no NotifiyOptionBuilder) BackoffFormula(formula string) NotifiyOptionBuilder {
|
||||||
|
return append(no, NotifyOptionFunc(func(parameters *NotifyParameters) {
|
||||||
|
parameters.BackoffFormula = formula
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Notify() NotifiyOptionBuilder {
|
||||||
|
return NotifiyOptionBuilder{}
|
||||||
|
}
|
Loading…
Reference in a new issue