diff --git a/go/pkg/errs/errs.go b/go/pkg/errs/errs.go index 76d3cba..10e7523 100644 --- a/go/pkg/errs/errs.go +++ b/go/pkg/errs/errs.go @@ -109,32 +109,33 @@ func (e *Err) Details(keysAndValues ...any) Error { // discarding any empty and duplicate messages in the chain. // // The error messages are concatenated with a colon and a space. +// +// The message does not expose the origin error message. +// +// To get them, errors.Unwrap have to be called against this error +// or view them in the logs. func (e *Err) Error() string { s := strings.Builder{} if e.message != "" { s.WriteString(e.message) - if e.origin != nil { - s.WriteString(": ") - } } unwrap := errors.Unwrap(e) for unwrap != nil { var current string - if e, ok := unwrap.(Error); ok && e.GetMessage() != "" { - current = e.GetMessage() - } else { - current = unwrap.Error() + if e, ok := unwrap.(Error); ok { + if msg := e.GetMessage(); msg != "" { + current = msg + } } next := errors.Unwrap(unwrap) if next != nil { current, _ = strings.CutSuffix(current, next.Error()) - current, _ = strings.CutSuffix(current, ": ") } if current != "" { - s.WriteString(current) - if next != nil { + if _, ok := next.(Error); ok { s.WriteString(": ") } + s.WriteString(current) } unwrap = next diff --git a/go/server/interceptor.go b/go/server/interceptor.go index 860ab26..c2a2b16 100644 --- a/go/server/interceptor.go +++ b/go/server/interceptor.go @@ -61,8 +61,10 @@ func ErrorMessageInterceptor() connect.UnaryInterceptorFunc { if cerr := new(connect.Error); errors.As(err, &cerr) { if e := errs.FindError(cerr); e != nil { - msg := e.GetMessage() - e.Message("[%s] %s", span.SpanContext().SpanID().String(), msg) + msg := e.Error() + spanContext := span.SpanContext() + traceId := spanContext.TraceID().String() + e.Message("%s|%s", traceId, msg) } } diff --git a/schemas/migrations/20240804155710_create_subreddits_table.sql b/schemas/migrations/20240804155710_create_subreddits_table.sql index 94d366c..3b62cf8 100644 --- a/schemas/migrations/20240804155710_create_subreddits_table.sql +++ b/schemas/migrations/20240804155710_create_subreddits_table.sql @@ -2,7 +2,7 @@ -- +goose StatementBegin CREATE TABLE subreddits ( name VARCHAR(30) NOT NULL PRIMARY KEY COLLATE NOCASE, - disable_scheduler TINYINT NOT NULL DEFAULT 0, + disabled TINYINT NOT NULL DEFAULT 0, "type" VARCHAR(5) NOT NULL DEFAULT 'r', schedule VARCHAR(20) NOT NULL DEFAULT '@daily', countback BIGINT NOT NULL DEFAULT 300, diff --git a/schemas/proto/device/v1/count.proto b/schemas/proto/device/v1/count.proto index a383331..2c2edf1 100644 --- a/schemas/proto/device/v1/count.proto +++ b/schemas/proto/device/v1/count.proto @@ -7,7 +7,7 @@ import "device/v1/list.proto"; option go_package = "github.com/tigorlazuardi/bluemage/go/gen/proto/device/v1"; message CountDevicesRequest { - // Limits the counts to devices that have the given name. + // Limits the counts to devices that contains the given name. // case insensitive. // // Ignored if empty. diff --git a/schemas/proto/device/v1/list.proto b/schemas/proto/device/v1/list.proto index aca676a..de47141 100644 --- a/schemas/proto/device/v1/list.proto +++ b/schemas/proto/device/v1/list.proto @@ -16,9 +16,11 @@ message ListDevicesRequest { // default: empty string. string search = 1; - // disabled limit the listing devides only + // disabled, if true, limit the listing devides only // to disabled devices. // + // if enabled, lists only enabled devices. + // // If unspecified, devices with either status will be received. DisabledFilter disabled = 2; @@ -36,12 +38,13 @@ message ListDevicesRequest { // order_by is the field to order the devices by. // - // If not given, the default is `created_at`. + // If unspecified, the default is `created_at` and sort is forced to DESC. + // regardless even if `sort` is set. OrderBy order_by = 5; // sort is the direction of the order_by result. // - // If not given, the default is `ascending`. + // If unspecified, the default is `ascending`. Sort sort = 6; } diff --git a/schemas/proto/subreddits/v1/count.proto b/schemas/proto/subreddits/v1/count.proto new file mode 100644 index 0000000..8ae1cea --- /dev/null +++ b/schemas/proto/subreddits/v1/count.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +package subreddits.v1; + +import "subreddits/v1/types.proto"; + +option go_package = "github.com/tigorlazuardi/bluemage/go/gen/proto/subreddits/v1"; + +message CountSubredditsRequest { + // Limits the counts to subreddits that contains the given name. + // case insensitive. + // + // Ignored if empty. + // + // default: empty string. + string search = 1; + + // disabled limit the counting to subreddits with the given status. + // + // If unspecified, subreddits with either status will be counted. + DisabledFilter disabled = 2; +} + +message CountSubredditsResponse { + int64 count = 1; +} diff --git a/schemas/proto/subreddits/v1/create.proto b/schemas/proto/subreddits/v1/create.proto index 4526cad..eddf85c 100644 --- a/schemas/proto/subreddits/v1/create.proto +++ b/schemas/proto/subreddits/v1/create.proto @@ -3,6 +3,7 @@ syntax = "proto3"; package subreddits.v1; import "buf/validate/validate.proto"; +import "subreddits/v1/types.proto"; option go_package = "github.com/tigorlazuardi/bluemage/go/gen/proto/subreddits/v1"; @@ -13,7 +14,10 @@ message CreateSubredditRequest { // will change to what Reddit has for // consistency. string name = 1 [(buf.validate.field).string.min_len = 1]; - bool disable_scheduler = 2; + // disabled disable the subreddit. + // + // disabled subreddit is left out from the scheduler. + bool disabled = 2; SubredditType type = 3; // schedule is cron job spec to set schedule on when // the runner for this subreddit runs. @@ -21,12 +25,6 @@ message CreateSubredditRequest { int64 countback = 5 [(buf.validate.field).int64.gt = 0]; } -enum SubredditType { - SUBREDDIT_TYPE_UNSPECIFIED = 0; - SUBREDDIT_TYPE_SUBREDDIT = 1; - SUBREDDIT_TYPE_USER = 2; -} - message CreateSubredditResponse { string name = 1; } diff --git a/schemas/proto/subreddits/v1/get.proto b/schemas/proto/subreddits/v1/get.proto index 86fcae8..e8f64e9 100644 --- a/schemas/proto/subreddits/v1/get.proto +++ b/schemas/proto/subreddits/v1/get.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package subreddits.v1; import "buf/validate/validate.proto"; -import "subreddits/v1/create.proto"; +import "subreddits/v1/types.proto"; option go_package = "github.com/tigorlazuardi/bluemage/go/gen/proto/subreddits/v1"; @@ -15,28 +15,5 @@ message GetSubredditRequest { } message GetSubredditResponse { - string name = 1; - bool disable_scheduler = 2; - // type is never unspecified for this response. - // - // It's always either `SUBREDDIT_TYPE_SUBREDDIT` - // or `SUBREDDIT_TYPE_USER`. - SubredditType type = 3; - string schedule = 4; - uint32 countback = 5; - // cover_image_id is the id of an image that - // acts as the cover for this subreddit. - // - // May not be present in these kind of situations: - // - // - The background task runner has not run for this subreddit. - // - The image that is used as cover is deleted. - // - The subreddit does not contain any images. - // - // cover_image_id changes after every insert of - // new images in that subreddit, so avoid - // caching the image for too long. - optional uint32 cover_image_id = 6; - int64 created_at = 7; - int64 updated_at = 8; + Subreddit subreddit = 1; } diff --git a/schemas/proto/subreddits/v1/list.proto b/schemas/proto/subreddits/v1/list.proto index 3fd25e6..a171e96 100644 --- a/schemas/proto/subreddits/v1/list.proto +++ b/schemas/proto/subreddits/v1/list.proto @@ -2,18 +2,52 @@ syntax = "proto3"; package subreddits.v1; -import "buf/validate/validate.proto"; -import "subreddits/v1/get.proto"; +import "subreddits/v1/types.proto"; option go_package = "github.com/tigorlazuardi/bluemage/go/gen/proto/subreddits/v1"; message ListSubredditsRequest { - // name of the subreddit. Case insensitive. + // Searches the name of the Subreddit. + // case insensitive. // - // Returns error on not found. - string name = 1 [(buf.validate.field).string.min_len = 1]; + // If empty or not given, lists all devices. + // (Limit, Offset, Order, Sort still applies). + // + // default: empty string. + string search = 1; + + // disabled, if true, limit the listing subreddits to only + // to disabled subreddits. + // + // if enabled, lists only enabled subreddits. + // + // If unspecified, subreddits with either status will be received. + DisabledFilter disabled = 2; + + // limits the number of results. + // + // if value is 0, negative value, or not given, limit is set to 25. + // + // if limit is higher than 100, it is clamped to 100. + int64 limit = 3; + + // offset for the given data. + // + // If offset is 0, negative value, or not given, the query begins from start. + int64 offset = 4; + + // order_by is the field to order the subreddits by. + // + // If unspecified, the default is `created_at` and sort is forced to DESC. + // regardless even if `sort` is set. + OrderBy order_by = 5; + + // sort is the direction of the order_by result. + // + // If unspecified, the default is `ascending`. + Sort sort = 6; } message ListSubredditsResponse { - repeated GetSubredditResponse images = 1; + repeated Subreddit subreddits = 1; } diff --git a/schemas/proto/subreddits/v1/types.proto b/schemas/proto/subreddits/v1/types.proto new file mode 100644 index 0000000..23e781f --- /dev/null +++ b/schemas/proto/subreddits/v1/types.proto @@ -0,0 +1,67 @@ +syntax = "proto3"; + +package subreddits.v1; + +option go_package = "github.com/tigorlazuardi/bluemage/go/gen/proto/subreddits/v1"; + +message Subreddit { + string name = 1; + bool disable_scheduler = 2; + // type is never unspecified for this response. + // + // It's always either `SUBREDDIT_TYPE_SUBREDDIT` + // or `SUBREDDIT_TYPE_USER`. + SubredditType type = 3; + string schedule = 4; + uint32 countback = 5; + // cover_image_id is the id of an image that + // acts as the cover for this subreddit. + // + // May not be present in these kind of situations: + // + // - The background task runner has not run for this subreddit. + // - The image that is used as cover is deleted. + // - The subreddit does not contain any images. + // + // cover_image_id changes after every insert of + // new images in that subreddit, so avoid + // caching the image for too long. + optional uint32 cover_image_id = 6; + int64 created_at = 7; + int64 updated_at = 8; +} + +enum SubredditType { + SUBREDDIT_TYPE_UNSPECIFIED = 0; + SUBREDDIT_TYPE_SUBREDDIT = 1; + SUBREDDIT_TYPE_USER = 2; +} + +enum DisabledFilter { + DISABLED_FILTER_UNSPECIFIED = 0; + DISABLED_FILTER_TRUE = 1; + DISABLED_FILTER_FALSE = 2; +} + +enum OrderBy { + ORDER_BY_UNSPECIFIED = 0; + ORDER_BY_NAME = 1; + // Sorting by Type only guarantee the order is subreddit type first + // or user first. + // + // It does not do any ordering further. + ORDER_BY_TYPE = 2; + // Sorting by countback only orders by countback value. + // + // There are no guarantee order when multiple values + // are the same. + ORDER_BY_COUNTBACK = 3; + ORDER_BY_CREATED_AT = 4; + ORDER_BY_UPDATED_AT = 5; +} + +enum Sort { + SORT_UNSPECIFIED = 0; + SORT_ASCENDING = 1; + SORT_DESCENDING = 2; +}