diff options
| author | Xe Iaso <me@xeiaso.net> | 2024-10-18 12:46:30 -0400 |
|---|---|---|
| committer | Xe Iaso <me@xeiaso.net> | 2024-10-18 12:46:30 -0400 |
| commit | dcc841e8eb84fb4e098a69c685dcf491124a6954 (patch) | |
| tree | ee82a95644d3ea7410892b21d273a1b4fada476c /proto | |
| parent | e461eabd42c09a221b2b2cdc26e759053edb04db (diff) | |
| download | x-dcc841e8eb84fb4e098a69c685dcf491124a6954.tar.xz x-dcc841e8eb84fb4e098a69c685dcf491124a6954.zip | |
proto: add Post service for Mimi Announce
Signed-off-by: Xe Iaso <me@xeiaso.net>
Diffstat (limited to 'proto')
| -rw-r--r-- | proto/external/jsonfeed/jsonfeed.pb.go | 2 | ||||
| -rw-r--r-- | proto/mi/mi.pb.go | 2 | ||||
| -rw-r--r-- | proto/mi/mi_grpc.pb.go | 65 | ||||
| -rw-r--r-- | proto/mimi/announce.proto | 8 | ||||
| -rw-r--r-- | proto/mimi/announce/announce.pb.go | 121 | ||||
| -rw-r--r-- | proto/mimi/announce/announce.twirp.go | 511 | ||||
| -rw-r--r-- | proto/mimi/announce/announce_grpc.pb.go | 129 | ||||
| -rw-r--r-- | proto/mimi/statuspage/statuspage.pb.go | 2 | ||||
| -rw-r--r-- | proto/mimi/statuspage/statuspage_grpc.pb.go | 27 | ||||
| -rw-r--r-- | proto/sanguisuga/sanguisuga.pb.go | 2 | ||||
| -rw-r--r-- | proto/sanguisuga/sanguisuga_grpc.pb.go | 46 | ||||
| -rw-r--r-- | proto/uplodr/uplodr.pb.go | 2 | ||||
| -rw-r--r-- | proto/uplodr/uplodr_grpc.pb.go | 85 |
13 files changed, 873 insertions, 129 deletions
diff --git a/proto/external/jsonfeed/jsonfeed.pb.go b/proto/external/jsonfeed/jsonfeed.pb.go index d88710d..ca8cfca 100644 --- a/proto/external/jsonfeed/jsonfeed.pb.go +++ b/proto/external/jsonfeed/jsonfeed.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 -// protoc v5.27.1 +// protoc v5.27.3 // source: jsonfeed.proto package jsonfeed diff --git a/proto/mi/mi.pb.go b/proto/mi/mi.pb.go index 0ec8169..336db5c 100644 --- a/proto/mi/mi.pb.go +++ b/proto/mi/mi.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 -// protoc v5.27.1 +// protoc v5.27.3 // source: mi.proto package mi diff --git a/proto/mi/mi_grpc.pb.go b/proto/mi/mi_grpc.pb.go index d9b3756..f826e91 100644 --- a/proto/mi/mi_grpc.pb.go +++ b/proto/mi/mi_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.4.0 -// - protoc v5.27.1 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.27.3 // source: mi.proto package mi @@ -16,8 +16,8 @@ import ( // 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.62.0 or later. -const _ = grpc.SupportPackageIsVersion8 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( SwitchTracker_Members_FullMethodName = "/within.website.x.mi.SwitchTracker/Members" @@ -98,7 +98,7 @@ func (c *switchTrackerClient) ListSwitches(ctx context.Context, in *ListSwitches // SwitchTrackerServer is the server API for SwitchTracker service. // All implementations must embed UnimplementedSwitchTrackerServer -// for forward compatibility +// for forward compatibility. type SwitchTrackerServer interface { Members(context.Context, *emptypb.Empty) (*MembersResp, error) WhoIsFront(context.Context, *emptypb.Empty) (*FrontChange, error) @@ -108,9 +108,12 @@ type SwitchTrackerServer interface { mustEmbedUnimplementedSwitchTrackerServer() } -// UnimplementedSwitchTrackerServer must be embedded to have forward compatible implementations. -type UnimplementedSwitchTrackerServer struct { -} +// UnimplementedSwitchTrackerServer 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 UnimplementedSwitchTrackerServer struct{} func (UnimplementedSwitchTrackerServer) Members(context.Context, *emptypb.Empty) (*MembersResp, error) { return nil, status.Errorf(codes.Unimplemented, "method Members not implemented") @@ -128,6 +131,7 @@ func (UnimplementedSwitchTrackerServer) ListSwitches(context.Context, *ListSwitc return nil, status.Errorf(codes.Unimplemented, "method ListSwitches not implemented") } func (UnimplementedSwitchTrackerServer) mustEmbedUnimplementedSwitchTrackerServer() {} +func (UnimplementedSwitchTrackerServer) testEmbeddedByValue() {} // UnsafeSwitchTrackerServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to SwitchTrackerServer will @@ -137,6 +141,13 @@ type UnsafeSwitchTrackerServer interface { } func RegisterSwitchTrackerServer(s grpc.ServiceRegistrar, srv SwitchTrackerServer) { + // If the following call pancis, it indicates UnimplementedSwitchTrackerServer 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(&SwitchTracker_ServiceDesc, srv) } @@ -293,20 +304,24 @@ func (c *pOSSEClient) RefreshBlog(ctx context.Context, in *emptypb.Empty, opts . // POSSEServer is the server API for POSSE service. // All implementations must embed UnimplementedPOSSEServer -// for forward compatibility +// for forward compatibility. type POSSEServer interface { RefreshBlog(context.Context, *emptypb.Empty) (*emptypb.Empty, error) mustEmbedUnimplementedPOSSEServer() } -// UnimplementedPOSSEServer must be embedded to have forward compatible implementations. -type UnimplementedPOSSEServer struct { -} +// UnimplementedPOSSEServer 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 UnimplementedPOSSEServer struct{} func (UnimplementedPOSSEServer) RefreshBlog(context.Context, *emptypb.Empty) (*emptypb.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method RefreshBlog not implemented") } func (UnimplementedPOSSEServer) mustEmbedUnimplementedPOSSEServer() {} +func (UnimplementedPOSSEServer) testEmbeddedByValue() {} // UnsafePOSSEServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to POSSEServer will @@ -316,6 +331,13 @@ type UnsafePOSSEServer interface { } func RegisterPOSSEServer(s grpc.ServiceRegistrar, srv POSSEServer) { + // If the following call pancis, it indicates UnimplementedPOSSEServer 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(&POSSE_ServiceDesc, srv) } @@ -413,7 +435,7 @@ func (c *eventsClient) Remove(ctx context.Context, in *Event, opts ...grpc.CallO // EventsServer is the server API for Events service. // All implementations must embed UnimplementedEventsServer -// for forward compatibility +// for forward compatibility. // // Events lets users fetch the current feed of events that Xe will be attending. type EventsServer interface { @@ -426,9 +448,12 @@ type EventsServer interface { mustEmbedUnimplementedEventsServer() } -// UnimplementedEventsServer must be embedded to have forward compatible implementations. -type UnimplementedEventsServer struct { -} +// UnimplementedEventsServer 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 UnimplementedEventsServer struct{} func (UnimplementedEventsServer) Get(context.Context, *emptypb.Empty) (*EventFeed, error) { return nil, status.Errorf(codes.Unimplemented, "method Get not implemented") @@ -440,6 +465,7 @@ func (UnimplementedEventsServer) Remove(context.Context, *Event) (*emptypb.Empty return nil, status.Errorf(codes.Unimplemented, "method Remove not implemented") } func (UnimplementedEventsServer) mustEmbedUnimplementedEventsServer() {} +func (UnimplementedEventsServer) testEmbeddedByValue() {} // UnsafeEventsServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to EventsServer will @@ -449,6 +475,13 @@ type UnsafeEventsServer interface { } func RegisterEventsServer(s grpc.ServiceRegistrar, srv EventsServer) { + // If the following call pancis, it indicates UnimplementedEventsServer 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(&Events_ServiceDesc, srv) } diff --git a/proto/mimi/announce.proto b/proto/mimi/announce.proto index b1a0374..953b4a2 100644 --- a/proto/mimi/announce.proto +++ b/proto/mimi/announce.proto @@ -5,6 +5,14 @@ option go_package = "within.website/x/proto/mimi/announce"; import "google/protobuf/empty.proto"; import "external/jsonfeed.proto"; +message StatusUpdate { + string body = 1; +} + service Announce { rpc Announce(jsonfeed.Item) returns (google.protobuf.Empty) {} +} + +service Post { + rpc Post(StatusUpdate) returns (google.protobuf.Empty) {} }
\ No newline at end of file diff --git a/proto/mimi/announce/announce.pb.go b/proto/mimi/announce/announce.pb.go index 8bcb173..9e83678 100644 --- a/proto/mimi/announce/announce.pb.go +++ b/proto/mimi/announce/announce.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 -// protoc v5.27.1 +// protoc v5.27.3 // source: announce.proto package announce @@ -11,6 +11,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" emptypb "google.golang.org/protobuf/types/known/emptypb" reflect "reflect" + sync "sync" jsonfeed "within.website/x/proto/external/jsonfeed" ) @@ -21,6 +22,53 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type StatusUpdate struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Body string `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"` +} + +func (x *StatusUpdate) Reset() { + *x = StatusUpdate{} + if protoimpl.UnsafeEnabled { + mi := &file_announce_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StatusUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StatusUpdate) ProtoMessage() {} + +func (x *StatusUpdate) ProtoReflect() protoreflect.Message { + mi := &file_announce_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StatusUpdate.ProtoReflect.Descriptor instead. +func (*StatusUpdate) Descriptor() ([]byte, []int) { + return file_announce_proto_rawDescGZIP(), []int{0} +} + +func (x *StatusUpdate) GetBody() string { + if x != nil { + return x.Body + } + return "" +} + var File_announce_proto protoreflect.FileDescriptor var file_announce_proto_rawDesc = []byte{ @@ -30,25 +78,49 @@ var file_announce_proto_rawDesc = []byte{ 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x66, 0x65, 0x65, 0x64, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0x40, 0x0a, 0x08, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, - 0x63, 0x65, 0x12, 0x34, 0x0a, 0x08, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x12, 0x0e, - 0x2e, 0x6a, 0x73, 0x6f, 0x6e, 0x66, 0x65, 0x65, 0x64, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x1a, 0x16, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x26, 0x5a, 0x24, 0x77, 0x69, 0x74, 0x68, - 0x69, 0x6e, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x2f, 0x78, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2f, 0x6d, 0x69, 0x6d, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x22, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x32, 0x40, 0x0a, 0x08, 0x41, 0x6e, + 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x08, 0x41, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, + 0x63, 0x65, 0x12, 0x0e, 0x2e, 0x6a, 0x73, 0x6f, 0x6e, 0x66, 0x65, 0x65, 0x64, 0x2e, 0x49, 0x74, + 0x65, 0x6d, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x32, 0x56, 0x0a, 0x04, + 0x50, 0x6f, 0x73, 0x74, 0x12, 0x4e, 0x0a, 0x04, 0x50, 0x6f, 0x73, 0x74, 0x12, 0x2c, 0x2e, 0x77, + 0x69, 0x74, 0x68, 0x69, 0x6e, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x2e, 0x78, 0x2e, + 0x6d, 0x69, 0x6d, 0x69, 0x2e, 0x61, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x22, 0x00, 0x42, 0x26, 0x5a, 0x24, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x2e, 0x77, + 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x2f, 0x78, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6d, + 0x69, 0x6d, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x75, 0x6e, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } +var ( + file_announce_proto_rawDescOnce sync.Once + file_announce_proto_rawDescData = file_announce_proto_rawDesc +) + +func file_announce_proto_rawDescGZIP() []byte { + file_announce_proto_rawDescOnce.Do(func() { + file_announce_proto_rawDescData = protoimpl.X.CompressGZIP(file_announce_proto_rawDescData) + }) + return file_announce_proto_rawDescData +} + +var file_announce_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_announce_proto_goTypes = []any{ - (*jsonfeed.Item)(nil), // 0: jsonfeed.Item - (*emptypb.Empty)(nil), // 1: google.protobuf.Empty + (*StatusUpdate)(nil), // 0: within.website.x.mimi.announce.StatusUpdate + (*jsonfeed.Item)(nil), // 1: jsonfeed.Item + (*emptypb.Empty)(nil), // 2: google.protobuf.Empty } var file_announce_proto_depIdxs = []int32{ - 0, // 0: within.website.x.mimi.announce.Announce.Announce:input_type -> jsonfeed.Item - 1, // 1: within.website.x.mimi.announce.Announce.Announce:output_type -> google.protobuf.Empty - 1, // [1:2] is the sub-list for method output_type - 0, // [0:1] is the sub-list for method input_type + 1, // 0: within.website.x.mimi.announce.Announce.Announce:input_type -> jsonfeed.Item + 0, // 1: within.website.x.mimi.announce.Post.Post:input_type -> within.website.x.mimi.announce.StatusUpdate + 2, // 2: within.website.x.mimi.announce.Announce.Announce:output_type -> google.protobuf.Empty + 2, // 3: within.website.x.mimi.announce.Post.Post:output_type -> google.protobuf.Empty + 2, // [2:4] is the sub-list for method output_type + 0, // [0:2] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name @@ -59,18 +131,33 @@ func file_announce_proto_init() { if File_announce_proto != nil { return } + if !protoimpl.UnsafeEnabled { + file_announce_proto_msgTypes[0].Exporter = func(v any, i int) any { + switch v := v.(*StatusUpdate); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_announce_proto_rawDesc, NumEnums: 0, - NumMessages: 0, + NumMessages: 1, NumExtensions: 0, - NumServices: 1, + NumServices: 2, }, GoTypes: file_announce_proto_goTypes, DependencyIndexes: file_announce_proto_depIdxs, + MessageInfos: file_announce_proto_msgTypes, }.Build() File_announce_proto = out.File file_announce_proto_rawDesc = nil diff --git a/proto/mimi/announce/announce.twirp.go b/proto/mimi/announce/announce.twirp.go index b049adf..9186537 100644 --- a/proto/mimi/announce/announce.twirp.go +++ b/proto/mimi/announce/announce.twirp.go @@ -524,6 +524,500 @@ func (s *announceServer) PathPrefix() string { return baseServicePath(s.pathPrefix, "within.website.x.mimi.announce", "Announce") } +// ============== +// Post Interface +// ============== + +type Post interface { + Post(context.Context, *StatusUpdate) (*google_protobuf.Empty, error) +} + +// ==================== +// Post Protobuf Client +// ==================== + +type postProtobufClient struct { + client HTTPClient + urls [1]string + interceptor twirp.Interceptor + opts twirp.ClientOptions +} + +// NewPostProtobufClient creates a Protobuf client that implements the Post interface. +// It communicates using Protobuf and can be configured with a custom HTTPClient. +func NewPostProtobufClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) Post { + if c, ok := client.(*http.Client); ok { + client = withoutRedirects(c) + } + + clientOpts := twirp.ClientOptions{} + for _, o := range opts { + o(&clientOpts) + } + + // Using ReadOpt allows backwards and forwards compatibility with new options in the future + literalURLs := false + _ = clientOpts.ReadOpt("literalURLs", &literalURLs) + var pathPrefix string + if ok := clientOpts.ReadOpt("pathPrefix", &pathPrefix); !ok { + pathPrefix = "/twirp" // default prefix + } + + // Build method URLs: <baseURL>[<prefix>]/<package>.<Service>/<Method> + serviceURL := sanitizeBaseURL(baseURL) + serviceURL += baseServicePath(pathPrefix, "within.website.x.mimi.announce", "Post") + urls := [1]string{ + serviceURL + "Post", + } + + return &postProtobufClient{ + client: client, + urls: urls, + interceptor: twirp.ChainInterceptors(clientOpts.Interceptors...), + opts: clientOpts, + } +} + +func (c *postProtobufClient) Post(ctx context.Context, in *StatusUpdate) (*google_protobuf.Empty, error) { + ctx = ctxsetters.WithPackageName(ctx, "within.website.x.mimi.announce") + ctx = ctxsetters.WithServiceName(ctx, "Post") + ctx = ctxsetters.WithMethodName(ctx, "Post") + caller := c.callPost + if c.interceptor != nil { + caller = func(ctx context.Context, req *StatusUpdate) (*google_protobuf.Empty, error) { + resp, err := c.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*StatusUpdate) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*StatusUpdate) when calling interceptor") + } + return c.callPost(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*google_protobuf.Empty) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*google_protobuf.Empty) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + return caller(ctx, in) +} + +func (c *postProtobufClient) callPost(ctx context.Context, in *StatusUpdate) (*google_protobuf.Empty, error) { + out := new(google_protobuf.Empty) + ctx, err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out) + if err != nil { + twerr, ok := err.(twirp.Error) + if !ok { + twerr = twirp.InternalErrorWith(err) + } + callClientError(ctx, c.opts.Hooks, twerr) + return nil, err + } + + callClientResponseReceived(ctx, c.opts.Hooks) + + return out, nil +} + +// ================ +// Post JSON Client +// ================ + +type postJSONClient struct { + client HTTPClient + urls [1]string + interceptor twirp.Interceptor + opts twirp.ClientOptions +} + +// NewPostJSONClient creates a JSON client that implements the Post interface. +// It communicates using JSON and can be configured with a custom HTTPClient. +func NewPostJSONClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) Post { + if c, ok := client.(*http.Client); ok { + client = withoutRedirects(c) + } + + clientOpts := twirp.ClientOptions{} + for _, o := range opts { + o(&clientOpts) + } + + // Using ReadOpt allows backwards and forwards compatibility with new options in the future + literalURLs := false + _ = clientOpts.ReadOpt("literalURLs", &literalURLs) + var pathPrefix string + if ok := clientOpts.ReadOpt("pathPrefix", &pathPrefix); !ok { + pathPrefix = "/twirp" // default prefix + } + + // Build method URLs: <baseURL>[<prefix>]/<package>.<Service>/<Method> + serviceURL := sanitizeBaseURL(baseURL) + serviceURL += baseServicePath(pathPrefix, "within.website.x.mimi.announce", "Post") + urls := [1]string{ + serviceURL + "Post", + } + + return &postJSONClient{ + client: client, + urls: urls, + interceptor: twirp.ChainInterceptors(clientOpts.Interceptors...), + opts: clientOpts, + } +} + +func (c *postJSONClient) Post(ctx context.Context, in *StatusUpdate) (*google_protobuf.Empty, error) { + ctx = ctxsetters.WithPackageName(ctx, "within.website.x.mimi.announce") + ctx = ctxsetters.WithServiceName(ctx, "Post") + ctx = ctxsetters.WithMethodName(ctx, "Post") + caller := c.callPost + if c.interceptor != nil { + caller = func(ctx context.Context, req *StatusUpdate) (*google_protobuf.Empty, error) { + resp, err := c.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*StatusUpdate) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*StatusUpdate) when calling interceptor") + } + return c.callPost(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*google_protobuf.Empty) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*google_protobuf.Empty) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + return caller(ctx, in) +} + +func (c *postJSONClient) callPost(ctx context.Context, in *StatusUpdate) (*google_protobuf.Empty, error) { + out := new(google_protobuf.Empty) + ctx, err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out) + if err != nil { + twerr, ok := err.(twirp.Error) + if !ok { + twerr = twirp.InternalErrorWith(err) + } + callClientError(ctx, c.opts.Hooks, twerr) + return nil, err + } + + callClientResponseReceived(ctx, c.opts.Hooks) + + return out, nil +} + +// =================== +// Post Server Handler +// =================== + +type postServer struct { + Post + interceptor twirp.Interceptor + hooks *twirp.ServerHooks + pathPrefix string // prefix for routing + jsonSkipDefaults bool // do not include unpopulated fields (default values) in the response + jsonCamelCase bool // JSON fields are serialized as lowerCamelCase rather than keeping the original proto names +} + +// NewPostServer builds a TwirpServer that can be used as an http.Handler to handle +// HTTP requests that are routed to the right method in the provided svc implementation. +// The opts are twirp.ServerOption modifiers, for example twirp.WithServerHooks(hooks). +func NewPostServer(svc Post, opts ...interface{}) TwirpServer { + serverOpts := newServerOpts(opts) + + // Using ReadOpt allows backwards and forwards compatibility with new options in the future + jsonSkipDefaults := false + _ = serverOpts.ReadOpt("jsonSkipDefaults", &jsonSkipDefaults) + jsonCamelCase := false + _ = serverOpts.ReadOpt("jsonCamelCase", &jsonCamelCase) + var pathPrefix string + if ok := serverOpts.ReadOpt("pathPrefix", &pathPrefix); !ok { + pathPrefix = "/twirp" // default prefix + } + + return &postServer{ + Post: svc, + hooks: serverOpts.Hooks, + interceptor: twirp.ChainInterceptors(serverOpts.Interceptors...), + pathPrefix: pathPrefix, + jsonSkipDefaults: jsonSkipDefaults, + jsonCamelCase: jsonCamelCase, + } +} + +// writeError writes an HTTP response with a valid Twirp error format, and triggers hooks. +// If err is not a twirp.Error, it will get wrapped with twirp.InternalErrorWith(err) +func (s *postServer) writeError(ctx context.Context, resp http.ResponseWriter, err error) { + writeError(ctx, resp, err, s.hooks) +} + +// handleRequestBodyError is used to handle error when the twirp server cannot read request +func (s *postServer) handleRequestBodyError(ctx context.Context, resp http.ResponseWriter, msg string, err error) { + if context.Canceled == ctx.Err() { + s.writeError(ctx, resp, twirp.NewError(twirp.Canceled, "failed to read request: context canceled")) + return + } + if context.DeadlineExceeded == ctx.Err() { + s.writeError(ctx, resp, twirp.NewError(twirp.DeadlineExceeded, "failed to read request: deadline exceeded")) + return + } + s.writeError(ctx, resp, twirp.WrapError(malformedRequestError(msg), err)) +} + +// PostPathPrefix is a convenience constant that may identify URL paths. +// Should be used with caution, it only matches routes generated by Twirp Go clients, +// with the default "/twirp" prefix and default CamelCase service and method names. +// More info: https://twitchtv.github.io/twirp/docs/routing.html +const PostPathPrefix = "/twirp/within.website.x.mimi.announce.Post/" + +func (s *postServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) { + ctx := req.Context() + ctx = ctxsetters.WithPackageName(ctx, "within.website.x.mimi.announce") + ctx = ctxsetters.WithServiceName(ctx, "Post") + ctx = ctxsetters.WithResponseWriter(ctx, resp) + + var err error + ctx, err = callRequestReceived(ctx, s.hooks) + if err != nil { + s.writeError(ctx, resp, err) + return + } + + if req.Method != "POST" { + msg := fmt.Sprintf("unsupported method %q (only POST is allowed)", req.Method) + s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) + return + } + + // Verify path format: [<prefix>]/<package>.<Service>/<Method> + prefix, pkgService, method := parseTwirpPath(req.URL.Path) + if pkgService != "within.website.x.mimi.announce.Post" { + msg := fmt.Sprintf("no handler for path %q", req.URL.Path) + s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) + return + } + if prefix != s.pathPrefix { + msg := fmt.Sprintf("invalid path prefix %q, expected %q, on path %q", prefix, s.pathPrefix, req.URL.Path) + s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) + return + } + + switch method { + case "Post": + s.servePost(ctx, resp, req) + return + default: + msg := fmt.Sprintf("no handler for path %q", req.URL.Path) + s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) + return + } +} + +func (s *postServer) servePost(ctx context.Context, resp http.ResponseWriter, req *http.Request) { + header := req.Header.Get("Content-Type") + i := strings.Index(header, ";") + if i == -1 { + i = len(header) + } + switch strings.TrimSpace(strings.ToLower(header[:i])) { + case "application/json": + s.servePostJSON(ctx, resp, req) + case "application/protobuf": + s.servePostProtobuf(ctx, resp, req) + default: + msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type")) + twerr := badRouteError(msg, req.Method, req.URL.Path) + s.writeError(ctx, resp, twerr) + } +} + +func (s *postServer) servePostJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) { + var err error + ctx = ctxsetters.WithMethodName(ctx, "Post") + ctx, err = callRequestRouted(ctx, s.hooks) + if err != nil { + s.writeError(ctx, resp, err) + return + } + + d := json.NewDecoder(req.Body) + rawReqBody := json.RawMessage{} + if err := d.Decode(&rawReqBody); err != nil { + s.handleRequestBodyError(ctx, resp, "the json request could not be decoded", err) + return + } + reqContent := new(StatusUpdate) + unmarshaler := protojson.UnmarshalOptions{DiscardUnknown: true} + if err = unmarshaler.Unmarshal(rawReqBody, reqContent); err != nil { + s.handleRequestBodyError(ctx, resp, "the json request could not be decoded", err) + return + } + + handler := s.Post.Post + if s.interceptor != nil { + handler = func(ctx context.Context, req *StatusUpdate) (*google_protobuf.Empty, error) { + resp, err := s.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*StatusUpdate) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*StatusUpdate) when calling interceptor") + } + return s.Post.Post(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*google_protobuf.Empty) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*google_protobuf.Empty) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + + // Call service method + var respContent *google_protobuf.Empty + func() { + defer ensurePanicResponses(ctx, resp, s.hooks) + respContent, err = handler(ctx, reqContent) + }() + + if err != nil { + s.writeError(ctx, resp, err) + return + } + if respContent == nil { + s.writeError(ctx, resp, twirp.InternalError("received a nil *google_protobuf.Empty and nil error while calling Post. nil responses are not supported")) + return + } + + ctx = callResponsePrepared(ctx, s.hooks) + + marshaler := &protojson.MarshalOptions{UseProtoNames: !s.jsonCamelCase, EmitUnpopulated: !s.jsonSkipDefaults} + respBytes, err := marshaler.Marshal(respContent) + if err != nil { + s.writeError(ctx, resp, wrapInternal(err, "failed to marshal json response")) + return + } + + ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK) + resp.Header().Set("Content-Type", "application/json") + resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes))) + resp.WriteHeader(http.StatusOK) + + if n, err := resp.Write(respBytes); err != nil { + msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error()) + twerr := twirp.NewError(twirp.Unknown, msg) + ctx = callError(ctx, s.hooks, twerr) + } + callResponseSent(ctx, s.hooks) +} + +func (s *postServer) servePostProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) { + var err error + ctx = ctxsetters.WithMethodName(ctx, "Post") + ctx, err = callRequestRouted(ctx, s.hooks) + if err != nil { + s.writeError(ctx, resp, err) + return + } + + buf, err := io.ReadAll(req.Body) + if err != nil { + s.handleRequestBodyError(ctx, resp, "failed to read request body", err) + return + } + reqContent := new(StatusUpdate) + if err = proto.Unmarshal(buf, reqContent); err != nil { + s.writeError(ctx, resp, malformedRequestError("the protobuf request could not be decoded")) + return + } + + handler := s.Post.Post + if s.interceptor != nil { + handler = func(ctx context.Context, req *StatusUpdate) (*google_protobuf.Empty, error) { + resp, err := s.interceptor( + func(ctx context.Context, req interface{}) (interface{}, error) { + typedReq, ok := req.(*StatusUpdate) + if !ok { + return nil, twirp.InternalError("failed type assertion req.(*StatusUpdate) when calling interceptor") + } + return s.Post.Post(ctx, typedReq) + }, + )(ctx, req) + if resp != nil { + typedResp, ok := resp.(*google_protobuf.Empty) + if !ok { + return nil, twirp.InternalError("failed type assertion resp.(*google_protobuf.Empty) when calling interceptor") + } + return typedResp, err + } + return nil, err + } + } + + // Call service method + var respContent *google_protobuf.Empty + func() { + defer ensurePanicResponses(ctx, resp, s.hooks) + respContent, err = handler(ctx, reqContent) + }() + + if err != nil { + s.writeError(ctx, resp, err) + return + } + if respContent == nil { + s.writeError(ctx, resp, twirp.InternalError("received a nil *google_protobuf.Empty and nil error while calling Post. nil responses are not supported")) + return + } + + ctx = callResponsePrepared(ctx, s.hooks) + + respBytes, err := proto.Marshal(respContent) + if err != nil { + s.writeError(ctx, resp, wrapInternal(err, "failed to marshal proto response")) + return + } + + ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK) + resp.Header().Set("Content-Type", "application/protobuf") + resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes))) + resp.WriteHeader(http.StatusOK) + if n, err := resp.Write(respBytes); err != nil { + msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error()) + twerr := twirp.NewError(twirp.Unknown, msg) + ctx = callError(ctx, s.hooks, twerr) + } + callResponseSent(ctx, s.hooks) +} + +func (s *postServer) ServiceDescriptor() ([]byte, int) { + return twirpFileDescriptor0, 1 +} + +func (s *postServer) ProtocGenTwirpVersion() string { + return "v8.1.3" +} + +// PathPrefix returns the base service path, in the form: "/<prefix>/<package>.<Service>/" +// that is everything in a Twirp route except for the <Method>. This can be used for routing, +// for example to identify the requests that are targeted to this service in a mux. +func (s *postServer) PathPrefix() string { + return baseServicePath(s.pathPrefix, "within.website.x.mimi.announce", "Post") +} + // ===== // Utils // ===== @@ -1090,16 +1584,19 @@ func callClientError(ctx context.Context, h *twirp.ClientHooks, err twirp.Error) } var twirpFileDescriptor0 = []byte{ - // 164 bytes of a gzipped FileDescriptorProto + // 219 bytes of a gzipped FileDescriptorProto |
